diff --git a/src/cmdu.c b/src/cmdu.c index 114313d11b97450b9e4453fc36359d06236dfc92..fa5aa37b8040e6b12e729f0e51d11aae2c0faf58 100644 --- a/src/cmdu.c +++ b/src/cmdu.c @@ -172,6 +172,37 @@ static size_t tlv_minsize(struct tlv *t) return 0; } +__thread int ieee1905_errval; + +int *ieee1905_get_errval(void) +{ + return &ieee1905_errval; +} + +#define ieee1905_set_error(v) (ieee1905_errval = (v)) + +static const char *ieee1905_errlist[IEEE1905_ERROR_MAXNUM] = { + "Ok", + [CMDU_STATUS_ERR_TLV_MALFORMED] = "TLV is malformed", + [CMDU_STATUS_ERR_TLV_NUM_LESS] = "Number of TLVs less than required", + [CMDU_STATUS_ERR_TLV_NUM_MORE] = "Number of TLVs more than required", + [CMDU_STATUS_ERR_TLV_NO_EOM] = "EOM TLV is not present", + [CMDU_STATUS_ERR_TLV_RESIDUE_DATA] = "Stray non-zero bytes after EOM", + [CMDU_STATUS_ERR_TLV_LEN_INSUFFICIENT] = "TLV length insufficient", + [CMDU_STATUS_ERR_TLV_LEN_OVERFLOW] = "TLV length points to beyond CMDU", + [CMDU_STATUS_ERR_MISC] = "Misc cmdu error", +}; + +const char *ieee1905_strerror(int err) +{ + int last_err = err; + + if (last_err >= 0 && last_err <= IEEE1905_ERROR_LAST) + return ieee1905_errlist[last_err]; + + return ""; +} + void cmdu_set_type(struct cmdu_buff *c, uint16_t type) { if (c && c->cdata) @@ -691,6 +722,7 @@ int cmdu_parse_tlvs(struct cmdu_buff *c, struct tlv *tv[][16], int i; + ieee1905_set_error(CMDU_STATUS_OK); if (!c || !c->data || !c->datalen) return -1; @@ -705,24 +737,32 @@ int cmdu_parse_tlvs(struct cmdu_buff *c, struct tlv *tv[][16], if (policy[i].type != t->type) continue; - if (policy[i].len && tlv_length(t) != policy[i].len) + if (policy[i].len && tlv_length(t) != policy[i].len) { + ieee1905_set_error(CMDU_STATUS_ERR_TLV_MALFORMED); return -1; + } if (policy[i].minlen > 0 && - tlv_length(t) < policy[i].minlen) - continue; + tlv_length(t) < policy[i].minlen) { + ieee1905_set_error(CMDU_STATUS_ERR_TLV_LEN_INSUFFICIENT); + return -1; + } if (policy[i].maxlen > 0 && - tlv_length(t) > policy[i].maxlen) - continue; + tlv_length(t) > policy[i].maxlen) { + ieee1905_set_error(CMDU_STATUS_ERR_TLV_LEN_OVERFLOW); + return -1; + } if (tlv_length(t) < tlv_minsize(t)) continue; if (tv[i][0]) { if (policy[i].present == TLV_PRESENT_ONE || - policy[i].present == TLV_PRESENT_OPTIONAL_ONE) + policy[i].present == TLV_PRESENT_OPTIONAL_ONE) { + ieee1905_set_error(CMDU_STATUS_ERR_TLV_NUM_MORE); return -1; + } } tv[i][idx[i]++] = t; @@ -734,16 +774,20 @@ int cmdu_parse_tlvs(struct cmdu_buff *c, struct tlv *tv[][16], int k = 0; while (k < len) { - if (c->data[c->datalen - len + k++] != 0) + if (c->data[c->datalen - len + k++] != 0) { + ieee1905_set_error(CMDU_STATUS_ERR_TLV_RESIDUE_DATA); return -1; + } } } /* strictly check against tlv policies */ for (i = 0; i < policy_len; i++) { if ((policy[i].present == TLV_PRESENT_ONE || - policy[i].present == TLV_PRESENT_MORE) && !tv[i][0]) + policy[i].present == TLV_PRESENT_MORE) && !tv[i][0]) { + ieee1905_set_error(CMDU_STATUS_ERR_TLV_NUM_LESS); return -1; + } } return 0; diff --git a/src/cmdu.h b/src/cmdu.h index 9dac85265d353baa1dc155a21ab717255ba87acb..9c970586122b098c069356fc1a9355a76ee799d4 100644 --- a/src/cmdu.h +++ b/src/cmdu.h @@ -241,6 +241,27 @@ int is_cmdu_type_response(uint16_t type); /** Function to check if a CMDU type must include atleast one TLV */ int is_cmdu_tlv_required(uint16_t type); +/** Parsing status of received CMDU */ +enum CMDU_STATUS { + CMDU_STATUS_OK, + CMDU_STATUS_ERR_TLV_MALFORMED, + CMDU_STATUS_ERR_TLV_NUM_LESS, /* mandatory tlv(s) absent */ + CMDU_STATUS_ERR_TLV_NUM_MORE, + CMDU_STATUS_ERR_TLV_NO_EOM, + CMDU_STATUS_ERR_TLV_RESIDUE_DATA, + CMDU_STATUS_ERR_TLV_LEN_INSUFFICIENT, + CMDU_STATUS_ERR_TLV_LEN_OVERFLOW, + CMDU_STATUS_ERR_MISC, + + IEEE1905_ERROR_MAXNUM, + IEEE1905_ERROR_LAST = IEEE1905_ERROR_MAXNUM - 1, +}; + + +extern int *ieee1905_get_errval(void); +#define ieee1905_error (*ieee1905_get_errval()) + +const char *ieee1905_strerror(int err); /** Parse a CMDU to get list of the TLVs present in it *