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 * 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; }