Пример #1
0
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;
}
Пример #2
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;
        ssize_t               ttl;

        if (!instance)
                return NULL;

        if (!pdu_ser_is_ok(pdu))
                return NULL;

#ifdef CONFIG_RINA_IPCPS_CRC
        if (!dup_chksum_is_ok(pdu)) {
                LOG_ERR("Bad CRC, PDU has been corrupted");
                return NULL;
        }

        /* Assuming CRC32 */
        if (pdu_ser_head_shrink(pdu, sizeof(u32))) {
                LOG_ERR("Failed to shrink ser PDU");
                return NULL;
        }
#endif

        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;

#ifdef CONFIG_RINA_IPCPS_TTL
        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(pdu, sizeof(u8))) {
                LOG_ERR("Failed to shrink ser PDU");
                pci_destroy(new_pci);
                pdu_destroy(new_pdu);
                return NULL;
        }
#endif

        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_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;
}
Пример #3
0
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;
}
Пример #4
0
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;
        }

#ifdef CONFIG_RINA_IPCPS_TTL
        if (pdu_ser_head_grow(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;
        }
#endif

#ifdef CONFIG_RINA_IPCPS_CRC
        /* Assuming CRC32 */
        if (pdu_ser_head_grow(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));
#endif

        pdu_destroy(pdu);

        return tmp;
}