diff --git a/umac/cmn_services/cmn_defs/inc/wlan_cmn_ieee80211.h b/umac/cmn_services/cmn_defs/inc/wlan_cmn_ieee80211.h index 1ac237721c67..708c13dc4d7b 100644 --- a/umac/cmn_services/cmn_defs/inc/wlan_cmn_ieee80211.h +++ b/umac/cmn_services/cmn_defs/inc/wlan_cmn_ieee80211.h @@ -121,6 +121,7 @@ #define WLAN_IBSS_IE_MAX_LEN 2 #define WLAN_REQUEST_IE_MAX_LEN 255 #define WLAN_RM_CAPABILITY_IE_MAX_LEN 5 +#define WLAN_RNR_IE_MIN_LEN 5 /* HT capability flags */ #define WLAN_HTCAP_C_ADVCODING 0x0001 @@ -392,6 +393,7 @@ enum element_ie { WLAN_ELEMID_AID = 197, WLAN_ELEMID_QUIET_CHANNEL = 198, WLAN_ELEMID_OP_MODE_NOTIFY = 199, + WLAN_ELEMID_REDUCED_NEIGHBOR_REPORT = 201, WLAN_ELEMID_VENDOR = 221, WLAN_ELEMID_FILS_INDICATION = 240, WLAN_ELEMID_EXTN_ELEM = 255, diff --git a/umac/scan/dispatcher/inc/wlan_scan_public_structs.h b/umac/scan/dispatcher/inc/wlan_scan_public_structs.h index 74672ad34b5a..0dbc83b02fdf 100644 --- a/umac/scan/dispatcher/inc/wlan_scan_public_structs.h +++ b/umac/scan/dispatcher/inc/wlan_scan_public_structs.h @@ -35,6 +35,7 @@ typedef uint32_t wlan_scan_id; #define WLAN_SCAN_MAX_NUM_SSID 16 #define WLAN_SCAN_MAX_NUM_BSSID 4 +#define MAX_RNR_BSS 5 #define SCM_CANCEL_SCAN_WAIT_TIME 50 #define SCM_CANCEL_SCAN_WAIT_ITERATION 600 @@ -154,6 +155,7 @@ struct element_info { * @fils_indication: pointer to FILS indication ie * @esp: pointer to ESP indication ie * @mbo_oce: pointer to mbo/oce indication ie + * @rnrie: reduced neighbor report IE * @adaptive_11r: pointer to adaptive 11r IE */ struct ie_list { @@ -203,6 +205,7 @@ struct ie_list { uint8_t *esp; uint8_t *mbo_oce; uint8_t *muedca; + uint8_t *rnrie; uint8_t *extender; uint8_t *adaptive_11r; }; @@ -278,6 +281,82 @@ struct scan_mbssid_info { uint8_t trans_bssid[QDF_MAC_ADDR_SIZE]; }; +/** + * struct rnr_bss_info - Reduced Neighbor Report BSS information + * @neighbor_ap_tbtt_offset: Neighbor AP TBTT offset + * @channel_number: channel number + * @operating_class: operting class + * @bssid: BSS MAC address + * @short_ssid: short ssid + * @bss_params: BSS parameters + */ +struct rnr_bss_info { + uint8_t neighbor_ap_tbtt_offset; + uint32_t channel_number; + uint32_t operating_class; + struct qdf_mac_addr bssid; + uint32_t short_ssid; + uint8_t bss_params; +}; + +/** + * struct tbtt_information_header - TBTT information header + * @tbbt_info_fieldtype: TBTT information field type + * @filter_neighbor_ap: filtered neighbor ap + * @tbbt_info_count: TBTT information count + * @tbtt_info_length: TBTT informaiton length + */ +struct tbtt_information_header { + uint16_t tbbt_info_fieldtype:2; + uint16_t filtered_neighbor_ap:1; + uint16_t reserved:1; + uint16_t tbtt_info_count:4; + uint16_t tbtt_info_length:8; +}; + +/** + * struct neighbor_ap_info_field - Neighbor information field + * @tbtt_info_header: TBTT information header + * @operting_class: operating class + * @channel_number: channel number + */ +struct neighbor_ap_info_field { + struct tbtt_information_header tbtt_header; + uint8_t operting_class; + uint8_t channel_number; +}; + +/** + * enum tbtt_information_field - TBTT information field + * @TBTT_NEIGHBOR_AP_OFFSET_ONLY: TBTT information field type + * @TBTT_NEIGHBOR_AP_BSS_PARAM: neighbor AP and bss param + * @TBTT_NEIGHBOR_AP_SHORTSSID: neighbor AP and Short ssid + * @TBTT_NEIGHBOR_AP_S_SSID_BSS_PARAM: neighbor AP, short ssid and bss param + * @TBTT_NEIGHBOR_AP_BSSID: neighbor AP and bssid + * @TBTT_NEIGHBOR_AP_BSSID_BSS_PARAM: neighbor AP, bssid and bss param + * @TBTT_NEIGHBOR_AP_BSSSID_S_SSID: neighbor AP, bssid and short ssid + * @TBTT_NEIGHBOR_AP_BSSID_S_SSID_BSS_PARAM: neighbor AP, bssid, short ssid + * and bss params + */ +enum tbtt_information_field { + TBTT_NEIGHBOR_AP_OFFSET_ONLY = 1, + TBTT_NEIGHBOR_AP_BSS_PARAM = 2, + TBTT_NEIGHBOR_AP_SHORTSSID = 5, + TBTT_NEIGHBOR_AP_S_SSID_BSS_PARAM = 6, + TBTT_NEIGHBOR_AP_BSSID = 7, + TBTT_NEIGHBOR_AP_BSSID_BSS_PARAM = 8, + TBTT_NEIGHBOR_AP_BSSSID_S_SSID = 11, + TBTT_NEIGHBOR_AP_BSSID_S_SSID_BSS_PARAM = 12 +}; + +/** + * struct reduced_neighbor_report - Reduced Neighbor Report + * @bss_info: RNR BSS Information + */ +struct reduced_neighbor_report { + struct rnr_bss_info bss_info[MAX_RNR_BSS]; +}; + /** * struct scan_cache_entry: structure containing scan entry * @frm_subtype: updated from beacon/probe @@ -306,6 +385,7 @@ struct scan_mbssid_info { * @hidden_ssid_timestamp: boottime in microsec when hidden * ssid was received * @mbssid_info: Multi bssid information + * @rnr: Reduced neighbor report information * @channel: channel info on which AP is present * @channel_mismatch: if channel received in metadata * doesnot match the one in beacon @@ -350,6 +430,7 @@ struct scan_cache_entry { qdf_time_t rssi_timestamp; qdf_time_t hidden_ssid_timestamp; struct scan_mbssid_info mbssid_info; + struct reduced_neighbor_report rnr; struct channel_info channel; bool channel_mismatch; struct mlme_info mlme_info; diff --git a/umac/scan/dispatcher/src/wlan_scan_utils_api.c b/umac/scan/dispatcher/src/wlan_scan_utils_api.c index e7a8ce1c1c30..034237dd249b 100644 --- a/umac/scan/dispatcher/src/wlan_scan_utils_api.c +++ b/umac/scan/dispatcher/src/wlan_scan_utils_api.c @@ -28,6 +28,9 @@ #include #define MAX_IE_LEN 1024 +#define SHORT_SSID_LEN 4 +#define NEIGHBOR_AP_LEN 1 +#define BSS_PARAMS_LEN 1 const char* util_scan_get_ev_type_name(enum scan_event_type type) @@ -559,6 +562,116 @@ util_scan_is_hidden_ssid(struct ie_ssid *ssid) return true; } +static QDF_STATUS +util_scan_update_rnr(struct rnr_bss_info *rnr, + struct neighbor_ap_info_field *ap_info, + uint8_t **data) +{ + uint16_t fieldtype; + uint8_t *tmp = *data; + + fieldtype = ap_info->tbtt_header.tbbt_info_fieldtype; + + switch (fieldtype) { + case TBTT_NEIGHBOR_AP_OFFSET_ONLY: + /* Dont store it skip*/ + *data = tmp + NEIGHBOR_AP_LEN; + break; + + case TBTT_NEIGHBOR_AP_BSS_PARAM: + /* Dont store it skip*/ + break; + + case TBTT_NEIGHBOR_AP_SHORTSSID: + rnr->channel_number = ap_info->channel_number; + rnr->operating_class = ap_info->operting_class; + qdf_mem_copy(&rnr->short_ssid, &tmp[1], SHORT_SSID_LEN); + *data = tmp + NEIGHBOR_AP_LEN + SHORT_SSID_LEN; + break; + + case TBTT_NEIGHBOR_AP_S_SSID_BSS_PARAM: + rnr->channel_number = ap_info->channel_number; + rnr->operating_class = ap_info->operting_class; + qdf_mem_copy(&rnr->short_ssid, &tmp[1], SHORT_SSID_LEN); + rnr->bss_params = tmp[5]; + *data = tmp + NEIGHBOR_AP_LEN + SHORT_SSID_LEN + BSS_PARAMS_LEN; + break; + + case TBTT_NEIGHBOR_AP_BSSID: + rnr->channel_number = ap_info->channel_number; + rnr->operating_class = ap_info->operting_class; + qdf_mem_copy(&rnr->bssid, &tmp[1], QDF_MAC_ADDR_SIZE); + *data = tmp + NEIGHBOR_AP_LEN + QDF_MAC_ADDR_SIZE; + break; + + case TBTT_NEIGHBOR_AP_BSSID_BSS_PARAM: + rnr->channel_number = ap_info->channel_number; + rnr->operating_class = ap_info->operting_class; + qdf_mem_copy(&rnr->bssid, &tmp[1], QDF_MAC_ADDR_SIZE); + rnr->bss_params = tmp[7]; + *data = tmp + NEIGHBOR_AP_LEN + QDF_MAC_ADDR_SIZE + + BSS_PARAMS_LEN; + break; + + case TBTT_NEIGHBOR_AP_BSSSID_S_SSID: + rnr->channel_number = ap_info->channel_number; + rnr->operating_class = ap_info->operting_class; + qdf_mem_copy(&rnr->bssid, &tmp[1], QDF_MAC_ADDR_SIZE); + qdf_mem_copy(&rnr->short_ssid, &tmp[7], SHORT_SSID_LEN); + *data = tmp + NEIGHBOR_AP_LEN + QDF_MAC_ADDR_SIZE + + SHORT_SSID_LEN; + break; + + case TBTT_NEIGHBOR_AP_BSSID_S_SSID_BSS_PARAM: + rnr->channel_number = ap_info->channel_number; + rnr->operating_class = ap_info->operting_class; + qdf_mem_copy(&rnr->bssid, &tmp[1], QDF_MAC_ADDR_SIZE); + qdf_mem_copy(&rnr->short_ssid, &tmp[7], SHORT_SSID_LEN); + rnr->bss_params = tmp[11]; + *data = tmp + NEIGHBOR_AP_LEN + QDF_MAC_ADDR_SIZE + + SHORT_SSID_LEN + BSS_PARAMS_LEN; + break; + + default: + scm_debug("Wrong fieldtype"); + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +util_scan_parse_rnr_ie(struct scan_cache_entry *scan_entry, + struct ie_header *ie) +{ + uint32_t rnr_ie_len; + uint16_t tbtt_count, tbtt_length, i, fieldtype; + uint8_t *data; + struct neighbor_ap_info_field *neighbor_ap_info; + + rnr_ie_len = ie->ie_len; + data = (uint8_t *)ie + sizeof(struct ie_header); + + while (data < (uint8_t *)ie + rnr_ie_len + 2) { + neighbor_ap_info = (struct neighbor_ap_info_field *)data; + tbtt_count = neighbor_ap_info->tbtt_header.tbtt_info_count; + tbtt_length = neighbor_ap_info->tbtt_header.tbtt_info_length; + fieldtype = neighbor_ap_info->tbtt_header.tbbt_info_fieldtype; + scm_debug("channel number %d, op class %d", + neighbor_ap_info->channel_number, + neighbor_ap_info->operting_class); + scm_debug("tbtt_count %d, tbtt_length %d, fieldtype %d", + tbtt_count, tbtt_length, fieldtype); + for (i = 0; i < tbtt_count && i < MAX_RNR_BSS; i++) { + data = data + sizeof(struct neighbor_ap_info_field); + util_scan_update_rnr(&scan_entry->rnr.bss_info[i], + neighbor_ap_info, + &data); + } + } + + return QDF_STATUS_SUCCESS; +} + static QDF_STATUS util_scan_parse_extn_ie(struct scan_cache_entry *scan_params, struct ie_header *ie) @@ -877,6 +990,14 @@ util_scan_populate_bcn_ie_list(struct scan_cache_entry *scan_params, if (QDF_IS_STATUS_ERROR(status)) goto err_status; break; + case WLAN_ELEMID_REDUCED_NEIGHBOR_REPORT: + if (ie->ie_len < WLAN_RNR_IE_MIN_LEN) + goto err; + scan_params->ie_list.rnrie = (uint8_t *)ie; + status = util_scan_parse_rnr_ie(scan_params, ie); + if (QDF_IS_STATUS_ERROR(status)) + goto err_status; + break; default: break; }