static ofl_err
ofl_msg_unpack_packet_in(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) {
    struct ofp_packet_in *sp;
    struct ofl_msg_packet_in *dp;

    if (*len < sizeof(struct ofp_packet_in)) {
        OFL_LOG_WARN(LOG_MODULE, "Received PACKET_IN message has invalid length (%zu).", *len);
        return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN);
    }

    sp = (struct ofp_packet_in *)src;

    if (ntohl(sp->in_port) == 0 ||
        (ntohl(sp->in_port) > OFPP_MAX &&
         ntohl(sp->in_port) != OFPP_LOCAL)) {
        if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) {
            char *ps = ofl_port_to_string(ntohl(sp->in_port));
            OFL_LOG_WARN(LOG_MODULE, "Received PACKET_IN message has invalid in_port (%s).", ps);
            free(ps);
        }
        return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
    }

    if (sp->table_id == 0xff) {
        if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) {
            char *ts = ofl_table_to_string(sp->table_id);
            OFL_LOG_WARN(LOG_MODULE, "Received PACKET_IN has invalid table_id (%s).", ts);
            free(ts);
        }
        return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
    }
    *len -= sizeof(struct ofp_packet_in);

    dp = (struct ofl_msg_packet_in *)malloc(sizeof(struct ofl_msg_packet_in));

    dp->buffer_id = ntohl(sp->buffer_id);
    dp->in_port = ntohl(sp->in_port);
    dp->in_phy_port = ntohl(sp->in_phy_port);
    dp->total_len = ntohs(sp->total_len);
    dp->reason = (enum ofp_packet_in_reason)sp->reason;
    dp->table_id = sp->table_id;

    dp->data_length = *len;
    dp->data = *len > 0 ? (uint8_t *)memcpy(malloc(*len), sp->data, *len) : NULL;
    *len = 0;

    *msg = (struct ofl_msg_header *)dp;
    return 0;
}
ofl_err
ofl_structs_queue_stats_unpack(struct ofp_queue_stats *src, size_t *len, struct ofl_queue_stats **dst) {
    struct ofl_queue_stats *p;

    if (*len < sizeof(struct ofp_queue_stats)) {
        OFL_LOG_WARN(LOG_MODULE, "Received queue stats has invalid length (%zu).", *len);
        return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
    }

    if (ntohl(src->port_no) == 0 || ntohl(src->port_no) > OFPP_MAX) {
        if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) {
            char *ps = ofl_port_to_string(ntohl(src->port_no));
            OFL_LOG_WARN(LOG_MODULE, "Received queue stats has invalid port_id (%s).", ps);
            free(ps);
        }
        return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN);
    }
    *len -= sizeof(struct ofp_queue_stats);

    p = (struct ofl_queue_stats *)malloc(sizeof(struct ofl_queue_stats));

    p->port_no =    ntohl(src->port_no);
    p->queue_id =   ntohl(src->queue_id);
    p->tx_bytes =   ntoh64(src->tx_bytes);
    p->tx_packets = ntoh64(src->tx_packets);
    p->tx_errors =  ntoh64(src->tx_errors);
    p->duration_sec = ntohl(src->duration_sec);
    p->duration_nsec = ntohl(src->duration_nsec);
    *dst = p;
    return 0;
}
ofl_err
ofl_structs_table_stats_unpack(struct ofp_table_stats *src, size_t *len, struct ofl_table_stats **dst) {
    struct ofl_table_stats *p;

    if (*len < sizeof(struct ofp_table_stats)) {
        OFL_LOG_WARN(LOG_MODULE, "Received table stats has invalid length (%zu).", *len);
        return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN);
    }

    if (src->table_id == 0xff) {
        if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) {
            char *ts = ofl_table_to_string(src->table_id);
            OFL_LOG_WARN(LOG_MODULE, "Received table stats has invalid table_id (%s).", ts);
            free(ts);
        }
        return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN);
    }
    *len -= sizeof(struct ofp_table_stats);

    p = (struct ofl_table_stats *)malloc(sizeof(struct ofl_table_stats));
    p->table_id =      src->table_id;
    p->active_count =  ntohl(src->active_count);
    p->lookup_count =  ntoh64(src->lookup_count);
    p->matched_count = ntoh64(src->matched_count);

    *dst = p;
    return 0;
}
static ofl_err
ofl_msg_unpack_port_mod(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) {
    struct ofp_port_mod *sm;
    struct ofl_msg_port_mod *dm;

    if (*len < sizeof(struct ofp_port_mod)) {
        OFL_LOG_WARN(LOG_MODULE, "Received PORT_MOD has invalid length (%zu).", *len);
        return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
    }

    sm = (struct ofp_port_mod *)src;

    if (ntohl(sm->port_no) == 0 || ntohl(sm->port_no) > OFPP_MAX) {
        if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) {
            char *ps = ofl_port_to_string(ntohl(sm->port_no));
            OFL_LOG_WARN(LOG_MODULE, "Received PORT_MOD message has invalid in_port (%s).", ps);
            free(ps);
        }
        return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
    }
    *len -= sizeof(struct ofp_port_mod);

    dm = (struct ofl_msg_port_mod *)malloc(sizeof(struct ofl_msg_port_mod));

    dm->port_no =   ntohl(sm->port_no);
    memcpy(dm->hw_addr, sm->hw_addr, OFP_ETH_ALEN);
    dm->config =    ntohl(sm->config);
    dm->mask =      ntohl(sm->mask);
    dm->advertise = ntohl(sm->advertise);

    *msg = (struct ofl_msg_header *)dm;
    return 0;
}
static ofl_err
ofl_msg_unpack_flow_removed(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) {
    struct ofp_flow_removed *sr;
    struct ofl_msg_flow_removed *dr;
    ofl_err error;

    if (*len < (sizeof(struct ofp_flow_removed) - sizeof(struct ofp_match))) {
        OFL_LOG_WARN(LOG_MODULE, "Received FLOW_REMOVED message has invalid length (%zu).", *len);
        return OFL_ERROR;
    }

    sr = (struct ofp_flow_removed *)src;

    if (sr->table_id == 0xff) {
        if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) {
            char *ts = ofl_table_to_string(sr->table_id);
            OFL_LOG_WARN(LOG_MODULE, "Received FLOW_REMOVED message has invalid table_id (%s).", ts);
            free(ts);
        }
        return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
    }
    *len -= (sizeof(struct ofp_flow_removed) - sizeof(struct ofp_match));

    dr = (struct ofl_msg_flow_removed *)malloc(sizeof(struct ofl_msg_flow_removed));
    dr->reason = (enum ofp_flow_removed_reason)sr->reason;

    dr->stats = (struct ofl_flow_stats *)malloc(sizeof(struct ofl_flow_stats));
    dr->stats->table_id         =        sr->table_id;
    dr->stats->duration_sec     = ntohl( sr->duration_sec);
    dr->stats->duration_nsec    = ntohl( sr->duration_nsec);
    dr->stats->priority         = ntoh64(sr->priority);
    dr->stats->idle_timeout     = ntohs( sr->idle_timeout);
    dr->stats->hard_timeout     = 0;
    dr->stats->cookie           = ntoh64(sr->cookie);
    dr->stats->packet_count     = ntoh64(sr->packet_count);
    dr->stats->byte_count       = ntoh64(sr->byte_count);
    dr->stats->instructions_num = 0;
    dr->stats->instructions     = NULL;

    error = ofl_structs_match_unpack(&(sr->match), len, &(dr->stats->match), exp);
    if (error) {
        free(dr->stats);
        free(dr);
        return error;
    }

    *msg = (struct ofl_msg_header *)dr;
    return 0;
}
ofl_err
ofl_structs_port_stats_unpack(struct ofp_port_stats *src, size_t *len, struct ofl_port_stats **dst) {
    struct ofl_port_stats *p;

    if (*len < sizeof(struct ofp_port_stats)) {
        OFL_LOG_WARN(LOG_MODULE, "Received port stats has invalid length (%zu).", *len);
        return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN);
    }
    if (ntohl(src->port_no) == 0 ||
        (ntohl(src->port_no) > OFPP_MAX && ntohl(src->port_no) != OFPP_LOCAL)) {
        if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) {
            char *ps = ofl_port_to_string(ntohl(src->port_no));
            OFL_LOG_WARN(LOG_MODULE, "Received port stats has invalid port_id (%s).", ps);
            free(ps);
        }
        return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN);
    }
    *len -= sizeof(struct ofp_port_stats);

    p = (struct ofl_port_stats *)malloc(sizeof(struct ofl_port_stats));

    p->port_no      = ntohl(src->port_no);
    p->rx_packets   = ntoh64(src->rx_packets);
    p->tx_packets   = ntoh64(src->tx_packets);
    p->rx_bytes     = ntoh64(src->rx_bytes);
    p->tx_bytes     = ntoh64(src->tx_bytes);
    p->rx_dropped   = ntoh64(src->rx_dropped);
    p->tx_dropped   = ntoh64(src->tx_dropped);
    p->rx_errors    = ntoh64(src->rx_errors);
    p->tx_errors    = ntoh64(src->tx_errors);
    p->rx_frame_err = ntoh64(src->rx_frame_err);
    p->rx_over_err  = ntoh64(src->rx_over_err);
    p->rx_crc_err   = ntoh64(src->rx_crc_err);
    p->collisions   = ntoh64(src->collisions);
    p->duration_sec = ntohl(src->duration_sec);
    p->duration_nsec = ntohl(src->duration_nsec);
    *dst = p;
    return 0;
}
ofl_err
ofl_structs_port_unpack(struct ofp_port *src, size_t *len, struct ofl_port **dst) {
    struct ofl_port *p;

    if (*len < sizeof(struct ofp_port)) {
        OFL_LOG_WARN(LOG_MODULE, "Received port has invalid length (%zu).", *len);
        return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN);
    }

    if (ntohl(src->port_no) == 0 ||
        (ntohl(src->port_no) > OFPP_MAX && ntohl(src->port_no) != OFPP_LOCAL)) {
        if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) {
            char *ps = ofl_port_to_string(ntohl(src->port_no));
            OFL_LOG_WARN(LOG_MODULE, "Received port has invalid port_id (%s).", ps);
            free(ps);
        }
        return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN);
    }
    *len -= sizeof(struct ofp_port);

    p = (struct ofl_port *)malloc(sizeof(struct ofl_port));

    p->port_no = ntohl(src->port_no);
    memcpy(p->hw_addr, src->hw_addr, ETH_ADDR_LEN);
    p->name = strcpy((char *)malloc(strlen(src->name) + 1), src->name);
    p->config = ntohl(src->config);
    p->state = ntohl(src->state);
    p->curr = ntohl(src->curr);
    p->advertised = ntohl(src->advertised);
    p->supported = ntohl(src->supported);
    p->peer = ntohl(src->peer);
    p->curr_speed = ntohl(src->curr_speed);
    p->max_speed = ntohl(src->max_speed);

    *dst = p;
    return 0;
}
ofl_err
ofl_structs_table_stats_unpack(struct ofp_table_stats *src, size_t *len, struct ofl_table_stats **dst) {
    struct ofl_table_stats *p;

    if (*len < sizeof(struct ofp_table_stats)) {
        OFL_LOG_WARN(LOG_MODULE, "Received table stats has invalid length (%zu).", *len);
        return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN);
    }

    if (src->table_id == 0xff) {
        if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) {
            char *ts = ofl_table_to_string(src->table_id);
            OFL_LOG_WARN(LOG_MODULE, "Received table stats has invalid table_id (%s).", ts);
            free(ts);
        }
        return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN);
    }
    *len -= sizeof(struct ofp_table_stats);

    p = (struct ofl_table_stats *)malloc(sizeof(struct ofl_table_stats));
    p->table_id =      src->table_id;
    p->name =          strcpy((char *)malloc(strlen(src->name) + 1), src->name);
    p->wildcards =     ntohl(src->wildcards);
    p->match =         ntohl(src->match);
    p->instructions =  ntohl(src->instructions);
    p->write_actions = ntohl(src->write_actions);
    p->apply_actions = ntohl(src->apply_actions);
    p->config =        ntohl(src->config);
    p->max_entries =   ntohl(src->max_entries);
    p->active_count =  ntohl(src->active_count);
    p->lookup_count =  ntoh64(src->lookup_count);
    p->matched_count = ntoh64(src->matched_count);

    *dst = p;
    return 0;
}
ofl_err
ofl_structs_instructions_unpack(struct ofp_instruction *src, size_t *len, struct ofl_instruction_header **dst, struct ofl_exp *exp) {
    size_t ilen;
    struct ofl_instruction_header *inst = NULL;

    if (*len < sizeof(struct ofp_instruction)) {
        OFL_LOG_WARN(LOG_MODULE, "Received instruction is too short (%zu).", *len);
        return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
    }

    if (*len < ntohs(src->len)) {
        OFL_LOG_WARN(LOG_MODULE, "Received instruction has invalid length (set to %u, but only %zu received).", ntohs(src->len), *len);
        return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
    }
    ilen = ntohs(src->len);

    switch (ntohs(src->type)) {
        case OFPIT_GOTO_TABLE: {
            struct ofp_instruction_goto_table *si;
            struct ofl_instruction_goto_table *di;

            if (ilen < sizeof(struct ofp_instruction_goto_table)) {
                OFL_LOG_WARN(LOG_MODULE, "Received GOTO_TABLE instruction has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN);
            }

            si = (struct ofp_instruction_goto_table *)src;

            if (si->table_id >= PIPELINE_TABLES) {
                if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) {
                    char *ts = ofl_table_to_string(si->table_id);
                    OFL_LOG_WARN(LOG_MODULE, "Received GOTO_TABLE instruction has invalid table_id (%s).", ts);
                    free(ts);
                }
                return ofl_error(OFPET_BAD_INSTRUCTION, OFPBIC_BAD_TABLE_ID);
            }

            di = (struct ofl_instruction_goto_table *)malloc(sizeof(struct ofl_instruction_goto_table));

            di->table_id = si->table_id;

            inst = (struct ofl_instruction_header *)di;
            ilen -= sizeof(struct ofp_instruction_goto_table);
            break;
        }

        case OFPIT_WRITE_METADATA: {
            struct ofp_instruction_write_metadata *si;
            struct ofl_instruction_write_metadata *di;

            if (ilen < sizeof(struct ofp_instruction_write_metadata)) {
                OFL_LOG_WARN(LOG_MODULE, "Received WRITE_METADATA instruction has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN);
            }

            si = (struct ofp_instruction_write_metadata *)src;
            di = (struct ofl_instruction_write_metadata *)malloc(sizeof(struct ofl_instruction_write_metadata));

            di->metadata =      ntoh64(si->metadata);
            di->metadata_mask = ntoh64(si->metadata_mask);

            inst = (struct ofl_instruction_header *)di;
            ilen -= sizeof(struct ofp_instruction_write_metadata);
            break;
        }
        case OFPIT_WRITE_ACTIONS:
        case OFPIT_APPLY_ACTIONS: {
            struct ofp_instruction_actions *si;
            struct ofl_instruction_actions *di;
            struct ofp_action_header *act;
            ofl_err error;
            size_t i;

            if (ilen < sizeof(struct ofp_instruction_actions)) {
                OFL_LOG_WARN(LOG_MODULE, "Received *_ACTIONS instruction has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
            }
            ilen -= sizeof(struct ofp_instruction_actions);

            si = (struct ofp_instruction_actions *)src;
            di = (struct ofl_instruction_actions *)malloc(sizeof(struct ofl_instruction_actions));

            error = ofl_utils_count_ofp_actions((uint8_t *)si->actions, ilen, &di->actions_num);
            if (error) {
                free(di);
                return error;
            }
            di->actions = (struct ofl_action_header **)malloc(di->actions_num * sizeof(struct ofl_action_header *));

            act = si->actions;
            for (i = 0; i < di->actions_num; i++) {
                error = ofl_actions_unpack(act, &ilen, &(di->actions[i]), exp);
                if (error) {
                    *len = *len - ntohs(src->len) + ilen;
                    OFL_UTILS_FREE_ARR_FUN2(di->actions, i,
                                            ofl_actions_free, exp);
                    free(di);
                    return error;
                }
                act = (struct ofp_action_header *)((uint8_t *)act + ntohs(act->len));
            }

            inst = (struct ofl_instruction_header *)di;
            break;
        }
        case OFPIT_CLEAR_ACTIONS: {
            if (ilen < sizeof(struct ofp_instruction_actions)) {
                OFL_LOG_WARN(LOG_MODULE, "Received CLEAR_ACTIONS instruction has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
            }

            inst = (struct ofl_instruction_header *)malloc(sizeof(struct ofl_instruction_header));
            inst->type = (enum ofp_instruction_type)ntohs(src->type);

            ilen -= sizeof(struct ofp_instruction_actions);
            break;
        }
        case OFPIT_METER: {
            struct ofp_instruction_meter *si;
            struct ofl_instruction_meter *di;
            
            if (ilen < sizeof(struct ofp_instruction_meter)) {
                OFL_LOG_WARN(LOG_MODULE, "Received METER instruction has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN);
            }
            si = (struct ofp_instruction_meter*)src;
            di = (struct ofl_instruction_meter *)malloc(sizeof(struct ofl_instruction_meter));

            di->meter_id = ntohl(si->meter_id);

            inst = (struct ofl_instruction_header *)di;
            ilen -= sizeof(struct ofp_instruction_meter);
            break; 
        }
        case OFPIT_EXPERIMENTER: {
            ofl_err error;

            if (exp == NULL || exp->inst == NULL || exp->inst->unpack == NULL) {
                OFL_LOG_WARN(LOG_MODULE, "Received EXPERIMENTER instruction, but no callback was given.");
                return ofl_error(OFPET_BAD_INSTRUCTION, OFPBIC_UNSUP_INST);
            }
            error = exp->inst->unpack(src, &ilen, &inst);
            if (error) {
                return error;
            }
            break;
        }
        default:
            OFL_LOG_WARN(LOG_MODULE, "The received instruction type (%u) is invalid.", ntohs(src->type));
            return ofl_error(OFPET_BAD_INSTRUCTION, OFPBIC_UNKNOWN_INST);
    }

    // must set type before check, so free works correctly
    inst->type = (enum ofp_instruction_type)ntohs(src->type);

    if (ilen != 0) {
        *len = *len - ntohs(src->len) + ilen;
        OFL_LOG_WARN(LOG_MODULE, "The received instruction contained extra bytes (%zu).", ilen);
        ofl_structs_free_instruction(inst, exp);
        return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
    }

    *len -= ntohs(src->len);
    (*dst) = inst;

    return 0;
}
ofl_err
ofl_actions_unpack(struct ofp_action_header *src, size_t *len, struct ofl_action_header **dst, struct ofl_exp *exp) {

    if (*len < sizeof(struct ofp_action_header)) {
        OFL_LOG_WARN(LOG_MODULE, "Received action is too short (%zu).", *len);
        return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
    }

    if (*len < ntohs(src->len)) {
        OFL_LOG_WARN(LOG_MODULE, "Received action has invalid length (set to %u, but only %zu received).", ntohs(src->len), *len);
        return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
    }

    if ((ntohs(src->len) % 8) != 0) {
        OFL_LOG_WARN(LOG_MODULE, "Received action length is not a multiple of 64 bits (%u).", ntohs(src->len));
        return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
    }

    switch (ntohs(src->type)) {
        case OFPAT_OUTPUT: {
            struct ofp_action_output *sa;
            struct ofl_action_output *da;

            if (*len < sizeof(struct ofp_action_output)) {
                OFL_LOG_WARN(LOG_MODULE, "Received OUTPUT action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_output *)src;

            if (ntohl(sa->port) == 0 ||
                (ntohl(sa->port) > OFPP_MAX && ntohl(sa->port) < OFPP_IN_PORT) ||
                ntohl(sa->port) == OFPP_ANY) {
                if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) {
                    char *ps = ofl_port_to_string(ntohl(sa->port));
                    OFL_LOG_WARN(LOG_MODULE, "Received OUTPUT action has invalid port (%s).", ps);
                    free(ps);
                }
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT);
            }

            da = (struct ofl_action_output *)malloc(sizeof(struct ofl_action_output));
            da->port = ntohl(sa->port);
            da->max_len = ntohs(sa->max_len);

            *len -= sizeof(struct ofp_action_output);
            *dst = (struct ofl_action_header *)da;
            break;
        }
        case OFPAT_COPY_TTL_OUT: {
            //ofp_action_header length was already checked
            *len -= sizeof(struct ofp_action_header);
            *dst = (struct ofl_action_header *)malloc(sizeof(struct ofl_action_header));
            break;
        }

        case OFPAT_COPY_TTL_IN: {
            //ofp_action_header length was already checked
            *len -= sizeof(struct ofp_action_header);
            *dst = (struct ofl_action_header *)malloc(sizeof(struct ofl_action_header));
            break;
        }

        case OFPAT_SET_MPLS_TTL: {
            struct ofp_action_mpls_ttl *sa;
            struct ofl_action_mpls_ttl *da;

            if (*len < sizeof(struct ofp_action_mpls_ttl)) {
                OFL_LOG_WARN(LOG_MODULE, "Received SET_MPLS_TTL action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_mpls_ttl *)src;

            da = (struct ofl_action_mpls_ttl *)malloc(sizeof(struct ofl_action_mpls_ttl));
            da->mpls_ttl = sa->mpls_ttl;

            *len -= sizeof(struct ofp_action_mpls_ttl);
            *dst = (struct ofl_action_header *)da;
            break;
        }

        case OFPAT_DEC_MPLS_TTL: {
            //ofp_action_header length was already checked
            *len -= sizeof(struct ofp_action_mpls_ttl);
            *dst = (struct ofl_action_header *)malloc(sizeof(struct ofl_action_header));
            break;
        }

        case OFPAT_PUSH_VLAN: 
        case OFPAT_PUSH_PBB:
        case OFPAT_PUSH_MPLS: {
            struct ofp_action_push *sa;
            struct ofl_action_push *da;

            if (*len < sizeof(struct ofp_action_push)) {
                OFL_LOG_WARN(LOG_MODULE, "Received PUSH_VLAN/MPLS/PBB action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_push *)src;

            if (((ntohs(src->type) == OFPAT_PUSH_VLAN) &&
                    (ntohs(sa->ethertype) != ETH_TYPE_VLAN &&
                     ntohs(sa->ethertype) != ETH_TYPE_VLAN_PBB)) ||
                ((ntohs(src->type) == OFPAT_PUSH_MPLS) &&
                    (ntohs(sa->ethertype) != ETH_TYPE_MPLS &&
                     ntohs(sa->ethertype) != ETH_TYPE_MPLS_MCAST)) ||
                ((ntohs(src->type) == OFPAT_PUSH_PBB) &&
                    (ntohs(sa->ethertype) != ETH_TYPE_PBB))) {
                OFL_LOG_WARN(LOG_MODULE, "Received PUSH_VLAN/MPLS/PBB has invalid eth type. (%u)", ntohs(sa->ethertype));
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
            }

            da = (struct ofl_action_push *)malloc(sizeof(struct ofl_action_push));
            da->ethertype = ntohs(sa->ethertype);

            *len -= sizeof(struct ofp_action_push);
            *dst = (struct ofl_action_header *)da;
            break;
        }

        case OFPAT_POP_VLAN: 
        case OFPAT_POP_PBB: {
            //ofp_action_header length was already checked
            *len -= sizeof(struct ofp_action_header);
            *dst = (struct ofl_action_header *)malloc(sizeof(struct ofl_action_header));
            break;
        }
                
        case OFPAT_POP_MPLS: {
            struct ofp_action_pop_mpls *sa;
            struct ofl_action_pop_mpls *da;

            if (*len < sizeof(struct ofp_action_pop_mpls)) {
                OFL_LOG_WARN(LOG_MODULE, "Received POP_MPLS action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_pop_mpls *)src;

            da = (struct ofl_action_pop_mpls *)malloc(sizeof(struct ofl_action_pop_mpls));
            da->ethertype = ntohs(sa->ethertype);

            *len -= sizeof(struct ofp_action_pop_mpls);
            *dst = (struct ofl_action_header *)da;
            break;
        }

        case OFPAT_SET_QUEUE: {
            struct ofp_action_set_queue *sa;
            struct ofl_action_set_queue *da;

            if (*len < sizeof(struct ofp_action_set_queue)) {
                OFL_LOG_WARN(LOG_MODULE, "Received SET_QUEUE action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_set_queue *)src;

            da = (struct ofl_action_set_queue *)malloc(sizeof(struct ofl_action_set_queue));
            da->queue_id = ntohl(sa->queue_id);

            *len -= sizeof(struct ofp_action_set_queue);
            *dst = (struct ofl_action_header *)da;
            break;
        }

        case OFPAT_GROUP: {
            struct ofp_action_group *sa;
            struct ofl_action_group *da;

            if (*len < sizeof(struct ofp_action_group)) {
                OFL_LOG_WARN(LOG_MODULE, "Received GROUP action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_group *)src;

            if (ntohl(sa->group_id) > OFPG_MAX) {
                if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) {
                    char *gs = ofl_group_to_string(ntohl(sa->group_id));
                    OFL_LOG_WARN(LOG_MODULE, "Received GROUP action has invalid group id (%s).", gs);
                    free(gs);
                }
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_GROUP);
            }

            da = (struct ofl_action_group *)malloc(sizeof(struct ofl_action_group));
            da->group_id = ntohl(sa->group_id);

            *len -= sizeof(struct ofp_action_group);
            *dst = (struct ofl_action_header *)da;
            break;
        }

        case OFPAT_SET_NW_TTL: {
            struct ofp_action_nw_ttl *sa;
            struct ofl_action_set_nw_ttl *da;

            if (*len < sizeof(struct ofp_action_nw_ttl)) {
                OFL_LOG_WARN(LOG_MODULE, "Received SET_NW_TTL action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_nw_ttl *)src;

            da = (struct ofl_action_set_nw_ttl *)malloc(sizeof(struct ofl_action_set_nw_ttl));
            da->nw_ttl = sa->nw_ttl;

            *len -= sizeof(struct ofp_action_nw_ttl);
            *dst = (struct ofl_action_header *)da;
            break;
        }

        case OFPAT_DEC_NW_TTL: {
            //ofp_action_header length was already checked
            *len -= sizeof(struct ofp_action_header);
            *dst = (struct ofl_action_header *)malloc(sizeof(struct ofl_action_header));
            break;
        }

        case OFPAT_SET_FIELD: {
            struct ofp_action_set_field *sa;
            struct ofl_action_set_field *da;
            uint8_t *value;
            
            sa = (struct ofp_action_set_field*) src;
            da = (struct ofl_action_set_field *)malloc(sizeof(struct ofl_action_set_field));
            da->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv));
            
            memcpy(&da->field->header,sa->field,4);
            da->field->header = ntohl(da->field->header);
            value = (uint8_t *) src + sizeof (struct ofp_action_set_field);
            da->field->value = malloc(OXM_LENGTH(da->field->header));
            /*TODO: need to check if other fields are valid */
            if(da->field->header == OXM_OF_IN_PORT || da->field->header == OXM_OF_IN_PHY_PORT
                                    || da->field->header == OXM_OF_METADATA
                                    || da->field->header == OXM_OF_IPV6_EXTHDR){

                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_SET_TYPE);
            }
            switch(OXM_LENGTH(da->field->header)){
                case 1:
                case 6:
                case 16:
                    memcpy(da->field->value , value, OXM_LENGTH(da->field->header));
                    break;
                
                case 2:{
                   uint16_t v = ntohs(*((uint16_t*) value));
                   memcpy(da->field->value , &v, OXM_LENGTH(da->field->header));
                    break;
                }
                case 4:{
                    uint32_t v; 
		    uint8_t field = OXM_FIELD(da->field->header);					
		    if( field != 11 && field != 12 && field != 22 && field != 23)  
		        v = htonl(*((uint32_t*) value));
		    else v = *((uint32_t*) value);
                    memcpy(da->field->value , &v, OXM_LENGTH(da->field->header));
                    break;
                }
                case 8:{
                    uint64_t v = hton64(*((uint64_t*) value));
                    memcpy(da->field->value , &v, OXM_LENGTH(da->field->header));
                    break;
                }                
            }
     	    *len -= ROUND_UP(ntohs(src->len),8);
     	    *dst = (struct ofl_action_header *)da;
            break;
	}

        case OFPAT_EXPERIMENTER: {
            ofl_err error;

            if (*len < sizeof(struct ofp_action_experimenter_header)) {
                OFL_LOG_WARN(LOG_MODULE, "Received EXPERIMENTER action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            if (exp == NULL || exp->act == NULL || exp->act->unpack == NULL) {
                OFL_LOG_WARN(LOG_MODULE, "Received EXPERIMENTER action, but no callback is given.");
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_EXPERIMENTER);
            }
            error = exp->act->unpack(src, len, dst);
            if (error) {
                return error;
            }
            break;
        }

        default: {
            OFL_LOG_WARN(LOG_MODULE, "Received unknown action type (%u).", ntohs(src->type));
            return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE);
        }
    }
    (*dst)->type = (enum ofp_action_type)ntohs(src->type);

    return 0;
}
Example #11
0
ofl_err
ofl_actions_unpack(struct ofp_action_header *src, size_t *len, struct ofl_action_header **dst, struct ofl_exp *exp) {

    if (*len < sizeof(struct ofp_action_header)) {
        OFL_LOG_WARN(LOG_MODULE, "Received action is too short (%zu).", *len);
        return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
    }

    if (*len < ntohs(src->len)) {
        OFL_LOG_WARN(LOG_MODULE, "Received action has invalid length (set to %u, but only %zu received).", ntohs(src->len), *len);
        return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
    }

    if ((ntohs(src->len) % 8) != 0) {
        OFL_LOG_WARN(LOG_MODULE, "Received action length is not a multiple of 64 bits (%u).", ntohs(src->len));
        return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
    }

    switch (ntohs(src->type)) {
        case OFPAT_OUTPUT: {
            struct ofp_action_output *sa;
            struct ofl_action_output *da;

            if (*len < sizeof(struct ofp_action_output)) {
                OFL_LOG_WARN(LOG_MODULE, "Received OUTPUT action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_output *)src;

            if (ntohl(sa->port) == 0 ||
                (ntohl(sa->port) > OFPP_MAX && ntohl(sa->port) < OFPP_IN_PORT) ||
                ntohl(sa->port) == OFPP_ANY) {
                if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) {
                    char *ps = ofl_port_to_string(ntohl(sa->port));
                    OFL_LOG_WARN(LOG_MODULE, "Received OUTPUT action has invalid port (%s).", ps);
                    free(ps);
                }
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT);
            }

            da = (struct ofl_action_output *)malloc(sizeof(struct ofl_action_output));
            da->port = ntohl(sa->port);
            da->max_len = ntohs(sa->max_len);

            *len -= sizeof(struct ofp_action_output);
            *dst = (struct ofl_action_header *)da;
            break;
        }

        case OFPAT_SET_VLAN_VID: {
            struct ofp_action_vlan_vid *sa;
            struct ofl_action_vlan_vid *da;

            if (*len < sizeof(struct ofp_action_vlan_vid)) {
                OFL_LOG_WARN(LOG_MODULE, "Received SET_VLAN_VID action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_vlan_vid *)src;

            if (ntohs(sa->vlan_vid) > VLAN_VID_MAX) {
                if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) {
                    char *vs = ofl_vlan_vid_to_string(ntohs(sa->vlan_vid));
                    OFL_LOG_WARN(LOG_MODULE, "Received SET_VLAN_VID action has invalid vid (%s).", vs);
                    free(vs);
                }
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
            }

            da = (struct ofl_action_vlan_vid *)malloc(sizeof(struct ofl_action_vlan_vid));
            da->vlan_vid = ntohs(sa->vlan_vid);

            *len -= sizeof(struct ofp_action_vlan_vid);
            *dst = (struct ofl_action_header *)da;
            break;
        }

        case OFPAT_SET_VLAN_PCP: {
            struct ofp_action_vlan_pcp *sa;
            struct ofl_action_vlan_pcp *da;

            if (*len < sizeof(struct ofp_action_vlan_pcp)) {
                OFL_LOG_WARN(LOG_MODULE, "Received SET_VLAN_PCP action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_vlan_pcp *)src;

            if (sa->vlan_pcp > VLAN_PCP_MAX) {
                OFL_LOG_WARN(LOG_MODULE, "Received SET_VLAN_PCP action has invalid pcp (%u).", sa->vlan_pcp);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
            }

            da = (struct ofl_action_vlan_pcp *)malloc(sizeof(struct ofl_action_vlan_pcp));
            da->vlan_pcp = sa->vlan_pcp;

            *len -= sizeof(struct ofp_action_vlan_pcp);
            *dst = (struct ofl_action_header *)da;
            break;
        }

        case OFPAT_SET_DL_SRC:
        case OFPAT_SET_DL_DST: {
            struct ofp_action_dl_addr *sa;
            struct ofl_action_dl_addr *da;

            if (*len < sizeof(struct ofp_action_dl_addr)) {
                OFL_LOG_WARN(LOG_MODULE, "Received SET_DL_SRC/DST action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_dl_addr *)src;

            da = (struct ofl_action_dl_addr *)malloc(sizeof(struct ofl_action_dl_addr));
            memcpy(&(da->dl_addr), &(sa->dl_addr), OFP_ETH_ALEN);

            *len -= sizeof(struct ofp_action_dl_addr);
            *dst = (struct ofl_action_header *)da;
            break;
        }
        case OFPAT_SET_NW_SRC:
        case OFPAT_SET_NW_DST: {
            struct ofp_action_nw_addr *sa;
            struct ofl_action_nw_addr *da;

            if (*len < sizeof(struct ofp_action_nw_addr)) {
                OFL_LOG_WARN(LOG_MODULE, "Received SET_NW_SRC/DST action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_nw_addr *)src;

            da = (struct ofl_action_nw_addr *)malloc(sizeof(struct ofl_action_nw_addr));
            da->nw_addr = sa->nw_addr;

            *len -= sizeof(struct ofp_action_nw_addr);
            *dst = (struct ofl_action_header *)da;
            break;
        }
        case OFPAT_SET_NW_TOS: {
            struct ofp_action_nw_tos *sa;
            struct ofl_action_nw_tos *da;

            if (*len < sizeof(struct ofp_action_nw_tos)) {
                OFL_LOG_WARN(LOG_MODULE, "Received SET_NW_TOS action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_nw_tos *)src;

            if (sa->nw_tos > IP_DSCP_MASK) {
                OFL_LOG_WARN(LOG_MODULE, "Received SET_NW_TOS action has invalid tos value (%u).", sa->nw_tos);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
            }

            da = (struct ofl_action_nw_tos *)malloc(sizeof(struct ofl_action_nw_tos));
            da->nw_tos = sa->nw_tos;

            *len -= sizeof(struct ofp_action_nw_tos);
            *dst = (struct ofl_action_header *)da;
            break;
        }

        case OFPAT_SET_NW_ECN: {
            struct ofp_action_nw_ecn *sa;
            struct ofl_action_nw_ecn *da;

            if (*len < sizeof(struct ofp_action_nw_ecn)) {
                OFL_LOG_WARN(LOG_MODULE, "Received SET_NW_ECN action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_nw_ecn *)src;

            if (sa->nw_ecn > IP_ECN_MASK) {
                OFL_LOG_WARN(LOG_MODULE, "Received SET_NW_ECN action has invalid ecn value (%u).", sa->nw_ecn);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
            }

            da = (struct ofl_action_nw_ecn *)malloc(sizeof(struct ofl_action_nw_ecn));
            da->nw_ecn = sa->nw_ecn;

            *len -= sizeof(struct ofp_action_nw_ecn);
            *dst = (struct ofl_action_header *)da;
            break;
        }

        case OFPAT_SET_TP_SRC:
        case OFPAT_SET_TP_DST: {
            struct ofp_action_tp_port *sa;
            struct ofl_action_tp_port *da;

            if (*len < sizeof(struct ofp_action_tp_port)) {
                OFL_LOG_WARN(LOG_MODULE, "Received SET_TP_SRC/DST action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_tp_port *)src;

            da = (struct ofl_action_tp_port *)malloc(sizeof(struct ofl_action_tp_port));
            da->tp_port = ntohs(sa->tp_port);

            *len -= sizeof(struct ofp_action_tp_port);
            *dst = (struct ofl_action_header *)da;
            break;
        }

        case OFPAT_COPY_TTL_OUT: {
            //ofp_action_header length was already checked
            *len -= sizeof(struct ofp_action_header);
            *dst = (struct ofl_action_header *)malloc(sizeof(struct ofl_action_header));
            break;
        }

        case OFPAT_COPY_TTL_IN: {
            //ofp_action_header length was already checked
            *len -= sizeof(struct ofp_action_header);
            *dst = (struct ofl_action_header *)malloc(sizeof(struct ofl_action_header));
            break;
        }

        case OFPAT_SET_MPLS_LABEL: {
            struct ofp_action_mpls_label *sa;
            struct ofl_action_mpls_label *da;

            if (*len < sizeof(struct ofp_action_mpls_label)) {
                OFL_LOG_WARN(LOG_MODULE, "Received SET_MPLS_LABEL action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_mpls_label *)src;

            if (ntohl(sa->mpls_label) > MPLS_LABEL_MAX) {
                OFL_LOG_WARN(LOG_MODULE, "Received SET_MPLS_LABEL action has invalid label value (%u).", ntohl(sa->mpls_label));
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
            }

            da = (struct ofl_action_mpls_label *)malloc(sizeof(struct ofl_action_mpls_label));
            da->mpls_label = ntohl(sa->mpls_label);

            *len -= sizeof(struct ofp_action_mpls_label);
            *dst = (struct ofl_action_header *)da;
            break;
        }

        case OFPAT_SET_MPLS_TC: {
            struct ofp_action_mpls_tc *sa;
            struct ofl_action_mpls_tc *da;

            if (*len < sizeof(struct ofp_action_mpls_tc)) {
                OFL_LOG_WARN(LOG_MODULE, "Received SET_MPLS_TC action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_mpls_tc *)src;

            if (sa->mpls_tc > MPLS_TC_MAX) {
                OFL_LOG_WARN(LOG_MODULE, "Received SET_MPLS_TC action has invalid tc value (%u).", sa->mpls_tc);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
            }

            da = (struct ofl_action_mpls_tc *)malloc(sizeof(struct ofl_action_mpls_tc));
            da->mpls_tc = sa->mpls_tc;

            *len -= sizeof(struct ofp_action_mpls_tc);
            *dst = (struct ofl_action_header *)da;
            break;
        }

        case OFPAT_SET_MPLS_TTL: {
            struct ofp_action_mpls_ttl *sa;
            struct ofl_action_mpls_ttl *da;

            if (*len < sizeof(struct ofp_action_mpls_ttl)) {
                OFL_LOG_WARN(LOG_MODULE, "Received SET_MPLS_TTL action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_mpls_ttl *)src;

            da = (struct ofl_action_mpls_ttl *)malloc(sizeof(struct ofl_action_mpls_ttl));
            da->mpls_ttl = sa->mpls_ttl;

            *len -= sizeof(struct ofp_action_mpls_ttl);
            *dst = (struct ofl_action_header *)da;
            break;
        }

        case OFPAT_DEC_MPLS_TTL: {
            //ofp_action_header length was already checked
            *len -= sizeof(struct ofp_action_mpls_ttl);
            *dst = (struct ofl_action_header *)malloc(sizeof(struct ofl_action_header));
            break;
        }

        case OFPAT_PUSH_VLAN:
        case OFPAT_PUSH_MPLS: {
            struct ofp_action_push *sa;
            struct ofl_action_push *da;

            if (*len < sizeof(struct ofp_action_push)) {
                OFL_LOG_WARN(LOG_MODULE, "Received PUSH_VLAN/MPLS action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_push *)src;

            if (((ntohs(src->type) == OFPAT_PUSH_VLAN) &&
                    (ntohs(sa->ethertype) != ETH_TYPE_VLAN &&
                     ntohs(sa->ethertype) != ETH_TYPE_VLAN_PBB)) ||
                ((ntohs(src->type) == OFPAT_PUSH_MPLS) &&
                    (ntohs(sa->ethertype) != ETH_TYPE_MPLS &&
                     ntohs(sa->ethertype) != ETH_TYPE_MPLS_MCAST))) {
                OFL_LOG_WARN(LOG_MODULE, "Received PUSH_VLAN/MPLS has invalid eth type. (%u)", ntohs(sa->ethertype));
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
            }

            da = (struct ofl_action_push *)malloc(sizeof(struct ofl_action_push));
            da->ethertype = ntohs(sa->ethertype);

            *len -= sizeof(struct ofp_action_push);
            *dst = (struct ofl_action_header *)da;
            break;
        }

        case OFPAT_POP_VLAN: {
            //ofp_action_header length was already checked
            *len -= sizeof(struct ofp_action_header);
            *dst = (struct ofl_action_header *)malloc(sizeof(struct ofl_action_header));
            break;
        }

        case OFPAT_POP_MPLS: {
            struct ofp_action_pop_mpls *sa;
            struct ofl_action_pop_mpls *da;

            if (*len < sizeof(struct ofp_action_pop_mpls)) {
                OFL_LOG_WARN(LOG_MODULE, "Received POP_MPLS action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_pop_mpls *)src;

            da = (struct ofl_action_pop_mpls *)malloc(sizeof(struct ofl_action_pop_mpls));
            da->ethertype = ntohs(sa->ethertype);

            *len -= sizeof(struct ofp_action_pop_mpls);
            *dst = (struct ofl_action_header *)da;
            break;
        }

        case OFPAT_SET_QUEUE: {
            struct ofp_action_set_queue *sa;
            struct ofl_action_set_queue *da;

            if (*len < sizeof(struct ofp_action_set_queue)) {
                OFL_LOG_WARN(LOG_MODULE, "Received SET_QUEUE action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_set_queue *)src;

            da = (struct ofl_action_set_queue *)malloc(sizeof(struct ofl_action_set_queue));
            da->queue_id = ntohl(sa->queue_id);

            *len -= sizeof(struct ofp_action_set_queue);
            *dst = (struct ofl_action_header *)da;
            break;
        }

        case OFPAT_GROUP: {
            struct ofp_action_group *sa;
            struct ofl_action_group *da;

            if (*len < sizeof(struct ofp_action_group)) {
                OFL_LOG_WARN(LOG_MODULE, "Received GROUP action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_group *)src;

            if (ntohl(sa->group_id) > OFPG_MAX) {
                if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) {
                    char *gs = ofl_group_to_string(ntohl(sa->group_id));
                    OFL_LOG_WARN(LOG_MODULE, "Received GROUP action has invalid group id (%s).", gs);
                    free(gs);
                }
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
            }

            da = (struct ofl_action_group *)malloc(sizeof(struct ofl_action_group));
            da->group_id = ntohl(sa->group_id);

            *len -= sizeof(struct ofp_action_group);
            *dst = (struct ofl_action_header *)da;
            break;
        }

        case OFPAT_SET_NW_TTL: {
            struct ofp_action_nw_ttl *sa;
            struct ofl_action_set_nw_ttl *da;

            if (*len < sizeof(struct ofp_action_nw_ttl)) {
                OFL_LOG_WARN(LOG_MODULE, "Received SET_NW_TTL action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            sa = (struct ofp_action_nw_ttl *)src;

            da = (struct ofl_action_set_nw_ttl *)malloc(sizeof(struct ofl_action_set_nw_ttl));
            da->nw_ttl = ntohs(sa->nw_ttl);

            *len -= sizeof(struct ofp_action_nw_ttl);
            *dst = (struct ofl_action_header *)da;
            break;
        }

        case OFPAT_DEC_NW_TTL: {
            //ofp_action_header length was already checked
            *len -= sizeof(struct ofp_action_header);
            *dst = (struct ofl_action_header *)malloc(sizeof(struct ofl_action_header));
            break;
        }

        case OFPAT_EXPERIMENTER: {
            ofl_err error;

            if (*len < sizeof(struct ofp_action_experimenter_header)) {
                OFL_LOG_WARN(LOG_MODULE, "Received EXPERIMENTER action has invalid length (%zu).", *len);
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
            }

            if (exp == NULL || exp->act == NULL || exp->act->unpack == NULL) {
                OFL_LOG_WARN(LOG_MODULE, "Received EXPERIMENTER action, but no callback is given.");
                return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_EXPERIMENTER);
            }
            error = exp->act->unpack(src, len, dst);
            if (error) {
                return error;
            }
            break;
        }

        default: {
            OFL_LOG_WARN(LOG_MODULE, "Received unknown action type (%u).", ntohs(src->type));
            return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE);
        }
    }

    (*dst)->type = (enum ofp_action_type)ntohs(src->type);
    return 0;
}
ofl_err
ofl_structs_group_stats_unpack(struct ofp_group_stats *src, size_t *len, struct ofl_group_stats **dst) {
    struct ofl_group_stats *s;
    struct ofp_bucket_counter *c;
    ofl_err error;
    size_t slen;
    size_t i;

    if (*len < sizeof(struct ofp_group_stats)) {
        OFL_LOG_WARN(LOG_MODULE, "Received group desc stats reply is too short (%zu).", *len);
        return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
    }

    if (*len < ntohs(src->length)) {
        OFL_LOG_WARN(LOG_MODULE, "Received group stats reply has invalid length (set to %u, but only %zu received).", ntohs(src->length), *len);
        return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
    }

    if (ntohl(src->group_id) > OFPG_MAX) {
        if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) {
            char *gs = ofl_group_to_string(ntohl(src->group_id));
            OFL_LOG_WARN(LOG_MODULE, "Received group stats has invalid group_id (%s).", gs);
            free(gs);
        }
        return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN);
    }
    slen = ntohs(src->length) - sizeof(struct ofp_group_stats);

    s = (struct ofl_group_stats *)malloc(sizeof(struct ofl_group_stats));
    s->group_id = ntohl(src->group_id);
    s->ref_count = ntohl(src->ref_count);
    s->packet_count = ntoh64(src->packet_count);
    s->byte_count = ntoh64(src->byte_count);
    s->duration_sec =  htonl(src->duration_sec);
    s->duration_nsec =  htonl(src->duration_nsec);

    error = ofl_utils_count_ofp_bucket_counters(src->bucket_stats, slen, &s->counters_num);
    if (error) {
        free(s);
        return error;
    }
    s->counters = (struct ofl_bucket_counter **)malloc(s->counters_num * sizeof(struct ofl_bucket_counter *));

    c = src->bucket_stats;
    for (i = 0; i < s->counters_num; i++) {
        error = ofl_structs_bucket_counter_unpack(c, &slen, &(s->counters[i]));
        if (error) {
            OFL_UTILS_FREE_ARR(s->counters, i);
            free(s);
            return error;
        }
        c = (struct ofp_bucket_counter *)((uint8_t *)c + sizeof(struct ofp_bucket_counter));
    }

    if (slen != 0) {
        *len = *len - ntohs(src->length) + slen;
        OFL_LOG_WARN(LOG_MODULE, "The received group stats contained extra bytes (%zu).", slen);
        ofl_structs_free_group_stats(s);
        return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
    }

    *len -= ntohs(src->length);
    *dst = s;
    return 0;
}
ofl_err
ofl_structs_flow_stats_unpack(struct ofp_flow_stats *src, uint8_t *buf, size_t *len, struct ofl_flow_stats **dst, struct ofl_exp *exp) {
    struct ofl_flow_stats *s;
    struct ofp_instruction *inst;
    ofl_err error;
    size_t slen;
    size_t i;
    int match_pos;
    if (*len < ( (sizeof(struct ofp_flow_stats) - sizeof(struct ofp_match)) + ROUND_UP(ntohs(src->match.length),8))) {
        OFL_LOG_WARN(LOG_MODULE, "Received flow stats has invalid length (%zu).", *len);
        return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
    }

    if (*len < ntohs(src->length)) {
        OFL_LOG_WARN(LOG_MODULE, "Received flow stats reply has invalid length (set to %u, but only %zu received).", ntohs(src->length), *len);
        return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
    }

    if (src->table_id >= PIPELINE_TABLES) {
        if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) {
            char *ts = ofl_table_to_string(src->table_id);
            OFL_LOG_WARN(LOG_MODULE, "Received flow stats has invalid table_id (%s).", ts);
            free(ts);
        }
        return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_TABLE_ID);
    }

    slen = ntohs(src->length) - (sizeof(struct ofp_flow_stats) - sizeof(struct ofp_match));

    s = (struct ofl_flow_stats *)malloc(sizeof(struct ofl_flow_stats));
    s->table_id =             src->table_id;
    s->duration_sec =  ntohl( src->duration_sec);
    s->duration_nsec = ntohl( src->duration_nsec);
    s->priority =      ntohs( src->priority);
    s->idle_timeout =  ntohs( src->idle_timeout);
    s->hard_timeout =  ntohs( src->hard_timeout);
    s->cookie =        ntoh64(src->cookie);
    s->packet_count =  ntoh64(src->packet_count);
    s->byte_count =    ntoh64(src->byte_count);

    match_pos = sizeof(struct ofp_flow_stats) - 4;

    error = ofl_structs_match_unpack(&(src->match),buf + match_pos , &slen, &(s->match), exp);
    if (error) {
        free(s);
        return error;
    }
    error = ofl_utils_count_ofp_instructions((struct ofp_instruction *) (buf + ROUND_UP(match_pos + s->match->length,8)), 
                                            slen, &s->instructions_num);
    
    if (error) {
        ofl_structs_free_match(s->match, exp);
        free(s);
        return error;
    }
   s->instructions = (struct ofl_instruction_header **)malloc(s->instructions_num * sizeof(struct ofl_instruction_header *));

   inst = (struct ofp_instruction *) (buf + ROUND_UP(match_pos + s->match->length,8));
   for (i = 0; i < s->instructions_num; i++) {
        error = ofl_structs_instructions_unpack(inst, &slen, &(s->instructions[i]), exp);
        if (error) {
            OFL_UTILS_FREE_ARR_FUN2(s->instructions, i,
                                    ofl_structs_free_instruction, exp);
            free(s);
            return error;
        }
        inst = (struct ofp_instruction *)((uint8_t *)inst + ntohs(inst->len));
    }

    if (slen != 0) {
        *len = *len - ntohs(src->length) + slen;
        OFL_LOG_WARN(LOG_MODULE, "The received flow stats contained extra bytes (%zu).", slen);
        ofl_structs_free_flow_stats(s, exp);
        return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
    }
    *len -= ntohs(src->length);
    *dst = s;
    return 0;
}
ofl_err
ofl_structs_group_desc_stats_unpack(struct ofp_group_desc_stats *src, size_t *len, struct ofl_group_desc_stats **dst, struct ofl_exp *exp) {
    struct ofl_group_desc_stats *dm;
    struct ofp_bucket *bucket;
    ofl_err error;
    size_t dlen;
    size_t i;

    if (*len < sizeof(struct ofp_group_desc_stats)) {
        OFL_LOG_WARN(LOG_MODULE, "Received group desc stats reply is too short (%zu).", *len);
        return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
    }

    if (*len < ntohs(src->length)) {
        OFL_LOG_WARN(LOG_MODULE, "Received group desc stats reply has invalid length (set to %u, but only %zu received).", ntohs(src->length), *len);
        return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
    }

    if (ntohl(src->group_id) > OFPG_MAX) {
        if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) {
            char *gs = ofl_group_to_string(ntohl(src->group_id));
            OFL_LOG_WARN(LOG_MODULE, "Received group desc stats has invalid group_id (%s).", gs);
            free(gs);
        }
        return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
    }
    dlen = ntohs(src->length) - sizeof(struct ofp_group_desc_stats);

    dm = (struct ofl_group_desc_stats *)malloc(sizeof(struct ofl_group_desc_stats));

    dm->type = src->type;
    dm->group_id = ntohl(src->group_id);

    error = ofl_utils_count_ofp_buckets(src->buckets, dlen, &dm->buckets_num);
    if (error) {
        free(dm);
        return error;
    }
    dm->buckets = (struct ofl_bucket **)malloc(dm->buckets_num * sizeof(struct ofl_bucket *));

    bucket = src->buckets;
    for (i = 0; i < dm->buckets_num; i++) {
        error = ofl_structs_bucket_unpack(bucket, &dlen, dm->type, &(dm->buckets[i]), exp);
        if (error) {
            OFL_UTILS_FREE_ARR_FUN2(dm->buckets, i,
                                    ofl_structs_free_bucket, exp);
            free (dm);
            return error;
        }
        bucket = (struct ofp_bucket *)((uint8_t *)bucket + ntohs(bucket->len));
    }

    if (dlen != 0) {
        *len = *len - ntohs(src->length) + dlen;
        OFL_LOG_WARN(LOG_MODULE, "The received group desc stats contained extra bytes (%zu).", dlen);
        ofl_structs_free_group_desc_stats(dm, exp);
        return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
    }

    *len -= ntohs(src->length);
    *dst = dm;
    return 0;
}
static ofl_err
ofl_msg_unpack_group_mod(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) {
    struct ofp_group_mod *sm;
    struct ofl_msg_group_mod *dm;
    struct ofp_bucket *bucket;
    ofl_err error;
    size_t i;

    if (*len < sizeof(struct ofp_group_mod)) {
        OFL_LOG_WARN(LOG_MODULE, "Received GROUP_MOD message has invalid length (%zu).", *len);
        return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
    }
    *len -= sizeof(struct ofp_group_mod);

    sm = (struct ofp_group_mod *)src;

    if (ntohs(sm->command) > OFPGC_DELETE) {
        OFL_LOG_WARN(LOG_MODULE, "Received GROUP_MOD message with invalid command (%u).", ntohs(sm->command));
        return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE);
    }

    if (ntohs(sm->type) > OFPGT_FF && ntohs(sm->type) < 128 /* experimenter */) {
        OFL_LOG_WARN(LOG_MODULE, "Received GROUP_MOD message with invalid type (%u).", ntohs(sm->type));
        return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE);
    }

    if (ntohl(sm->group_id) > OFPG_MAX &&
                       !(ntohs(sm->command) == OFPGC_DELETE && ntohl(sm->group_id) == OFPG_ALL)) {
        if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) {
            char *gs = ofl_group_to_string(ntohl(sm->group_id));
            OFL_LOG_WARN(LOG_MODULE, "Received GROUP_MOD message with invalid group id (%s).", gs);
            free(gs);
        }
        return ofl_error(OFPET_GROUP_MOD_FAILED, OFPGMFC_INVALID_GROUP);
    }

    dm = (struct ofl_msg_group_mod *)malloc(sizeof(struct ofl_msg_group_mod));

    dm->command = (enum ofp_group_mod_command)ntohs(sm->command);
    dm->type = sm->type;
    dm->group_id = ntohl(sm->group_id);

    error = ofl_utils_count_ofp_buckets(&(sm->buckets), *len, &dm->buckets_num);
    if (error) {
        free(dm);
        return error;
    }

    if (dm->command == OFPGC_DELETE && dm->buckets_num > 0) {
        OFL_LOG_WARN(LOG_MODULE, "Received DELETE group command with buckets (%zu).", dm->buckets_num);
        free(dm);
        return ofl_error(OFPET_GROUP_MOD_FAILED, OFPGMFC_INVALID_GROUP);
    }

    if (dm->type == OFPGT_INDIRECT && dm->buckets_num != 1) {
        OFL_LOG_WARN(LOG_MODULE, "Received INDIRECT group doesn't have exactly one bucket (%zu).", dm->buckets_num);
        free(dm);
        return ofl_error(OFPET_GROUP_MOD_FAILED, OFPGMFC_INVALID_GROUP);
    }

    dm->buckets = (struct ofl_bucket **)malloc(dm->buckets_num * sizeof(struct ofl_bucket *));

    bucket = sm->buckets;
    for (i = 0; i < dm->buckets_num; i++) {
        error = ofl_structs_bucket_unpack(bucket, len, dm->type, &(dm->buckets[i]), exp);
        if (error) {
            OFL_UTILS_FREE_ARR_FUN2(dm->buckets, i,
                                    ofl_structs_free_bucket, exp);
            free(dm);
            return error;
        }
        bucket = (struct ofp_bucket *)((uint8_t *)bucket + ntohs(bucket->len));
    }

    *msg = (struct ofl_msg_header *)dm;
    return 0;
}
static ofl_err
ofl_msg_unpack_packet_out(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) {
    struct ofp_packet_out *sp;
    struct ofl_msg_packet_out *dp;
    struct ofp_action_header *act;
    uint8_t *data;
    ofl_err error;
    size_t i, actions_num;

    if (*len < sizeof(struct ofp_packet_out)) {
        OFL_LOG_WARN(LOG_MODULE, "Received PACKET_OUT message has invalid length (%zu).", *len);
        return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN);
    }

    sp = (struct ofp_packet_out *)src;

    if (ntohl(sp->in_port) == 0 ||
        (ntohl(sp->in_port) > OFPP_MAX && ntohl(sp->in_port) != OFPP_CONTROLLER)) {
        if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) {
            char *ps = ofl_port_to_string(ntohl(sp->in_port));
            OFL_LOG_WARN(LOG_MODULE, "Received PACKET_OUT message with invalid in_port (%s).", ps);
            free(ps);
        }
        return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
    }

    if (ntohl(sp->buffer_id) != 0xffffffff &&
        *len != sizeof(struct ofp_packet_out) + ntohs(sp->actions_len)) {
        if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) {
            char *bs = ofl_buffer_to_string(ntohl(sp->buffer_id));
            OFL_LOG_WARN(LOG_MODULE, "Received PACKET_OUT message with data and buffer_id (%s).", bs);
            free(bs);
        }
        return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN);
    }
    *len -= sizeof(struct ofp_packet_out);

    dp = (struct ofl_msg_packet_out *)malloc(sizeof(struct ofl_msg_packet_out));

    dp->buffer_id = ntohl(sp->buffer_id);
    dp->in_port = ntohl(sp->in_port);

    if (*len < ntohs(sp->actions_len)) {
        OFL_LOG_WARN(LOG_MODULE, "Received PACKET_OUT message has invalid action length (%zu).", *len);
        free(dp);
        return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN);
    }

    error = ofl_utils_count_ofp_actions(&(sp->actions), ntohs(sp->actions_len), &actions_num);
    if (error) {
        free(dp);
        return error;
    }
    dp->actions_num = actions_num;
    dp->actions = (struct ofl_action_header **)malloc(dp->actions_num * sizeof(struct ofp_action_header *));

    // TODO Zoltan: Output actions can contain OFPP_TABLE
    act = sp->actions;
    for (i = 0; i < dp->actions_num; i++) {
        error = ofl_actions_unpack(act, len, &(dp->actions[i]), exp);
        if (error) {
            OFL_UTILS_FREE_ARR_FUN2(dp->actions, i,
                                    ofl_actions_free, exp);
            free(dp);
        }
        act = (struct ofp_action_header *)((uint8_t *)act + ntohs(act->len));
    }

    data = ((uint8_t *)sp->actions) + ntohs(sp->actions_len);
    dp->data_length = *len;
    dp->data = *len > 0 ? (uint8_t *)memcpy(malloc(*len), data, *len) : NULL;
    *len = 0;

    *msg = (struct ofl_msg_header *)dp;
    return 0;
}