Commit 5461707a authored by Benjamin Berg's avatar Benjamin Berg Committed by Johannes Berg

wifi: cfg80211: search all RNR elements for colocated APs

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: default avatarBenjamin Berg <benjamin.berg@intel.com>
Signed-off-by: default avatarGregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230618214436.ffe2c014f478.I372a4f96c88f7ea28ac39e94e0abfc465b5330d4@changeidSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 8dcc91c4
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment