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; }
static ofl_err ofl_structs_table_properties_unpack(struct ofp_table_feature_prop_header * src, size_t *len, struct ofl_table_feature_prop_header **dst, struct ofl_exp *exp){ size_t plen; ofl_err error; struct ofl_table_feature_prop_header * prop = NULL; if (*len < sizeof(struct ofp_table_feature_prop_header)){ OFL_LOG_WARN(LOG_MODULE, "Received feature is too short (%zu).", *len); return ofl_error(OFPET_TABLE_FEATURES_FAILED, OFPTFFC_BAD_LEN); } if (*len < ntohs(src->length)) { OFL_LOG_WARN(LOG_MODULE, "Received table property has invalid length (set to %u, but only %zu received).", ntohs(src->length), *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } plen = ntohs(src->length); switch(ntohs(src->type)){ case OFPTFPT_INSTRUCTIONS: case OFPTFPT_INSTRUCTIONS_MISS:{ struct ofp_table_feature_prop_instructions *sp = (struct ofp_table_feature_prop_instructions*) src; struct ofl_table_feature_prop_instructions *dp; size_t ilen,i; uint8_t *ptr; if (plen < sizeof(struct ofp_table_feature_prop_instructions)) { OFL_LOG_WARN(LOG_MODULE, "Received INSTRUCTION feature has invalid length (%zu).", *len); return ofl_error(OFPET_TABLE_FEATURES_FAILED, OFPTFFC_BAD_LEN); } dp = (struct ofl_table_feature_prop_instructions*) malloc(sizeof(struct ofl_table_feature_prop_instructions)); ilen = plen - sizeof(struct ofp_table_feature_prop_instructions); error = ofl_utils_count_ofp_instructions((uint8_t*) sp->instruction_ids, ilen, &dp->ids_num); if(error){ free(dp); return error; } dp->instruction_ids = (struct ofl_instruction_header*) malloc(sizeof(struct ofl_instruction_header) * dp->ids_num); ptr = (uint8_t*) sp->instruction_ids; for(i = 0; i < dp->ids_num; i++){ dp->instruction_ids[i].type = ntohs(((struct ofp_instruction*) ptr)->type); ptr += ntohs(((struct ofp_instruction*) ptr)->len); } plen -= ntohs(sp->length); prop = (struct ofl_table_feature_prop_header*) dp; break; } case OFPTFPT_NEXT_TABLES: case OFPTFPT_NEXT_TABLES_MISS:{ struct ofp_table_feature_prop_next_tables *sp = (struct ofp_table_feature_prop_next_tables*) src; struct ofl_table_feature_prop_next_tables *dp; if (plen < sizeof(struct ofp_table_feature_prop_next_tables)) { OFL_LOG_WARN(LOG_MODULE, "Received NEXT TABLE feature has invalid length (%zu).", *len); return ofl_error(OFPET_TABLE_FEATURES_FAILED, OFPTFFC_BAD_LEN); } dp = (struct ofl_table_feature_prop_next_tables*) malloc(sizeof(struct ofl_table_feature_prop_next_tables)); dp->table_num = ntohs(sp->length) - sizeof(struct ofp_table_feature_prop_next_tables); dp->next_table_ids = (uint8_t*) malloc(sizeof(uint8_t) * dp->table_num); memcpy(dp->next_table_ids, sp->next_table_ids, dp->table_num); plen -= ntohs(sp->length); prop = (struct ofl_table_feature_prop_header*) dp; break; } case OFPTFPT_WRITE_ACTIONS: case OFPTFPT_WRITE_ACTIONS_MISS: case OFPTFPT_APPLY_ACTIONS: case OFPTFPT_APPLY_ACTIONS_MISS:{ struct ofp_table_feature_prop_actions *sp = (struct ofp_table_feature_prop_actions*) src; struct ofl_table_feature_prop_actions *dp; size_t alen, i; uint8_t *ptr; if (plen < sizeof(struct ofp_table_feature_prop_actions)) { OFL_LOG_WARN(LOG_MODULE, "Received ACTION feature has invalid length (%zu).", *len); return ofl_error(OFPET_TABLE_FEATURES_FAILED, OFPTFFC_BAD_LEN); } alen = plen - sizeof(struct ofp_table_feature_prop_actions); dp = (struct ofl_table_feature_prop_actions*) malloc(sizeof(struct ofl_table_feature_prop_actions)); error = ofl_utils_count_ofp_actions((uint8_t*)sp->action_ids, alen, &dp->actions_num); if(error){ free(dp); return error; } dp->action_ids = (struct ofl_action_header*) malloc(sizeof(struct ofl_action_header) * dp->actions_num); ptr = (uint8_t*) sp->action_ids; for(i = 0; i < dp->actions_num; i++){ dp->action_ids[i].type = ntohs(((struct ofp_action_header*) ptr)->type); dp->action_ids[i].len = ntohs(((struct ofp_action_header*) ptr)->len); ptr += ntohs(((struct ofp_action_header*) ptr)->len); } plen -= ntohs(sp->length); prop = (struct ofl_table_feature_prop_header*) dp; break; } case OFPTFPT_MATCH: case OFPTFPT_WILDCARDS: case OFPTFPT_WRITE_SETFIELD: case OFPTFPT_WRITE_SETFIELD_MISS: case OFPTFPT_APPLY_SETFIELD: case OFPTFPT_APPLY_SETFIELD_MISS:{ struct ofp_table_feature_prop_oxm *sp = (struct ofp_table_feature_prop_oxm*) src; struct ofl_table_feature_prop_oxm *dp; size_t i; if (plen < sizeof(struct ofp_table_feature_prop_oxm)) { OFL_LOG_WARN(LOG_MODULE, "Received MATCH feature has invalid length (%zu).", *len); return ofl_error(OFPET_TABLE_FEATURES_FAILED, OFPTFFC_BAD_LEN); } dp = (struct ofl_table_feature_prop_oxm*) malloc(sizeof(struct ofl_table_feature_prop_oxm)); dp->oxm_num = (ntohs(sp->length) - sizeof(struct ofp_table_feature_prop_oxm))/sizeof(uint32_t); dp->oxm_ids = (uint32_t*) malloc(sizeof(uint32_t) * dp->oxm_num); for(i = 0; i < dp->oxm_num; i++ ){ dp->oxm_ids[i] = ntohl(sp->oxm_ids[i]); } plen -= ntohs(sp->length); prop = (struct ofl_table_feature_prop_header*) dp; break; } } // must set type before check, so free works correctly prop->type = (enum ofp_table_feature_prop_type) ntohs(src->type); /* Make sure it can be reused for packing. Jean II */ prop->length = ntohs(src->length); if (plen != 0){ *len = *len - ntohs(src->length) + plen; OFL_LOG_WARN(LOG_MODULE, "The received property contained extra bytes (%zu).", plen); //ofl_structs_free_property(inst, exp); return ofl_error(OFPET_TABLE_FEATURES_FAILED, OFPTFFC_BAD_LEN); } *len -= ntohs(src->length); (*dst) = prop; return 0; }
ofl_err ofl_structs_bucket_unpack(struct ofp_bucket *src, size_t *len, uint8_t gtype, struct ofl_bucket **dst, struct ofl_exp *exp, char *errbuf) { struct ofl_bucket *b; struct ofp_action_header *act; size_t blen; ofl_err error; size_t i; if (*len < sizeof(struct ofp_bucket)) { if (errbuf != NULL) { snprintf(errbuf, OFL_ERRBUF_SIZE, "Received bucket is too short (%zu).", *len); } return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } if (*len < ntohs(src->len)) { if (errbuf != NULL) { snprintf(errbuf, OFL_ERRBUF_SIZE, "Received bucket has invalid length (set to %u, but only %zu received).", ntohs(src->len), *len); } return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } blen = ntohs(src->len) - sizeof(struct ofp_bucket); if (gtype == OFPGT_SELECT && ntohs(src->weight) == 0) { if (errbuf != NULL) { snprintf(errbuf, OFL_ERRBUF_SIZE, "Received bucket has no weight for SELECT group."); } return ofl_error(OFPET_GROUP_MOD_FAILED, OFPGMFC_INVALID_GROUP); } if (gtype != OFPGT_SELECT && ntohs(src->weight) > 0) { if (errbuf != NULL) { snprintf(errbuf, OFL_ERRBUF_SIZE, "Received bucket has weight for non-SELECT group."); } return ofl_error(OFPET_GROUP_MOD_FAILED, OFPGMFC_INVALID_GROUP); } b = (struct ofl_bucket *)malloc(sizeof(struct ofl_bucket)); b->weight = ntohs(src->weight); b->watch_port = ntohl(src->watch_port); b->watch_group = ntohl(src->watch_group); error = ofl_utils_count_ofp_actions((uint8_t *)src->actions, blen, &b->actions_num, errbuf); if (error) { free(b); return error; } b->actions = (struct ofl_action_header **)malloc(b->actions_num * sizeof(struct ofl_action_header *)); act = src->actions; for (i = 0; i < b->actions_num; i++) { error = ofl_actions_unpack(act, &blen, &(b->actions[i]), exp, errbuf); if (error) { *len = *len - ntohs(src->len) + blen; OFL_UTILS_FREE_ARR_FUN3(b->actions, i, ofl_actions_free, exp, errbuf); //TODO error free(b); return error; } act = (struct ofp_action_header *)((uint8_t *)act + ntohs(act->len)); } if (blen >= 8) { *len = *len - ntohs(src->len) + blen; ofl_structs_free_bucket(b, exp, errbuf); //TODO error if (errbuf != NULL) { snprintf(errbuf, OFL_ERRBUF_SIZE, "Received bucket has more than 64 bit padding (%zu).", blen); } return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } *len -= ntohs(src->len); *dst = b; 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, char *errbuf) { 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)) { if (errbuf != NULL) { snprintf(errbuf, OFL_ERRBUF_SIZE, "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 (errbuf != NULL) { char *ps = ofl_port_to_string(ntohl(sp->in_port)); snprintf(errbuf, OFL_ERRBUF_SIZE, "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 (errbuf != NULL) { char *bs = ofl_buffer_to_string(ntohl(sp->buffer_id)); snprintf(errbuf, OFL_ERRBUF_SIZE, "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)) { if (errbuf != NULL) { snprintf(errbuf, OFL_ERRBUF_SIZE, "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, errbuf); 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, errbuf); if (error) { OFL_UTILS_FREE_ARR_FUN3(dp->actions, i, ofl_actions_free, exp, errbuf); 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; }