diff --git a/src/cmdu_validate.c b/src/cmdu_validate.c index 2fb70d2bc2faa4788de6b6ce7ce98f14b06dfeac..4aff49a2e51e00891b5a98d282975f93e0af8d55 100644 --- a/src/cmdu_validate.c +++ b/src/cmdu_validate.c @@ -143,6 +143,228 @@ static int check_searched_service_tlv(struct tlv *t) return check_service_tlv(t); } +/* Check AP Metrics TLV */ +static int check_ap_metrics_tlv(struct tlv *t) +{ + uint16_t tlv_len = 0; + struct tlv_ap_metrics *tlv; + int offset = 0; + + tlv_len = tlv_length(t); + if (!tlv_len) + return -1; + + tlv = (struct tlv_ap_metrics *) t->data; + if (!tlv) + return -1; + + /* bssid(6), channel_utilization(1), num_station(1), esp_ac(1), esp_be(3) */ + if (offset + sizeof(*tlv) > tlv_len) + return -1; + + offset += sizeof(*tlv); + + /* esp_be */ + if (!(tlv->esp_ac & ESP_AC_BE)) + return -1; + + /* esp[] */ + if (tlv->esp_ac & ESP_AC_BK) + offset += 3; + if (tlv->esp_ac & ESP_AC_VO) + offset += 3; + if (tlv->esp_ac & ESP_AC_VI) + offset += 3; + + if (offset > tlv_len) + return -1; + + return 0; +} + +/* Check Associated STA Traffic Stats TLV */ +static int check_assoc_sta_traffic_stats_tlv(struct tlv *t) +{ + return check_serialized_tlv(t, + sizeof(struct tlv_assoc_sta_traffic_stats)); +} + +/* Check Associated STA Link Metrics TLV */ +static int check_assoc_sta_link_metrics_tlv(struct tlv *tlv) +{ + int offset = 0; + uint8_t num_bss; + uint8_t *tv_data; + uint16_t tlv_len; + + if (!tlv) + return -1; + + tlv_len = tlv_length(tlv); + if (tlv_len < sizeof(struct tlv_assoc_sta_link_metrics)) + return -1; + + tv_data = (uint8_t *)tlv->data; + if (!tv_data) + return -1; + + offset += 6; /* bssid */ + num_bss = tv_data[offset++]; + + if (offset + num_bss * sizeof(struct assoc_sta_link_metrics_bss) > tlv_len) + return -1; + + return 0; +} + +/* Check AP Extended Metrics TLV */ +static int check_ap_ext_metrics_tlv(struct tlv *t) +{ + return check_serialized_tlv(t, + sizeof(struct tlv_ap_ext_metrics)); +} + +/* Check Radio Metrics TLV */ +static int check_radio_metrics_tlv(struct tlv *t) +{ + return check_serialized_tlv(t, + sizeof(struct tlv_radio_metrics)); +} + +/* Check Associated STA Extended Link Metrics TLV */ +static int check_assoc_sta_ext_link_metrics_tlv(struct tlv *tlv) +{ + int offset = 0; + uint8_t num_bss; + uint8_t *tv_data; + uint16_t tlv_len; + + if (!tlv) + return -1; + + tlv_len = tlv_length(tlv); + if (tlv_len < sizeof(struct tlv_sta_ext_link_metric)) + return -1; + + tv_data = (uint8_t *)tlv->data; + if (!tv_data) + return -1; + + offset += 6; /* bssid */ + num_bss = tv_data[offset++]; + + if (offset + num_bss * sizeof(struct sta_ext_link_metric_bss) > tlv_len) + return -1; + + return 0; +} + +bool validate_ap_metrics_response(struct cmdu_buff *cmdu, struct tlv *tv[][16]) +{ + int ret = 0; + int idx; + struct tlv_policy metric_policy[] = { + [0] = { + .type = MAP_TLV_AP_METRICS, + .present = TLV_PRESENT_MORE, + .minlen = 13 + }, + [1] = { + .type = MAP_TLV_ASSOCIATED_STA_TRAFFIC_STATS, + .present = TLV_PRESENT_OPTIONAL_MORE, + .minlen = 34, + .maxlen = 34 + }, + [2] = { + .type = MAP_TLV_ASSOCIATED_STA_LINK_METRICS, + .present = TLV_PRESENT_OPTIONAL_MORE, + .minlen = 7 + }, + [3] = { + .type = MAP_TLV_AP_EXTENDED_METRICS, + .present = TLV_PRESENT_MORE, + .minlen = 30, + .maxlen = 30 + }, + [4] = { + .type = MAP_TLV_RADIO_METRICS, + .present = TLV_PRESENT_OPTIONAL_MORE, + .minlen = 10, + .maxlen = 10 + }, + [5] = { + .type = MAP_TLV_ASSOCIATED_STA_EXT_LINK_METRICS, + .present = TLV_PRESENT_OPTIONAL_MORE, + .minlen = 7 + } + }; + + trace("%s |" MACFMT "|CMDU: ap metrics response\n", + __func__, MAC2STR(cmdu->origin)); + + /* Parsing AP Metrics TLV */ + ret = cmdu_parse_tlvs(cmdu, tv, metric_policy, 6); + if (ret) { + dbg("%s: parse_tlv failed\n", __func__); + return false; + } + + if (!tv[0][0] || !tv[3][0]) { + dbg("%s: Missing one or more mandatory TLV!\n", __func__); + return false; + } + + idx = 0; + while (tv[0][idx]) { + /* Parse AP Metrics TLV */ + if (check_ap_metrics_tlv(tv[0][idx])) + return false; + idx++; + } + + idx = 0; + while (tv[1][idx]) { + /* Parse Associated STA Traffic Stats TLV */ + if (check_assoc_sta_traffic_stats_tlv(tv[1][idx])) + return false; + idx++; + } + + idx = 0; + while (tv[2][idx]) { + /* Parse Associated STA Link Metrics TLV */ + if (check_assoc_sta_link_metrics_tlv(tv[2][idx])) + return false; + idx++; + } + + idx = 0; + while (tv[3][idx]) { + /* Parse AP Extended Metrics TLV */ + if (check_ap_ext_metrics_tlv(tv[3][idx])) + return false; + idx++; + } + + idx = 0; + while (tv[4][idx]) { + /* Parse Radio Metrics TLV */ + if (check_radio_metrics_tlv(tv[4][idx])) + return false; + idx++; + } + + idx = 0; + while (tv[5][idx]) { + /* Parse Associated STA Extended Link Metrics TLV */ + if (check_assoc_sta_ext_link_metrics_tlv(tv[5][idx])) + return false; + idx++; + } + + return true; +} + bool validate_channel_scan_report(struct cmdu_buff *cmdu, struct tlv *tv_tsp[][16], struct tlv *tv_scan[], int *num) { @@ -811,7 +1033,7 @@ bool validate_ap_autoconfig_response(struct cmdu_buff *cmdu, struct tlv *tv[][16 if (check_map_profile_tlv(tv[2][0])) return false; - /* Parse SupportedFreqBand TLV */ + /* Parse SupportedFreqBand TLV */ if (check_supported_band_tlv(tv[3][0])) return false; diff --git a/src/cmdu_validate.h b/src/cmdu_validate.h index d173b6da23adc01da9ce8db44fabe4cd31cd22f4..509407a7184c25c9cf19fc0e8c1cab971768072e 100644 --- a/src/cmdu_validate.h +++ b/src/cmdu_validate.h @@ -3,6 +3,7 @@ #ifndef CMDU_VALIDATE #define CMDU_VALIDATE +bool validate_ap_metrics_response(struct cmdu_buff *cmdu, struct tlv *tv[][16]); bool validate_channel_scan_report(struct cmdu_buff *cmdu, struct tlv *tv_tsp[][16], struct tlv *tv_scan[], int *num); bool validate_topology_response(struct cmdu_buff *cmdu, struct tlv *tv_tsp[][16]); diff --git a/src/cntlr_map.c b/src/cntlr_map.c index dfc8a39d942cb51d8900f2f5a0142cf48e8600a1..cfccce0d87b326831b0836bfca253913c195827a 100644 --- a/src/cntlr_map.c +++ b/src/cntlr_map.c @@ -1128,14 +1128,6 @@ int handle_ap_metrics_response(void *cntlr, struct cmdu_buff *cmdu) struct wifi_bss_element *b; //struct link_metrics *link; struct tlv *tv[6][16] = { 0 }; - struct tlv_policy metric_policy[] = { - [0] = { .type = MAP_TLV_AP_METRICS, .present = TLV_PRESENT_MORE }, - [1] = { .type = MAP_TLV_ASSOCIATED_STA_TRAFFIC_STATS, .present = TLV_PRESENT_OPTIONAL_MORE }, - [2] = { .type = MAP_TLV_ASSOCIATED_STA_LINK_METRICS, .present = TLV_PRESENT_OPTIONAL_MORE }, - [3] = { .type = MAP_TLV_AP_EXTENDED_METRICS, .present = TLV_PRESENT_MORE }, - [4] = { .type = MAP_TLV_RADIO_METRICS, .present = TLV_PRESENT_OPTIONAL_MORE }, - [5] = { .type = MAP_TLV_ASSOCIATED_STA_EXT_LINK_METRICS, .present = TLV_PRESENT_OPTIONAL_MORE } - }; struct tlv_ap_metrics *p; if (!cmdu) { @@ -1145,10 +1137,10 @@ int handle_ap_metrics_response(void *cntlr, struct cmdu_buff *cmdu) trace("Storing AP metrics of |" MACFMT "|\n", MAC2STR(cmdu->origin)); - /* TODO: validate frame */ - - /* Parsing AP Metrics TLV */ - cmdu_parse_tlvs(cmdu, tv, metric_policy, 6); + if (!validate_ap_metrics_response(cmdu, tv)) { + dbg("cmdu validation: [AP_METRICS_RESPONSE] failed\n"); + return -1; + } /* Storing AP Metrics TLV */ idx = 0;