RE: [RFC] cfg80211: Implement Multiple BSSID capability in scanning
> Is a new version of this patch hinging only on this? We'd love to have a > fixed- > up one :-) The new version covers the use cases mentioned by Jouni as the OUIs of the vendor commands has the format of OUI + type + subtype. For other format of vendor commands, they will be treated as different vendor commands and are added in the new IE as well. Jouni, could you chime in to explain your view on this? Thanks, Peng
Re: [RFC] cfg80211: Implement Multiple BSSID capability in scanning
Hi, > As you pointed out the use cases for having vendor elements in MBSSID > subelements, what is > your suggestion to identify and process the vendor elements? Is a new version of this patch hinging only on this? We'd love to have a fixed-up one :-) johannes
RE: [RFC] cfg80211: Implement Multiple BSSID capability in scanning
> On Tue, Nov 14, 2017 at 02:39:31PM +, Peng Xu wrote: > > > I'm not even sure why this is necessary anyway though, do we really > > > think vendors will expect to be able to put vendor IEs inside the > > > subelements and override the ones outside? > > > > > > Is there even any point for the WFA ones? It seems WMM really ought > > > to be the same for all anyway, for example. > > > > I don't have any use case for such scenario. If vendor elements are > > unlikely to be present in subelement, this logic can be removed. > > As far as WMM element is concerned, I'd note that IEEE 802.11 standard does > not list EDCA Parameter Set element as one of the items that has to be same > for all the BSSs in a multiple BSSID set and as such, I'd consider it to be > allowed behavior for an AP to advertise different WMM parameters for > different nontransmitted BSSIDs. > > As far as other vendor specific elements are concerned, there could certainly > be use cases for using different values for WPA element, Hotspot 2.0 > element, MBO/OCE element. > Hi Jouni, As you pointed out the use cases for having vendor elements in MBSSID subelements, what is your suggestion to identify and process the vendor elements? Thanks, Peng
Re: [RFC] cfg80211: Implement Multiple BSSID capability in scanning
On Tue, Nov 14, 2017 at 02:39:31PM +, Peng Xu wrote: > > I'm not even sure why this is necessary anyway though, do we really think > > vendors will expect to be able to put vendor IEs inside the subelements and > > override the ones outside? > > > > Is there even any point for the WFA ones? It seems WMM really ought to be > > the same for all anyway, for example. > > I don't have any use case for such scenario. If vendor elements are unlikely > to > be present in subelement, this logic can be removed. As far as WMM element is concerned, I'd note that IEEE 802.11 standard does not list EDCA Parameter Set element as one of the items that has to be same for all the BSSs in a multiple BSSID set and as such, I'd consider it to be allowed behavior for an AP to advertise different WMM parameters for different nontransmitted BSSIDs. As far as other vendor specific elements are concerned, there could certainly be use cases for using different values for WPA element, Hotspot 2.0 element, MBO/OCE element. -- Jouni MalinenPGP id EFC895FA
RE: [RFC] cfg80211: Implement Multiple BSSID capability in scanning
> > Right, not really. > > I'm not even sure why this is necessary anyway though, do we really think > vendors will expect to be able to put vendor IEs inside the subelements and > override the ones outside? > > Is there even any point for the WFA ones? It seems WMM really ought to be > the same for all anyway, for example. > I don't have any use case for such scenario. If vendor elements are unlikely to be present in subelement, this logic can be removed. Thanks, Peng
Re: [RFC] cfg80211: Implement Multiple BSSID capability in scanning
> > > > This may be right for the WFA/Microsoft OUI, but not necessary anything > > else? > > > > Right, I only considered the most common cases since I did not find a > generic way to compare two vendor elements. Any suggestion? Right, not really. I'm not even sure why this is necessary anyway though, do we really think vendors will expect to be able to put vendor IEs inside the subelements and override the ones outside? Is there even any point for the WFA ones? It seems WMM really ought to be the same for all anyway, for example. johannes
RE: [RFC] cfg80211: Implement Multiple BSSID capability in scanning
> > > > It is OUI + type + subTye. > > Ah, right, type/subtype. > > Still, this is problematic, because there's nothing that says that the vendor > IE > must have OUI + type + subtype, the spec only says OUI + vendor specific > data. > > This may be right for the WFA/Microsoft OUI, but not necessary anything > else? > Right, I only considered the most common cases since I did not find a generic way to compare two vendor elements. Any suggestion? Thanks, Peng
Re: [RFC] cfg80211: Implement Multiple BSSID capability in scanning
On Tue, 2017-11-14 at 14:20 +, Peng Xu wrote: > > > > > + if (tmp_old[0] == WLAN_EID_VENDOR_SPECIFIC) { > > > + if (!memcmp(tmp_old + 2, tmp + 2, 5)) { > > > + /* same vendor ie, copy from new ie > > > > */ > > > + memcpy(pos, tmp, tmp[1] + 2); > > > + pos += tmp[1] + 2; > > > + } else { > > > + memcpy(pos, tmp_old, tmp_old[1] + > > > > 2); > > > + pos += tmp_old[1] + 2; > > > > This seems really strange. What's 5? Should it be 4, so you have > > OUI+subelement ID? > > > > It is OUI + type + subTye. Ah, right, type/subtype. Still, this is problematic, because there's nothing that says that the vendor IE must have OUI + type + subtype, the spec only says OUI + vendor specific data. This may be right for the WFA/Microsoft OUI, but not necessary anything else? johannes
RE: [RFC] cfg80211: Implement Multiple BSSID capability in scanning
> > > + if (tmp_old[0] == WLAN_EID_VENDOR_SPECIFIC) { > > + if (!memcmp(tmp_old + 2, tmp + 2, 5)) { > > + /* same vendor ie, copy from new ie > */ > > + memcpy(pos, tmp, tmp[1] + 2); > > + pos += tmp[1] + 2; > > + } else { > > + memcpy(pos, tmp_old, tmp_old[1] + > 2); > > + pos += tmp_old[1] + 2; > > This seems really strange. What's 5? Should it be 4, so you have > OUI+subelement ID? > It is OUI + type + subTye. Thanks, Peng
Re: [RFC] cfg80211: Implement Multiple BSSID capability in scanning
> + if (tmp_old[0] == WLAN_EID_VENDOR_SPECIFIC) { > + if (!memcmp(tmp_old + 2, tmp + 2, 5)) { > + /* same vendor ie, copy from new ie */ > + memcpy(pos, tmp, tmp[1] + 2); > + pos += tmp[1] + 2; > + } else { > + memcpy(pos, tmp_old, tmp_old[1] + 2); > + pos += tmp_old[1] + 2; This seems really strange. What's 5? Should it be 4, so you have OUI+subelement ID? johannes
Re: [RFC] cfg80211: Implement Multiple BSSID capability in scanning
Hi, Thanks for working on this. > +u8 *gen_new_bssid(const u8 *bssid, u8 max_bssid, u8 mbssid_index, gfp_t gfp) I looks like this should be static? I'm also pretty sure you leak the result, I guess you shouldn't allocate memory here. Just passing in a pointer to a buffer (that could be on the stack in the caller) would work fine, afaict. > +{ > + int i; > + u64 bssid_a, bssid_b, bssid_tmp = 0; > + u64 lsb_n; > + u8 *new_bssid; > + > + for (i = 0; i < 5; i++) { > + bssid_tmp = bssid_tmp | bssid[i]; > + bssid_tmp = bssid_tmp << 8; > + } ether_addr_to_u64() > + bssid_tmp = bssid_tmp | bssid[5]; > + > + lsb_n = bssid_tmp & ((1 << max_bssid) - 1); > + bssid_b = (lsb_n + mbssid_index) % (1 << max_bssid); > + bssid_a = bssid_tmp & ~((1 << max_bssid) - 1); > + bssid_tmp = bssid_a | bssid_b; This seems like a somewhat roundabout way of getting this, even if this is how the spec says it's done. How about just new_bssid = bssid_tmp; new_bssid &= ~((1 << max_bssid) - 1); new_bssid |= (lsb_n + mbssid_index) % (1 << max_bssid); > + new_bssid = kzalloc(6, gfp); > + if (!new_bssid) > + return NULL; don't allocate > + for (i = 0; i < 6; i++) { > + new_bssid[5 - i] = bssid_tmp & 0xFF; > + bssid_tmp >>= 8; > + } u64_to_ether_addr() Also, wouldn't it be better to handle both the index and list option from the Co-Located BSSID List subelement in the same function? > +size_t calculate_new_ie_len(const u8 *ie, size_t ielen, const u8 *subelement, > + size_t subie_len) static > +{ > + size_t new_ie_len; > + const u8 *old_ie, *new_ie; > + int delta; > + > + new_ie_len = ielen; > + > + /* calculate length difference between ssid ie */ > + old_ie = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen); > + new_ie = cfg80211_find_ie(WLAN_EID_SSID, subelement, subie_len); > + if (old_ie && new_ie) { > + delta = new_ie[1] - old_ie[1]; > + new_ie_len += delta; > + } No need for the delta variable. Also, this goes wrong if old_ie is missing but new_ie is present. Probably can't happen, but still. > + /* calculate length difference between FMS Descriptor ie */ > + old_ie = cfg80211_find_ie(WLAN_EID_FMS_DESCRIPTOR, ie, ielen); > + new_ie = cfg80211_find_ie(WLAN_EID_FMS_DESCRIPTOR, subelement, > + subie_len); > + if (!old_ie && new_ie) > + new_ie_len += new_ie[1]; > + else if (old_ie && new_ie) > + new_ie_len += (new_ie[1] - old_ie[1]); Technically that's missing teh old_ie && !new_ie case. Perhaps you should pull that out into a small separate function: new_ie_len += ie_len_delta(WLAN_EID_SSID, ie, ielen, subelement, subie_len); or so. > + /* calculate length difference for same vendor ie */ > + new_ie = cfg80211_find_ie(WLAN_EID_VENDOR_SPECIFIC, subelement, > + subie_len); > + while (new_ie && (new_ie - subelement) < subie_len) { > + old_ie = cfg80211_find_ie(WLAN_EID_VENDOR_SPECIFIC, ie, ielen); > + while (old_ie && ((old_ie - ie) < ielen)) { > + if (!memcmp(new_ie + 2, old_ie + 2, 5)) { > + /* same vendor ie, calculate length difference*/ > + new_ie_len += (new_ie[1] - old_ie[1]); > + break; > + } > + old_ie = cfg80211_find_ie( > + WLAN_EID_VENDOR_SPECIFIC, > + old_ie + old_ie[1] + 2, > + ielen - (old_ie + old_ie[1] + 2 - ie)); > + } > + new_ie = cfg80211_find_ie(WLAN_EID_VENDOR_SPECIFIC, > + new_ie + new_ie[1] + 2, > + subie_len - > + (new_ie + new_ie[1] + 2 - > + subelement)); > + } Perhaps that could be used here too, though I'm not really sure exactly what you're doing here. Can you add a comment pointing to where this logic is mentioned in the spec? > + /* check other ie in subelement */ > + new_ie = cfg80211_find_ie(WLAN_EID_NON_TX_BSSID_CAP, subelement, > + subie_len); > + while (new_ie && (new_ie - subelement < subie_len)) { > + if (new_ie[0] == WLAN_EID_NON_TX_BSSID_CAP || > + new_ie[0] == WLAN_EID_SSID || > + new_ie[0] == WLAN_EID_FMS_DESCRIPTOR || > + new_ie[0] == WLAN_EID_MULTI_BSSID_IDX) { > + if ((new_ie + 2 + new_ie[1] - subelement) == > + subie_len) { > + /* new_ie is the last ie */ > +
[RFC] cfg80211: Implement Multiple BSSID capability in scanning
From: Peng XuThis extends cfg80211 BSS table processing to be able to parse Multiple BSSID element from Beacon and Probe Response frames and to update the BSS profiles in internal database for non-transmitted BSSs. Signed-off-by: Peng Xu Signed-off-by: Jouni Malinen --- net/wireless/core.h | 1 + net/wireless/scan.c | 537 ++-- 2 files changed, 526 insertions(+), 12 deletions(-) diff --git a/net/wireless/core.h b/net/wireless/core.h index 35165f4..3b4a566 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -139,6 +139,7 @@ extern int cfg80211_rdev_list_generation; struct cfg80211_internal_bss { struct list_head list; struct list_head hidden_list; + struct list_head nontrans_list; struct rb_node rbn; u64 ts_boottime; unsigned long ts; diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 9f0901f..a9e3b31 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -149,6 +149,7 @@ static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev, } list_del_init(>list); + list_del_init(>nontrans_list); rb_erase(>rbn, >bss_tree); rdev->bss_entries--; WARN_ONCE((rdev->bss_entries == 0) ^ list_empty(>bss_list), @@ -1005,6 +1006,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev, memcpy(new, tmp, sizeof(*new)); new->refcount = 1; INIT_LIST_HEAD(>hidden_list); + INIT_LIST_HEAD(>nontrans_list); if (rcu_access_pointer(tmp->pub.proberesp_ies)) { hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN); @@ -1086,18 +1088,235 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen, return channel; } +u8 *gen_new_bssid(const u8 *bssid, u8 max_bssid, u8 mbssid_index, gfp_t gfp) +{ + int i; + u64 bssid_a, bssid_b, bssid_tmp = 0; + u64 lsb_n; + u8 *new_bssid; + + for (i = 0; i < 5; i++) { + bssid_tmp = bssid_tmp | bssid[i]; + bssid_tmp = bssid_tmp << 8; + } + bssid_tmp = bssid_tmp | bssid[5]; + + lsb_n = bssid_tmp & ((1 << max_bssid) - 1); + bssid_b = (lsb_n + mbssid_index) % (1 << max_bssid); + bssid_a = bssid_tmp & ~((1 << max_bssid) - 1); + bssid_tmp = bssid_a | bssid_b; + + new_bssid = kzalloc(6, gfp); + if (!new_bssid) + return NULL; + for (i = 0; i < 6; i++) { + new_bssid[5 - i] = bssid_tmp & 0xFF; + bssid_tmp >>= 8; + } + + return new_bssid; +} + +size_t calculate_new_ie_len(const u8 *ie, size_t ielen, const u8 *subelement, + size_t subie_len) +{ + size_t new_ie_len; + const u8 *old_ie, *new_ie; + int delta; + + new_ie_len = ielen; + + /* calculate length difference between ssid ie */ + old_ie = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen); + new_ie = cfg80211_find_ie(WLAN_EID_SSID, subelement, subie_len); + if (old_ie && new_ie) { + delta = new_ie[1] - old_ie[1]; + new_ie_len += delta; + } + + /* calculate length difference between FMS Descriptor ie */ + old_ie = cfg80211_find_ie(WLAN_EID_FMS_DESCRIPTOR, ie, ielen); + new_ie = cfg80211_find_ie(WLAN_EID_FMS_DESCRIPTOR, subelement, + subie_len); + if (!old_ie && new_ie) + new_ie_len += new_ie[1]; + else if (old_ie && new_ie) + new_ie_len += (new_ie[1] - old_ie[1]); + + /* calculate length difference for same vendor ie */ + new_ie = cfg80211_find_ie(WLAN_EID_VENDOR_SPECIFIC, subelement, + subie_len); + while (new_ie && (new_ie - subelement) < subie_len) { + old_ie = cfg80211_find_ie(WLAN_EID_VENDOR_SPECIFIC, ie, ielen); + while (old_ie && ((old_ie - ie) < ielen)) { + if (!memcmp(new_ie + 2, old_ie + 2, 5)) { + /* same vendor ie, calculate length difference*/ + new_ie_len += (new_ie[1] - old_ie[1]); + break; + } + old_ie = cfg80211_find_ie( + WLAN_EID_VENDOR_SPECIFIC, + old_ie + old_ie[1] + 2, + ielen - (old_ie + old_ie[1] + 2 - ie)); + } + new_ie = cfg80211_find_ie(WLAN_EID_VENDOR_SPECIFIC, + new_ie + new_ie[1] + 2, + subie_len - + (new_ie + new_ie[1] + 2 - + subelement)); + } + + /*