wifi: cfg80211: search all RNR elements for colocated APs
authorBenjamin Berg <benjamin.berg@intel.com>
Sun, 18 Jun 2023 18:50:01 +0000 (21:50 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 19 Jun 2023 11:12:44 +0000 (13:12 +0200)
An AP reporting colocated APs may send more than one reduced neighbor
report element. As such, iterate all elements instead of only parsing
the first one when looking for colocated APs.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230618214436.ffe2c014f478.I372a4f96c88f7ea28ac39e94e0abfc465b5330d4@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/wireless/scan.c

index 9167169..ede95ca 100644 (file)
@@ -643,90 +643,89 @@ static int cfg80211_parse_colocated_ap(const struct cfg80211_bss_ies *ies,
        int n_coloc = 0, ret;
        LIST_HEAD(ap_list);
 
-       elem = cfg80211_find_elem(WLAN_EID_REDUCED_NEIGHBOR_REPORT, ies->data,
-                                 ies->len);
-       if (!elem)
-               return 0;
-
-       pos = elem->data;
-       end = pos + elem->datalen;
-
        ret = cfg80211_calc_short_ssid(ies, &ssid_elem, &s_ssid_tmp);
        if (ret)
                return ret;
 
-       /* RNR IE may contain more than one NEIGHBOR_AP_INFO */
-       while (pos + sizeof(*ap_info) <= end) {
-               enum nl80211_band band;
-               int freq;
-               u8 length, i, count;
+       for_each_element_id(elem, WLAN_EID_REDUCED_NEIGHBOR_REPORT,
+                           ies->data, ies->len) {
+               pos = elem->data;
+               end = elem->data + elem->datalen;
 
-               ap_info = (void *)pos;
-               count = u8_get_bits(ap_info->tbtt_info_hdr,
-                                   IEEE80211_AP_INFO_TBTT_HDR_COUNT) + 1;
-               length = ap_info->tbtt_info_len;
+               /* RNR IE may contain more than one NEIGHBOR_AP_INFO */
+               while (pos + sizeof(*ap_info) <= end) {
+                       enum nl80211_band band;
+                       int freq;
+                       u8 length, i, count;
 
-               pos += sizeof(*ap_info);
+                       ap_info = (void *)pos;
+                       count = u8_get_bits(ap_info->tbtt_info_hdr,
+                                           IEEE80211_AP_INFO_TBTT_HDR_COUNT) + 1;
+                       length = ap_info->tbtt_info_len;
 
-               if (!ieee80211_operating_class_to_band(ap_info->op_class,
-                                                      &band))
-                       break;
+                       pos += sizeof(*ap_info);
 
-               freq = ieee80211_channel_to_frequency(ap_info->channel, band);
+                       if (!ieee80211_operating_class_to_band(ap_info->op_class,
+                                                              &band))
+                               break;
 
-               if (end - pos < count * length)
-                       break;
+                       freq = ieee80211_channel_to_frequency(ap_info->channel,
+                                                             band);
 
-               if (u8_get_bits(ap_info->tbtt_info_hdr,
-                               IEEE80211_AP_INFO_TBTT_HDR_TYPE) !=
-                   IEEE80211_TBTT_INFO_TYPE_TBTT) {
-                       pos += count * length;
-                       continue;
-               }
+                       if (end - pos < count * length)
+                               break;
 
-               /*
-                * TBTT info must include bss param + BSSID +
-                * (short SSID or same_ssid bit to be set).
-                * ignore other options, and move to the
-                * next AP info
-                */
-               if (band != NL80211_BAND_6GHZ ||
-                   !(length == offsetofend(struct ieee80211_tbtt_info_7_8_9,
-                                           bss_params) ||
-                     length == sizeof(struct ieee80211_tbtt_info_7_8_9) ||
-                     length >= offsetofend(struct ieee80211_tbtt_info_ge_11,
-                                           bss_params))) {
-                       pos += count * length;
-                       continue;
-               }
+                       if (u8_get_bits(ap_info->tbtt_info_hdr,
+                                       IEEE80211_AP_INFO_TBTT_HDR_TYPE) !=
+                           IEEE80211_TBTT_INFO_TYPE_TBTT) {
+                               pos += count * length;
+                               continue;
+                       }
 
-               for (i = 0; i < count; i++) {
-                       struct cfg80211_colocated_ap *entry;
+                       /* TBTT info must include bss param + BSSID +
+                        * (short SSID or same_ssid bit to be set).
+                        * ignore other options, and move to the
+                        * next AP info
+                        */
+                       if (band != NL80211_BAND_6GHZ ||
+                           !(length == offsetofend(struct ieee80211_tbtt_info_7_8_9,
+                                                   bss_params) ||
+                             length == sizeof(struct ieee80211_tbtt_info_7_8_9) ||
+                             length >= offsetofend(struct ieee80211_tbtt_info_ge_11,
+                                                   bss_params))) {
+                               pos += count * length;
+                               continue;
+                       }
 
-                       entry = kzalloc(sizeof(*entry) + IEEE80211_MAX_SSID_LEN,
-                                       GFP_ATOMIC);
+                       for (i = 0; i < count; i++) {
+                               struct cfg80211_colocated_ap *entry;
 
-                       if (!entry)
-                               goto error;
+                               entry = kzalloc(sizeof(*entry) + IEEE80211_MAX_SSID_LEN,
+                                               GFP_ATOMIC);
 
-                       entry->center_freq = freq;
+                               if (!entry)
+                                       goto error;
 
-                       if (!cfg80211_parse_ap_info(entry, pos, length,
-                                                   ssid_elem, s_ssid_tmp)) {
-                               n_coloc++;
-                               list_add_tail(&entry->list, &ap_list);
-                       } else {
-                               kfree(entry);
-                       }
+                               entry->center_freq = freq;
+
+                               if (!cfg80211_parse_ap_info(entry, pos, length,
+                                                           ssid_elem,
+                                                           s_ssid_tmp)) {
+                                       n_coloc++;
+                                       list_add_tail(&entry->list, &ap_list);
+                               } else {
+                                       kfree(entry);
+                               }
 
-                       pos += length;
+                               pos += length;
+                       }
                }
-       }
 
 error:
-       if (pos != end) {
-               cfg80211_free_coloc_ap_list(&ap_list);
-               return 0;
+               if (pos != end) {
+                       cfg80211_free_coloc_ap_list(&ap_list);
+                       return 0;
+               }
        }
 
        list_splice_tail(&ap_list, list);