bool pdu_pci_present(const struct pdu * pdu) { if (!pdu_is_ok(pdu)) return false; return pdu->pci ? true : false; }
struct pci * pdu_pci_get_rw(struct pdu * pdu) { if (!pdu_is_ok(pdu)) return NULL; return pdu->pci; }
struct buffer * pdu_buffer_get_rw(struct pdu * pdu) { if (!pdu_is_ok(pdu)) return NULL; return pdu->buffer; }
int common_closed_window(struct dtp_ps * ps, struct pdu * pdu) { struct dtp * dtp = ps->dm; struct cwq * cwq; struct dt * dt; uint_t max_len; if (!dtp) { LOG_ERR("No instance passed, cannot run policy"); pdu_destroy(pdu); return -1; } if (!pdu_is_ok(pdu)) { LOG_ERR("PDU is not ok, cannot run policy"); pdu_destroy(pdu); return -1; } dt = dtp_dt(dtp); ASSERT(dt); cwq = dt_cwq(dt); if (!cwq) { LOG_ERR("Failed to get cwq"); pdu_destroy(pdu); return -1; } LOG_DBG("Closed Window Queue"); ASSERT(dtp); max_len = dtcp_max_closed_winq_length(dtcp_config_get(dt_dtcp(dt))); if (cwq_size(cwq) < max_len - 1) { if (cwq_push(cwq, pdu)) { LOG_ERR("Failed to push into cwq"); return -1; } return 0; } ASSERT(ps->flow_control_overrun); if (ps->flow_control_overrun(ps, pdu)) { LOG_ERR("Failed Flow Control Overrun"); return -1; } return 0; }
static struct pdu * pdu_dup_gfp(gfp_t flags, const struct pdu * pdu) { struct pdu * tmp; if (!pdu_is_ok(pdu)) return NULL; tmp = rkmalloc(sizeof(*tmp), flags); if (!tmp) return NULL; tmp->pci = pci_dup_gfp(flags, pdu->pci); tmp->buffer = buffer_dup_gfp(flags, pdu->buffer); if (!pdu_is_ok(tmp)) { pdu_destroy(tmp); return NULL; } return tmp; }
static int default_flow_control_overrun(struct dtp_ps * ps, struct pdu * pdu) { struct cwq * cwq; struct dt * dt; struct dtp * dtp = ps->dm; if (!dtp) { LOG_ERR("No instance passed, cannot run policy"); return -1; } dt = dtp_dt(dtp); ASSERT(dt); cwq = dt_cwq(dt); if (!cwq) { LOG_ERR("Failed to get cwq"); pdu_destroy(pdu); return -1; } LOG_DBG("Default Flow Control"); if (!pdu_is_ok(pdu)) { LOG_ERR("PDU is not ok, cannot run policy"); return -1; } if (cwq_push(cwq, pdu)) { LOG_ERR("Failed to push into cwq"); return -1; } if (efcp_disable_write(dt_efcp(dt))) return -1; return 0; }
static struct pdu * pdu_create_from_gfp(gfp_t flags, const struct sdu * sdu) { struct pdu * tmp_pdu; const struct buffer * tmp_buff; const uint8_t * ptr; size_t pci_size; /* FIXME: This implementation is pure crap, please fix it soon */ if (!sdu_is_ok(sdu)) return NULL; tmp_buff = sdu_buffer_ro(sdu); ASSERT(tmp_buff); if (buffer_length(tmp_buff) < pci_length_min()) return NULL; /* FIXME: We should compute the real PCI length */ pci_size = pci_length_min(); tmp_pdu = pdu_create_gfp(flags); if (!tmp_pdu) return NULL; ptr = (const uint8_t *) buffer_data_ro(tmp_buff); ASSERT(ptr); tmp_pdu->pci = pci_create_from_gfp(flags, ptr); tmp_pdu->buffer = buffer_create_from_gfp(flags, ptr + pci_size, (buffer_length(sdu->buffer) - pci_size)); ASSERT(pdu_is_ok(tmp_pdu)); return tmp_pdu; }
static int default_closed_window(struct dtp_ps * ps, struct pdu * pdu) { struct dtp * dtp = ps->dm; struct cwq * cwq; struct dt * dt; struct dtp_sv * sv; struct connection * connection; uint_t max_len; if (!dtp) { LOG_ERR("No instance passed, cannot run policy"); pdu_destroy(pdu); return -1; } if (!pdu_is_ok(pdu)) { LOG_ERR("PDU is not ok, cannot run policy"); pdu_destroy(pdu); return -1; } dt = dtp_dt(dtp); ASSERT(dt); cwq = dt_cwq(dt); if (!cwq) { LOG_ERR("Failed to get cwq"); pdu_destroy(pdu); return -1; } LOG_DBG("Closed Window Queue"); ASSERT(dtp); sv = dtp_dtp_sv(dtp); ASSERT(sv); connection = dtp_sv_connection(sv); ASSERT(connection); ASSERT(connection->policies_params); max_len = dtcp_max_closed_winq_length(connection-> policies_params-> dtcp_cfg); if (cwq_size(cwq) < max_len - 1) { if (cwq_push(cwq, pdu)) { LOG_ERR("Failed to push into cwq"); return -1; } return 0; } ASSERT(ps->flow_control_overrun); if (ps->flow_control_overrun(ps, pdu)) { LOG_ERR("Failed Flow Control Overrun"); return -1; } return 0; }
static struct pdu * pdu_deserialize_gfp(gfp_t flags, const struct serdes * instance, struct pdu_ser * pdu) { struct pdu * new_pdu; struct dt_cons * dt_cons; const struct buffer * tmp_buff; struct buffer * new_buff; struct pci * new_pci; const uint8_t * ptr; int offset; ssize_t pdu_len; seq_num_t seq; if (!pdu_ser_is_ok(pdu)) return NULL; if (!instance) return NULL; dt_cons = instance->dt_cons; ASSERT(dt_cons); tmp_buff = pdu_ser_buffer(pdu); ASSERT(tmp_buff); if (buffer_length(tmp_buff) < base_pci_size(dt_cons)) return NULL; ptr = (const uint8_t *) buffer_data_ro(tmp_buff); ASSERT(ptr); new_pdu = pdu_create_gfp(flags); if (!new_pdu) { LOG_ERR("Failed to create new pdu"); return NULL; } new_pci = pci_create_gfp(flags); if (!new_pci) { LOG_ERR("Failed to create new pci"); pdu_destroy(new_pdu); return NULL; } pdu_len = 0; if (deserialize_base_pci(instance, new_pci, &offset, ptr, &pdu_len)) { LOG_ERR("Could not deser base PCI"); pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } switch (pci_type(new_pci)) { case PDU_TYPE_MGMT: case PDU_TYPE_DT: /* Create buffer with rest of PDU if it is a DT or MGMT PDU*/ memcpy(&seq, ptr + offset, dt_cons->seq_num_length); offset += dt_cons->seq_num_length; if (pci_sequence_number_set(new_pci, seq)) { pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } new_buff = buffer_create_from_gfp(flags, ptr + offset, pdu_len - offset); if (!new_buff) { LOG_ERR("Could not create new_buff"); pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } break; case PDU_TYPE_FC: if (deserialize_ctrl_seq(instance, new_pci, &offset, ptr) || deserialize_fc_pci(instance, new_pci, &offset, ptr)) { pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } /* * FIXME: It would be better if a PDU consisted of * Base PCI + Data | Control PDU stuff * e.g. * struct pdu { * struct pci base_pci; * union { * struct buffer * data; * struct pci_ctrl * ctrl; * } * } */ new_buff = buffer_create_gfp(flags, 1); if (!new_buff) { pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } break; case PDU_TYPE_ACK: if (deserialize_ctrl_seq(instance, new_pci, &offset, ptr) || deserialize_ack_pci(instance, new_pci, &offset, ptr)) { pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } new_buff = buffer_create_gfp(flags, 1); if (!new_buff) { pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } break; case PDU_TYPE_ACK_AND_FC: if (deserialize_ctrl_seq(instance, new_pci, &offset, ptr) || deserialize_ack_pci(instance, new_pci, &offset, ptr) || deserialize_fc_pci(instance, new_pci, &offset, ptr)) { pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } new_buff = buffer_create_gfp(flags, 1); if (!new_buff) { pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } break; case PDU_TYPE_CC: if (deserialize_ctrl_seq(instance, new_pci, &offset, ptr) || deserialize_cc_pci(instance, new_pci, &offset, ptr)) { pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } new_buff = buffer_create_gfp(flags, 1); if (!new_buff) { pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } break; default: LOG_ERR("Unknown PDU type %02X", pci_type(new_pci)); pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } if (pdu_pci_set(new_pdu, new_pci)) { LOG_ERR("Failed to set PCI in PDU"); buffer_destroy(new_buff); pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } if (pdu_buffer_set(new_pdu, new_buff)) { LOG_ERR("Failed to set buffer in PDU"); pdu_destroy(new_pdu); return NULL; } ASSERT(pdu_is_ok(new_pdu)); pdu_ser_destroy(pdu); return new_pdu; }
static struct pdu_ser * pdu_serialize_gfp(gfp_t flags, const const struct serdes * instance, struct pdu * pdu) { struct pdu_ser * tmp; struct dt_cons * dt_cons; const void * buffer_data; const struct buffer * buffer; const struct pci * pci; size_t size; ssize_t buffer_size; ssize_t pci_size; char * data; pdu_type_t pdu_type; seq_num_t seq; struct buffer * buf; if (!pdu_is_ok(pdu)) return NULL; if (!instance) return NULL; dt_cons = instance->dt_cons; ASSERT(dt_cons); buffer = pdu_buffer_get_ro(pdu); if (!buffer) return NULL; buffer_data = buffer_data_ro(buffer); if (!buffer_data) return NULL; buffer_size = buffer_length(buffer); if (buffer_size <= 0) return NULL; pci = pdu_pci_get_ro(pdu); if (!pci) return NULL; pdu_type = pci_type(pci); if (!pdu_type_is_ok(pdu_type)) { LOG_ERR("Wrong PDU type"); return NULL; } /* Base PCI size, fields present in all PDUs */ pci_size = base_pci_size(dt_cons); /* * These are available in the stack at this point in time * Extend if necessary (e.g.) NACKs, SACKs, ... * Set size in first switch/case */ switch (pdu_type) { case PDU_TYPE_MGMT: case PDU_TYPE_DT: size = pci_size + dt_cons->seq_num_length + buffer_size; if (size <= 0) return NULL; break; case PDU_TYPE_FC: size = pci_size + CTRL_SEQ_NR + fc_pci_size(dt_cons); if (size <= 0) return NULL; break; case PDU_TYPE_ACK: size = pci_size + CTRL_SEQ_NR + dt_cons->seq_num_length; if (size <= 0) return NULL; break; case PDU_TYPE_ACK_AND_FC: size = pci_size + CTRL_SEQ_NR + fc_pci_size(dt_cons) + dt_cons->seq_num_length; if (size <= 0) return NULL; break; case PDU_TYPE_CC: size = pci_size + 2 * CTRL_SEQ_NR + 4 * dt_cons->seq_num_length + RATE_LEN; if (size <= 0) return NULL; break; default: LOG_ERR("Unknown PDU type %02X", pdu_type); return NULL; } data = rkmalloc(size, flags); if (!data) return NULL; /* Needed for all PDUs */ if (serialize_base_pci(instance, data, pci, size)) { LOG_ERR("Failed to serialize base PCI"); rkfree(data); return NULL; } /* Do actual serializing in the second switch case */ switch (pdu_type) { case PDU_TYPE_MGMT: case PDU_TYPE_DT: seq = pci_sequence_number_get(pci); memcpy(data + pci_size, &seq, dt_cons->seq_num_length); memcpy(data + pci_size + dt_cons->seq_num_length, buffer_data, buffer_size); break; case PDU_TYPE_FC: if (serialize_ctrl_seq(instance, data, pci, pci_size) || serialize_fc_pci(instance, data, pci, pci_size + CTRL_SEQ_NR)) { rkfree(data); return NULL; } break; case PDU_TYPE_ACK: if (serialize_ctrl_seq(instance, data, pci, pci_size) || serialize_ack_pci(instance, data, pci, pci_size + CTRL_SEQ_NR)) { rkfree(data); return NULL; } break; case PDU_TYPE_ACK_AND_FC: if (serialize_ctrl_seq(instance, data, pci, pci_size) || serialize_ack_pci(instance, data, pci, pci_size + CTRL_SEQ_NR) || serialize_fc_pci(instance, data, pci, pci_size + CTRL_SEQ_NR + dt_cons->seq_num_length)) { rkfree(data); return NULL; } break; case PDU_TYPE_CC: if (serialize_ctrl_seq(instance, data, pci, pci_size) || serialize_cc_pci(instance, data, pci, pci_size + CTRL_SEQ_NR)) { rkfree(data); return NULL; } break; default: LOG_ERR("Unknown PDU type %02X", pdu_type); return NULL; } buf = buffer_create_with_gfp(flags, data, size); if (!buf) { rkfree(data); return NULL; } tmp = pdu_ser_create_buffer_with_gfp(flags, buf); if (!tmp) { rkfree(buf); return NULL; } pdu_destroy(pdu); return tmp; }
int dtcp_common_rcv_control(struct dtcp * dtcp, struct pdu * pdu) { struct dtcp_ps * ps; struct pci * pci; pdu_type_t type; seq_num_t sn; seq_num_t last_ctrl; int ret; LOG_DBG("dtcp_common_rcv_control called"); if (!pdu_is_ok(pdu)) { LOG_ERR("PDU is not ok"); pdu_destroy(pdu); return -1; } if (!dtcp) { LOG_ERR("DTCP instance bogus"); pdu_destroy(pdu); return -1; } atomic_inc(&dtcp->cpdus_in_transit); pci = pdu_pci_get_rw(pdu); if (!pci_is_ok(pci)) { LOG_ERR("PCI couldn't be retrieved"); atomic_dec(&dtcp->cpdus_in_transit); pdu_destroy(pdu); return -1; } type = pci_type(pci); if (!pdu_type_is_control(type)) { LOG_ERR("CommonRCVControl policy received a non-control PDU"); atomic_dec(&dtcp->cpdus_in_transit); pdu_destroy(pdu); return -1; } sn = pci_sequence_number_get(pci); last_ctrl = last_rcv_ctrl_seq(dtcp); if (sn <= last_ctrl) { switch (type) { case PDU_TYPE_FC: flow_ctrl_inc(dtcp); break; case PDU_TYPE_ACK: acks_inc(dtcp); break; case PDU_TYPE_ACK_AND_FC: acks_inc(dtcp); flow_ctrl_inc(dtcp); break; default: break; } pdu_destroy(pdu); return 0; } rcu_read_lock(); ps = container_of(rcu_dereference(dtcp->base.ps), struct dtcp_ps, base); if (sn > (last_ctrl + 1)) { ps->lost_control_pdu(ps); } rcu_read_unlock(); /* We are in sn >= last_ctrl + 1 */ last_rcv_ctrl_seq_set(dtcp, sn); LOG_DBG("dtcp_common_rcv_control sending to proper function..."); switch (type) { case PDU_TYPE_ACK: ret = rcv_ack(dtcp, pdu); break; case PDU_TYPE_NACK: ret = rcv_nack_ctl(dtcp, pdu); break; case PDU_TYPE_FC: ret = rcv_flow_ctl(dtcp, pdu); break; case PDU_TYPE_ACK_AND_FC: ret = rcv_ack_and_flow_ctl(dtcp, pdu); break; default: ret = -1; break; } atomic_dec(&dtcp->cpdus_in_transit); return ret; }
static struct pdu * pdu_deserialize_gfp(gfp_t flags, const struct serdes * instance, struct pdu_ser * pdu, struct dup_config_entry * dup_conf, struct crypto_blkcipher * blkcipher) { struct pdu * new_pdu; struct dt_cons * dt_cons; struct buffer * tmp_buff; struct buffer * new_buff; struct pci * new_pci; const uint8_t * ptr; int offset; ssize_t pdu_len; seq_num_t seq; ssize_t ttl; uint8_t pad_len; const char * data; if (!instance) return NULL; if (!pdu_ser_is_ok(pdu)) return NULL; /* FIXME: this should be moved to specific policy code */ if (dup_conf != NULL && dup_conf->error_check_policy != NULL){ if (!dup_chksum_is_ok(pdu)) { LOG_ERR("Bad CRC, PDU has been corrupted"); return NULL; } /* Assuming CRC32 */ if (pdu_ser_head_shrink_gfp(flags, pdu, sizeof(u32))) { LOG_ERR("Failed to shrink ser PDU"); return NULL; } } /* FIXME: this should be moved to specific policy code */ if (blkcipher != NULL && dup_conf != NULL && dup_conf->enable_decryption){ if (!dup_decrypt_data(pdu, blkcipher)) { LOG_ERR("Failed to decrypt PDU"); return NULL; } tmp_buff = pdu_ser_buffer(pdu); data = buffer_data_ro(tmp_buff); pad_len = data[buffer_length(tmp_buff)-1]; //remove padding if (pdu_ser_tail_shrink_gfp(pdu, pad_len)){ LOG_ERR("Failed to shrink ser PDU"); return NULL; } } dt_cons = instance->dt_cons; ASSERT(dt_cons); tmp_buff = pdu_ser_buffer(pdu); ASSERT(tmp_buff); if (buffer_length(tmp_buff) < base_pci_size(dt_cons)) return NULL; new_pdu = pdu_create_gfp(flags); if (!new_pdu) { LOG_ERR("Failed to create new pdu"); return NULL; } new_pci = pci_create_gfp(flags); if (!new_pci) { LOG_ERR("Failed to create new pci"); pdu_destroy(new_pdu); return NULL; } ttl = 0; /* FIXME: this should be moved to specific policy code */ if (dup_conf != NULL && dup_conf->ttl_policy != NULL){ ttl = dup_ttl_decrement(pdu); if (ttl < 0) { LOG_ERR("Could not decrement TTL"); pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } if (pci_ttl_set(new_pci, ttl)) { LOG_ERR("Could not set TTL"); pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } if (pdu_ser_head_shrink_gfp(flags, pdu, sizeof(u8))) { LOG_ERR("Failed to shrink ser PDU"); pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } } ptr = (const uint8_t *) buffer_data_ro(tmp_buff); ASSERT(ptr); pdu_len = 0; if (deserialize_base_pci(instance, new_pci, &offset, ptr, &pdu_len)) { LOG_ERR("Could not deser base PCI"); pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } switch (pci_type(new_pci)) { case PDU_TYPE_MGMT: case PDU_TYPE_DT: /* Create buffer with rest of PDU if it is a DT or MGMT PDU*/ memcpy(&seq, ptr + offset, dt_cons->seq_num_length); offset += dt_cons->seq_num_length; if (pci_sequence_number_set(new_pci, seq)) { pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } new_buff = buffer_create_from_gfp(flags, ptr + offset, pdu_len - offset); if (!new_buff) { LOG_ERR("Could not create new_buff"); pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } break; case PDU_TYPE_FC: if (deserialize_ctrl_seq(instance, new_pci, &offset, ptr) || deserialize_fc_pci(instance, new_pci, &offset, ptr)) { pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } /* * FIXME: It would be better if a PDU consisted of * Base PCI + Data | Control PDU stuff * e.g. * struct pdu { * struct pci base_pci; * union { * struct buffer * data; * struct pci_ctrl * ctrl; * } * } */ new_buff = buffer_create_gfp(flags, 1); if (!new_buff) { pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } break; case PDU_TYPE_ACK: if (deserialize_ctrl_seq(instance, new_pci, &offset, ptr) || deserialize_ack_pci(instance, new_pci, &offset, ptr)) { pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } new_buff = buffer_create_gfp(flags, 1); if (!new_buff) { pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } break; case PDU_TYPE_ACK_AND_FC: if (deserialize_ctrl_seq(instance, new_pci, &offset, ptr) || deserialize_ack_pci(instance, new_pci, &offset, ptr) || deserialize_fc_pci(instance, new_pci, &offset, ptr)) { pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } new_buff = buffer_create_gfp(flags, 1); if (!new_buff) { pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } break; case PDU_TYPE_CACK: if (deserialize_ctrl_seq(instance, new_pci, &offset, ptr) || deserialize_cc_pci(instance, new_pci, &offset, ptr)) { pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } new_buff = buffer_create_gfp(flags, 1); if (!new_buff) { pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } break; default: LOG_ERR("Unknown PDU type %02X", pci_type(new_pci)); pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } if (pdu_pci_set(new_pdu, new_pci)) { LOG_ERR("Failed to set PCI in PDU"); buffer_destroy(new_buff); pci_destroy(new_pci); pdu_destroy(new_pdu); return NULL; } if (pdu_buffer_set(new_pdu, new_buff)) { LOG_ERR("Failed to set buffer in PDU"); pdu_destroy(new_pdu); return NULL; } ASSERT(pdu_is_ok(new_pdu)); pdu_ser_destroy(pdu); return new_pdu; }
static struct pdu_ser * pdu_serialize_gfp(gfp_t flags, const const struct serdes * instance, struct pdu * pdu, struct dup_config_entry * dup_conf, struct crypto_blkcipher * blkcipher) { struct pdu_ser * tmp; struct dt_cons * dt_cons; const void * buffer_data; const struct buffer * buffer; const struct pci * pci; size_t size; ssize_t buffer_size; ssize_t blk_size; ssize_t encrypted_size; ssize_t pci_size; char * data; pdu_type_t pdu_type; seq_num_t seq; struct buffer * buf; int i; if (!pdu_is_ok(pdu)) return NULL; if (!instance) return NULL; dt_cons = instance->dt_cons; ASSERT(dt_cons); buffer = pdu_buffer_get_ro(pdu); if (!buffer) return NULL; buffer_data = buffer_data_ro(buffer); if (!buffer_data) return NULL; buffer_size = buffer_length(buffer); if (buffer_size <= 0) return NULL; pci = pdu_pci_get_ro(pdu); if (!pci) return NULL; pdu_type = pci_type(pci); if (!pdu_type_is_ok(pdu_type)) { LOG_ERR("Wrong PDU type"); return NULL; } /* Base PCI size, fields present in all PDUs */ pci_size = base_pci_size(dt_cons); /* * These are available in the stack at this point in time * Extend if necessary (e.g.) NACKs, SACKs, ... * Set size in first switch/case */ switch (pdu_type) { case PDU_TYPE_MGMT: case PDU_TYPE_DT: size = pci_size + dt_cons->seq_num_length + buffer_size; if (size <= 0) return NULL; break; case PDU_TYPE_FC: size = pci_size + CTRL_SEQ_NR + fc_pci_size(dt_cons); if (size <= 0) return NULL; break; case PDU_TYPE_ACK: size = pci_size + CTRL_SEQ_NR + dt_cons->seq_num_length; if (size <= 0) return NULL; break; case PDU_TYPE_ACK_AND_FC: size = pci_size + CTRL_SEQ_NR + fc_pci_size(dt_cons) + dt_cons->seq_num_length; if (size <= 0) return NULL; break; case PDU_TYPE_CACK: size = pci_size + 2 * CTRL_SEQ_NR + 4 * dt_cons->seq_num_length + RATE_LEN; if (size <= 0) return NULL; break; default: LOG_ERR("Unknown PDU type %02X", pdu_type); return NULL; } data = rkmalloc(size, flags); if (!data) return NULL; /* Needed for all PDUs */ if (serialize_base_pci(instance, data, pci, size)) { LOG_ERR("Failed to serialize base PCI"); rkfree(data); return NULL; } /* Do actual serializing in the second switch case */ switch (pdu_type) { case PDU_TYPE_MGMT: case PDU_TYPE_DT: seq = pci_sequence_number_get(pci); memcpy(data + pci_size, &seq, dt_cons->seq_num_length); memcpy(data + pci_size + dt_cons->seq_num_length, buffer_data, buffer_size); break; case PDU_TYPE_FC: if (serialize_ctrl_seq(instance, data, pci, pci_size) || serialize_fc_pci(instance, data, pci, pci_size + CTRL_SEQ_NR)) { rkfree(data); return NULL; } break; case PDU_TYPE_ACK: if (serialize_ctrl_seq(instance, data, pci, pci_size) || serialize_ack_pci(instance, data, pci, pci_size + CTRL_SEQ_NR)) { rkfree(data); return NULL; } break; case PDU_TYPE_ACK_AND_FC: if (serialize_ctrl_seq(instance, data, pci, pci_size) || serialize_ack_pci(instance, data, pci, pci_size + CTRL_SEQ_NR) || serialize_fc_pci(instance, data, pci, pci_size + CTRL_SEQ_NR + dt_cons->seq_num_length)) { rkfree(data); return NULL; } break; case PDU_TYPE_CACK: if (serialize_ctrl_seq(instance, data, pci, pci_size) || serialize_cc_pci(instance, data, pci, pci_size + CTRL_SEQ_NR)) { rkfree(data); return NULL; } break; default: LOG_ERR("Unknown PDU type %02X", pdu_type); return NULL; } buf = buffer_create_with_gfp(flags, data, size); if (!buf) { rkfree(data); return NULL; } tmp = pdu_ser_create_buffer_with_gfp(flags, buf); if (!tmp) { rkfree(buf); return NULL; } /* FIXME: this should be moved to specific policy code */ if (dup_conf != NULL && dup_conf->ttl_policy != NULL){ if (pdu_ser_head_grow_gfp(flags, tmp, sizeof(u8))) { LOG_ERR("Failed to grow ser PDU"); pdu_ser_destroy(tmp); return NULL; } if (!dup_ttl_set(tmp, pci_ttl(pci))) { LOG_ERR("Could not set TTL"); pdu_ser_destroy(tmp); return NULL; } if (dup_ttl_is_expired(tmp)) { LOG_DBG("TTL is expired, dropping PDU"); pdu_ser_destroy(tmp); return NULL; } } /* FIXME: this should be moved to specific policy code */ if (blkcipher != NULL && dup_conf != NULL && dup_conf->enable_encryption){ buf = pdu_ser_buffer(tmp); blk_size = crypto_blkcipher_blocksize(blkcipher); buffer_size = buffer_length(buf); encrypted_size = (buffer_size/blk_size + 1) * blk_size; if (pdu_ser_tail_grow_gfp(tmp, encrypted_size - buffer_size)){ LOG_ERR("Failed to grow ser PDU"); pdu_ser_destroy(tmp); return NULL; } /* PADDING */ data = buffer_data_rw(buf); for (i=encrypted_size-1; i>buffer_size; i--){ data[i] = encrypted_size - buffer_size; } /* Encrypt */ if (!dup_encrypt_data(tmp, blkcipher)) { LOG_ERR("Failed to encrypt PDU"); pdu_ser_destroy(tmp); return NULL; } } /* FIXME: this should be moved to specific policy code */ if (dup_conf != NULL && dup_conf->error_check_policy != NULL){ /* Assuming CRC32 */ if (pdu_ser_head_grow_gfp(flags, tmp, sizeof(u32))) { LOG_ERR("Failed to grow ser PDU"); pdu_ser_destroy(tmp); return NULL; } if (!dup_chksum_set(tmp)) { LOG_ERR("Failed to add CRC"); pdu_ser_destroy(tmp); return NULL; } ASSERT(dup_chksum_is_ok(tmp)); } return tmp; }