From patchwork Tue Aug 28 12:13:48 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johannes Berg X-Patchwork-Id: 10578347 X-Patchwork-Delegate: johannes@sipsolutions.net Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 03C1F14BD for ; Tue, 28 Aug 2018 12:19:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E550A29F01 for ; Tue, 28 Aug 2018 12:19:49 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D7F7429F13; Tue, 28 Aug 2018 12:19:49 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A233C29F01 for ; Tue, 28 Aug 2018 12:19:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727468AbeH1QLK (ORCPT ); Tue, 28 Aug 2018 12:11:10 -0400 Received: from s3.sipsolutions.net ([144.76.43.62]:53014 "EHLO sipsolutions.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727162AbeH1QLK (ORCPT ); Tue, 28 Aug 2018 12:11:10 -0400 Received: by sipsolutions.net with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.91) (envelope-from ) id 1fucsm-00018J-1I; Tue, 28 Aug 2018 14:14:04 +0200 From: Johannes Berg To: linux-wireless@vger.kernel.org Cc: Jouni Malinen , Peng Xu Subject: [RFC 1/6] cfg80211: Implement Multiple BSSID capability in scanning Date: Tue, 28 Aug 2018 14:13:48 +0200 Message-Id: <20180828121353.11193-2-johannes@sipsolutions.net> X-Mailer: git-send-email 2.14.4 In-Reply-To: <20180828121353.11193-1-johannes@sipsolutions.net> References: <20180828121353.11193-1-johannes@sipsolutions.net> Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Peng Xu This 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 Signed-off-by: Sara Sharon Signed-off-by: Johannes Berg --- backport-include/linux/etherdevice.h | 23 ++ intc-scripts/chromeOS/hdrs/mac80211-bp.h | 23 ++ net/wireless/core.h | 1 + net/wireless/scan.c | 449 +++++++++++++++++++++++++++++-- 4 files changed, 481 insertions(+), 15 deletions(-) diff --git a/backport-include/linux/etherdevice.h b/backport-include/linux/etherdevice.h index 92256e005169..0b96cc16e96e 100644 --- a/backport-include/linux/etherdevice.h +++ b/backport-include/linux/etherdevice.h @@ -193,4 +193,27 @@ static inline int eth_skb_pad(struct sk_buff *skb) } #endif /* LINUX_VERSION_IS_LESS(3,19,0) */ +#if LINUX_VERSION_IS_LESS(4,11,0) +static inline u64 ether_addr_to_u64(const u8 *addr) +{ + u64 u = 0; + int i; + + for (i = 0; i < ETH_ALEN; i++) + u = u << 8 | addr[i]; + + return u; +} + +static inline void u64_to_ether_addr(u64 u, u8 *addr) +{ + int i; + + for (i = ETH_ALEN - 1; i >= 0; i--) { + addr[i] = u & 0xff; + u = u >> 8; + } +} +#endif /* LINUX_VERSION_IS_LESS(4,11,0) */ + #endif /* _BACKPORT_LINUX_ETHERDEVICE_H */ diff --git a/intc-scripts/chromeOS/hdrs/mac80211-bp.h b/intc-scripts/chromeOS/hdrs/mac80211-bp.h index 31f28bd60ae4..99abc01eacee 100644 --- a/intc-scripts/chromeOS/hdrs/mac80211-bp.h +++ b/intc-scripts/chromeOS/hdrs/mac80211-bp.h @@ -243,3 +243,26 @@ static inline void timer_setup(struct timer_list *timer, #define from_timer(var, callback_timer, timer_fieldname) \ container_of(callback_timer, typeof(*var), timer_fieldname) #endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) +static inline u64 ether_addr_to_u64(const u8 *addr) +{ + u64 u = 0; + int i; + + for (i = 0; i < ETH_ALEN; i++) + u = u << 8 | addr[i]; + + return u; +} + +static inline void u64_to_ether_addr(u64 u, u8 *addr) +{ + int i; + + for (i = ETH_ALEN - 1; i >= 0; i--) { + addr[i] = u & 0xff; + u = u >> 8; + } +} +#endif /* < 4,11,0 */ diff --git a/net/wireless/core.h b/net/wireless/core.h index 204cd19e9eba..625c59653ed6 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -144,6 +144,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 c4327520ffed..a1c0f6af1d3c 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -3,7 +3,7 @@ * * Copyright 2008 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH - * Copyright 2016 Intel Deutschland GmbH + * Copyright 2016-2017 Intel Deutschland GmbH */ #include #include @@ -149,6 +149,7 @@ static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev, } list_del_init(&bss->list); + list_del_init(&bss->nontrans_list); rb_erase(&bss->rbn, &rdev->bss_tree); rdev->bss_entries--; WARN_ONCE((rdev->bss_entries == 0) ^ list_empty(&rdev->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(&new->hidden_list); + INIT_LIST_HEAD(&new->nontrans_list); if (rcu_access_pointer(tmp->pub.proberesp_ies)) { hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN); @@ -1086,18 +1088,157 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen, return channel; } +static void gen_new_bssid(const u8 *bssid, u8 max_bssid, u8 mbssid_index, + u8 *new_bssid_addr) +{ + u64 bssid_tmp, new_bssid = 0; + u64 lsb_n; + + bssid_tmp = ether_addr_to_u64(bssid); + + lsb_n = bssid_tmp & ((1 << max_bssid) - 1); + new_bssid = bssid_tmp; + new_bssid &= ~((1 << max_bssid) - 1); + new_bssid |= (lsb_n + mbssid_index) % (1 << max_bssid); + + u64_to_ether_addr(new_bssid, new_bssid_addr); +} + +static size_t gen_new_ie(const u8 *ie, size_t ielen, const u8 *subelement, + size_t subie_len, u8 *new_ie, gfp_t gfp) +{ + u8 *pos, *tmp; + const u8 *tmp_old, *tmp_new; + u8 *sub_copy; + + /* copy subelement as we need to change its content to + * mark an ie after it is processed. + */ + sub_copy = kmalloc(subie_len, gfp); + if (!sub_copy) + return 0; + memcpy(sub_copy, subelement, subie_len); + + pos = &new_ie[0]; + + /* set new ssid */ + tmp_new = cfg80211_find_ie(WLAN_EID_SSID, sub_copy, subie_len); + if (tmp_new) { + memcpy(pos, tmp_new, tmp_new[1] + 2); + pos += (tmp_new[1] + 2); + } + + /* go through IEs in ie (skip SSID) and subelement, + * merge them into new_ie + */ + tmp_old = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen); + tmp_old = (tmp_old) ? tmp_old + tmp_old[1] + 2 : ie; + + while (tmp_old + tmp_old[1] + 2 - ie <= ielen) { + if (tmp_old[0] == 0) { + tmp_old++; + continue; + } + + tmp = (u8 *)cfg80211_find_ie(tmp_old[0], sub_copy, subie_len); + if (!tmp) { + /* ie in old ie but not in subelement */ + if (tmp_old[0] != WLAN_EID_MULTIPLE_BSSID) { + memcpy(pos, tmp_old, tmp_old[1] + 2); + pos += tmp_old[1] + 2; + } + } else { + /* ie in transmitting ie also in subelement, + * copy from subelement and flag the ie in subelement + * as copied (by setting eid field to 0xff). For + * vendor ie, compare OUI + type + subType to + * determine if they are the same ie. + */ + if (tmp_old[0] == WLAN_EID_VENDOR_SPECIFIC) { + if (!memcmp(tmp_old + 2, tmp + 2, 5)) { + /* same vendor ie, copy from + * subelement + */ + memcpy(pos, tmp, tmp[1] + 2); + pos += tmp[1] + 2; + tmp[0] = 0xff; + } else { + memcpy(pos, tmp_old, tmp_old[1] + 2); + pos += tmp_old[1] + 2; + } + } else { + /* copy ie from subelement into new ie */ + memcpy(pos, tmp, tmp[1] + 2); + pos += tmp[1] + 2; + tmp[0] = 0xff; + } + } + + if (tmp_old + tmp_old[1] + 2 - ie == ielen) + break; + + tmp_old += tmp_old[1] + 2; + } + + /* go through subelement again to check if there is any ie not + * copied to new ie, skip ssid, capability, bssid-index ie + */ + tmp_new = sub_copy; + while (tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) { + if (!(tmp_new[0] == WLAN_EID_NON_TX_BSSID_CAP || + tmp_new[0] == WLAN_EID_SSID || + tmp_new[0] == WLAN_EID_MULTI_BSSID_IDX || + tmp_new[0] == 0xff)) { + memcpy(pos, tmp_new, tmp_new[1] + 2); + pos += tmp_new[1] + 2; + } + if (tmp_new + tmp_new[1] + 2 - sub_copy == subie_len) + break; + tmp_new += tmp_new[1] + 2; + } + + kfree(sub_copy); + return pos - new_ie; +} + +static int add_nontrans_list(struct cfg80211_internal_bss *trans_bss, + struct cfg80211_internal_bss *nontrans_bss) +{ + const u8 *ssid; + size_t ssid_len; + struct cfg80211_internal_bss *bss = NULL; + + ssid = ieee80211_bss_get_ie(&nontrans_bss->pub, WLAN_EID_SSID); + if (!ssid) + return -EINVAL; + ssid_len = ssid[1]; + ssid = ssid + 2; + + /* check if nontrans_bss is in the list */ + list_for_each_entry(bss, &trans_bss->nontrans_list, nontrans_list) { + if (is_bss(&bss->pub, nontrans_bss->pub.bssid, ssid, ssid_len)) + return 0; + } + + /* add to the list */ + list_add_tail(&nontrans_bss->nontrans_list, &trans_bss->nontrans_list); + return 0; +} + /* Returned bss is reference counted and must be cleaned up appropriately. */ -struct cfg80211_bss * -cfg80211_inform_bss_data(struct wiphy *wiphy, - struct cfg80211_inform_bss *data, - enum cfg80211_bss_frame_type ftype, - const u8 *bssid, u64 tsf, u16 capability, - u16 beacon_interval, const u8 *ie, size_t ielen, - gfp_t gfp) +static struct cfg80211_bss * +cfg80211_inform_single_bss_data(struct wiphy *wiphy, + struct cfg80211_inform_bss *data, + enum cfg80211_bss_frame_type ftype, + const u8 *bssid, u64 tsf, u16 capability, + u16 beacon_interval, const u8 *ie, size_t ielen, + struct cfg80211_bss *trans_bss, + gfp_t gfp) { + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct cfg80211_bss_ies *ies; struct ieee80211_channel *channel; - struct cfg80211_internal_bss tmp = {}, *res; + struct cfg80211_internal_bss tmp = {}, *res, *trans_internal; int bss_type; bool signal_valid; @@ -1165,18 +1306,245 @@ cfg80211_inform_bss_data(struct wiphy *wiphy, regulatory_hint_found_beacon(wiphy, channel, gfp); } + if (trans_bss) { + /* this is a nontransmitting bss, we need to add it to + * transmitting bss' list if it is not there + */ + trans_internal = container_of(trans_bss, + struct cfg80211_internal_bss, + pub); + if (add_nontrans_list(trans_internal, res)) { + if (__cfg80211_unlink_bss(rdev, res)) + rdev->bss_generation++; + } + } + trace_cfg80211_return_bss(&res->pub); /* cfg80211_bss_update gives us a referenced result */ return &res->pub; } + +static void parse_mbssid_data(struct wiphy *wiphy, + struct cfg80211_inform_bss *data, + enum cfg80211_bss_frame_type ftype, + const u8 *bssid, u64 tsf, + u16 beacon_interval, const u8 *ie, size_t ielen, + struct cfg80211_bss *trans_bss, + gfp_t gfp) +{ + const u8 *pos, *subelement, *mbssid_end_pos; + const u8 *tmp, *mbssid_index_ie; + size_t subie_len, new_ie_len; + u8 new_bssid[ETH_ALEN]; + u8 *new_ie; + u16 capability; + struct cfg80211_bss *bss; + + if (!trans_bss) + return; + if (!cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen)) + return; + + pos = ie; + + new_ie = kmalloc(IEEE80211_MAX_DATA_LEN, gfp); + if (!new_ie) + return; + + while (pos < ie + ielen + 2) { + tmp = cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, pos, + ielen - (pos - ie)); + if (!tmp) + break; + + mbssid_end_pos = tmp + tmp[1] + 2; + /* Skip Element ID, Len, MaxBSSID Indicator */ + if (tmp[1] < 4) + break; + for (subelement = tmp + 3; subelement < mbssid_end_pos - 1; + subelement += 2 + subelement[1]) { + subie_len = subelement[1]; + if (mbssid_end_pos - subelement < 2 + subie_len) + break; + if (subelement[0] != 0 || subelement[1] < 4) { + /* not a valid BSS profile */ + continue; + } + + if (subelement[2] != WLAN_EID_NON_TX_BSSID_CAP || + subelement[3] != 2) { + /* The first element within the Nontransmitted + * BSSID Profile is not the Nontransmitted + * BSSID Capability element. + */ + continue; + } + + /* found a Nontransmitted BSSID Profile */ + mbssid_index_ie = cfg80211_find_ie( + WLAN_EID_MULTI_BSSID_IDX, + subelement + 2, subie_len); + if (!mbssid_index_ie || mbssid_index_ie[1] < 1 || + mbssid_index_ie[2] == 0) { + /* No valid Multiple BSSID-Index element */ + continue; + } + + gen_new_bssid(bssid, tmp[2], mbssid_index_ie[2], + new_bssid); + memset(new_ie, 0, IEEE80211_MAX_DATA_LEN); + new_ie_len = gen_new_ie(ie, ielen, subelement + 2, + subie_len, new_ie, gfp); + if (!new_ie_len) + continue; + + capability = le16_to_cpup((const __le16 *)&subelement[4]); + bss = cfg80211_inform_single_bss_data(wiphy, data, + ftype, + new_bssid, tsf, + capability, + beacon_interval, + new_ie, + new_ie_len, + trans_bss, gfp); + if (!bss) + break; + cfg80211_put_bss(wiphy, bss); + } + + pos = mbssid_end_pos; + } + + kfree(new_ie); +} + +struct cfg80211_bss * +cfg80211_inform_bss_data(struct wiphy *wiphy, + struct cfg80211_inform_bss *data, + enum cfg80211_bss_frame_type ftype, + const u8 *bssid, u64 tsf, u16 capability, + u16 beacon_interval, const u8 *ie, size_t ielen, + gfp_t gfp) +{ + struct cfg80211_bss *res; + + res = cfg80211_inform_single_bss_data(wiphy, data, ftype, bssid, tsf, + capability, beacon_interval, ie, + ielen, NULL, gfp); + parse_mbssid_data(wiphy, data, ftype, bssid, tsf, beacon_interval, + ie, ielen, res, gfp); + return res; +} EXPORT_SYMBOL(cfg80211_inform_bss_data); +static void parse_mbssid_frame_data(struct wiphy *wiphy, + struct cfg80211_inform_bss *data, + struct ieee80211_mgmt *mgmt, size_t len, + struct cfg80211_bss *trans_bss, + gfp_t gfp) +{ + enum cfg80211_bss_frame_type ftype; + const u8 *ie = mgmt->u.probe_resp.variable; + size_t ielen = len - offsetof(struct ieee80211_mgmt, + u.probe_resp.variable); + + ftype = ieee80211_is_beacon(mgmt->frame_control) ? + CFG80211_BSS_FTYPE_BEACON : CFG80211_BSS_FTYPE_PRESP; + + parse_mbssid_data(wiphy, data, ftype, mgmt->bssid, + le64_to_cpu(mgmt->u.probe_resp.timestamp), + le16_to_cpu(mgmt->u.probe_resp.beacon_int), + ie, ielen, trans_bss, gfp); +} + +static void update_notlisted_nontrans(struct wiphy *wiphy, + struct cfg80211_internal_bss + *nontrans_bss, + struct ieee80211_mgmt *mgmt, size_t len, + gfp_t gfp) + +{ + u8 *ie, *new_ie, *pos; + const u8 *tmp, *tmp1; + size_t ielen = len - offsetof(struct ieee80211_mgmt, + u.probe_resp.variable); + size_t new_ie_len; + struct cfg80211_bss_ies *new_ies; + const struct cfg80211_bss_ies *old; + + ie = mgmt->u.probe_resp.variable; + + new_ie_len = ielen; + tmp = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen); + if (!tmp) + return; + new_ie_len -= tmp[1]; + tmp = cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen); + if (!tmp) + return; + new_ie_len -= tmp[1]; + tmp = ieee80211_bss_get_ie(&nontrans_bss->pub, WLAN_EID_SSID); + if (!tmp) + return; + new_ie_len += tmp[1]; + + /* generate new ie for nontrans BSS + * 1. replace SSID with nontrans BSS' SSID + * 2. skip MBSSID IE + */ + new_ie = kzalloc(new_ie_len, gfp); + if (!new_ie) + goto error; + pos = new_ie; + tmp = ieee80211_bss_get_ie(&nontrans_bss->pub, WLAN_EID_SSID); + if (!tmp) + goto error; + + memcpy(pos, tmp, tmp[1] + 2); + pos += tmp[1] + 2; + tmp = cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen); + tmp1 = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen); + if (!tmp || !tmp1) + goto error; + memcpy(pos, (tmp1 + tmp1[1] + 2), (tmp - (tmp1 + tmp1[1] + 2))); + pos += (tmp - (tmp1 + tmp1[1] + 2)); + memcpy(pos, tmp + tmp[1] + 2, ((ie + ielen) - (tmp + tmp[1] + 2))); + + /* update ie */ + new_ies = kzalloc(sizeof(*new_ies) + new_ie_len, gfp); + if (!new_ies) + goto error; + new_ies->len = new_ie_len; + new_ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); + new_ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control); + memcpy(new_ies->data, new_ie, new_ie_len); + if (ieee80211_is_probe_resp(mgmt->frame_control)) { + old = rcu_access_pointer(nontrans_bss->pub.proberesp_ies); + rcu_assign_pointer(nontrans_bss->pub.proberesp_ies, new_ies); + rcu_assign_pointer(nontrans_bss->pub.ies, new_ies); + if (old) + kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head); + } else { + old = rcu_access_pointer(nontrans_bss->pub.beacon_ies); + rcu_assign_pointer(nontrans_bss->pub.beacon_ies, new_ies); + rcu_assign_pointer(nontrans_bss->pub.ies, new_ies); + if (old) + kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head); + } + + return; + +error: + kfree(new_ie); +} + /* cfg80211_inform_bss_width_frame helper */ -struct cfg80211_bss * -cfg80211_inform_bss_frame_data(struct wiphy *wiphy, - struct cfg80211_inform_bss *data, - struct ieee80211_mgmt *mgmt, size_t len, - gfp_t gfp) +static struct cfg80211_bss * +cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy, + struct cfg80211_inform_bss *data, + struct ieee80211_mgmt *mgmt, size_t len, + struct cfg80211_bss *trans_bss, + gfp_t gfp) { struct cfg80211_internal_bss tmp = {}, *res; @@ -1254,6 +1622,50 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy, /* cfg80211_bss_update gives us a referenced result */ return &res->pub; } + +struct cfg80211_bss * +cfg80211_inform_bss_frame_data(struct wiphy *wiphy, + struct cfg80211_inform_bss *data, + struct ieee80211_mgmt *mgmt, size_t len, + gfp_t gfp) +{ + struct cfg80211_bss *res; + struct cfg80211_internal_bss *trans_bss, *tmp_bss; + const u8 *ie = mgmt->u.probe_resp.variable; + const struct cfg80211_bss_ies *ies1, *ies2; + size_t ielen = len - offsetof(struct ieee80211_mgmt, + u.probe_resp.variable); + + res = cfg80211_inform_single_bss_frame_data(wiphy, data, mgmt, + len, NULL, gfp); + if (!cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen)) + return res; + + /* process each non-transmitting bss */ + parse_mbssid_frame_data(wiphy, data, mgmt, len, res, gfp); + + /* check if the res has other nontransmitting bss which is not + * in MBSSID IE + */ + ies1 = rcu_access_pointer(res->ies); + trans_bss = container_of(res, struct cfg80211_internal_bss, pub); + if (!trans_bss) + return res; + + /* go through nontrans_list, if the timestamp of the BSS is + * earlier than the timestamp of the transmitting BSS then + * update it + */ + list_for_each_entry(tmp_bss, &trans_bss->nontrans_list, + nontrans_list) { + ies2 = rcu_access_pointer(tmp_bss->pub.ies); + if (ies2->tsf < ies1->tsf) + update_notlisted_nontrans(wiphy, tmp_bss, mgmt, + len, gfp); + } + + return res; +} EXPORT_SYMBOL(cfg80211_inform_bss_frame_data); void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) @@ -1291,7 +1703,7 @@ EXPORT_SYMBOL(cfg80211_put_bss); void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) { struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); - struct cfg80211_internal_bss *bss; + struct cfg80211_internal_bss *bss, *nontrans_bss, *tmp; if (WARN_ON(!pub)) return; @@ -1300,6 +1712,13 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) spin_lock_bh(&rdev->bss_lock); if (!list_empty(&bss->list)) { + list_for_each_entry_safe(nontrans_bss, tmp, + &bss->nontrans_list, + nontrans_list) { + if (__cfg80211_unlink_bss(rdev, nontrans_bss)) + rdev->bss_generation++; + } + if (__cfg80211_unlink_bss(rdev, bss)) rdev->bss_generation++; } From patchwork Tue Aug 28 12:13:49 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johannes Berg X-Patchwork-Id: 10578359 X-Patchwork-Delegate: johannes@sipsolutions.net Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BD04814BD for ; Tue, 28 Aug 2018 12:20:07 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AC9E529F11 for ; Tue, 28 Aug 2018 12:20:07 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A113F29F2B; Tue, 28 Aug 2018 12:20:07 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 703B329F16 for ; Tue, 28 Aug 2018 12:20:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727864AbeH1QL0 (ORCPT ); Tue, 28 Aug 2018 12:11:26 -0400 Received: from s3.sipsolutions.net ([144.76.43.62]:53032 "EHLO sipsolutions.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727162AbeH1QL0 (ORCPT ); Tue, 28 Aug 2018 12:11:26 -0400 Received: by sipsolutions.net with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.91) (envelope-from ) id 1fucsm-00018J-EV; Tue, 28 Aug 2018 14:14:04 +0200 From: Johannes Berg To: linux-wireless@vger.kernel.org Cc: Jouni Malinen , Peng Xu , Sara Sharon Subject: [RFC 2/6] cfg80211: clean up the previous patch [SQUASH] Date: Tue, 28 Aug 2018 14:13:49 +0200 Message-Id: <20180828121353.11193-3-johannes@sipsolutions.net> X-Mailer: git-send-email 2.14.4 In-Reply-To: <20180828121353.11193-1-johannes@sipsolutions.net> References: <20180828121353.11193-1-johannes@sipsolutions.net> Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Sara Sharon Rename functions. Remove redundant assignments. Add some comments Signed-off-by: Sara Sharon Signed-off-by: Johannes Berg --- net/wireless/scan.c | 145 +++++++++++++++++++++++++++------------------------- 1 file changed, 75 insertions(+), 70 deletions(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index a1c0f6af1d3c..75e1fc79a890 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -1088,8 +1088,8 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen, return channel; } -static void gen_new_bssid(const u8 *bssid, u8 max_bssid, u8 mbssid_index, - u8 *new_bssid_addr) +static void cfg80211_gen_new_bssid(const u8 *bssid, u8 max_bssid, + u8 mbssid_index, u8 *new_bssid_addr) { u64 bssid_tmp, new_bssid = 0; u64 lsb_n; @@ -1104,8 +1104,9 @@ static void gen_new_bssid(const u8 *bssid, u8 max_bssid, u8 mbssid_index, u64_to_ether_addr(new_bssid, new_bssid_addr); } -static size_t gen_new_ie(const u8 *ie, size_t ielen, const u8 *subelement, - size_t subie_len, u8 *new_ie, gfp_t gfp) +static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen, + const u8 *subelement, size_t subie_len, + u8 *new_ie, gfp_t gfp) { u8 *pos, *tmp; const u8 *tmp_old, *tmp_new; @@ -1201,8 +1202,9 @@ static size_t gen_new_ie(const u8 *ie, size_t ielen, const u8 *subelement, return pos - new_ie; } -static int add_nontrans_list(struct cfg80211_internal_bss *trans_bss, - struct cfg80211_internal_bss *nontrans_bss) +static int +cfg80211_add_nontrans_list(struct cfg80211_internal_bss *trans_bss, + struct cfg80211_internal_bss *nontrans_bss) { const u8 *ssid; size_t ssid_len; @@ -1313,7 +1315,7 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, trans_internal = container_of(trans_bss, struct cfg80211_internal_bss, pub); - if (add_nontrans_list(trans_internal, res)) { + if (cfg80211_add_nontrans_list(trans_internal, res)) { if (__cfg80211_unlink_bss(rdev, res)) rdev->bss_generation++; } @@ -1324,13 +1326,14 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, return &res->pub; } -static void parse_mbssid_data(struct wiphy *wiphy, - struct cfg80211_inform_bss *data, - enum cfg80211_bss_frame_type ftype, - const u8 *bssid, u64 tsf, - u16 beacon_interval, const u8 *ie, size_t ielen, - struct cfg80211_bss *trans_bss, - gfp_t gfp) +static void cfg80211_parse_mbssid_data(struct wiphy *wiphy, + struct cfg80211_inform_bss *data, + enum cfg80211_bss_frame_type ftype, + const u8 *bssid, u64 tsf, + u16 beacon_interval, const u8 *ie, + size_t ielen, + struct cfg80211_bss *trans_bss, + gfp_t gfp) { const u8 *pos, *subelement, *mbssid_end_pos; const u8 *tmp, *mbssid_index_ie; @@ -1390,11 +1393,14 @@ static void parse_mbssid_data(struct wiphy *wiphy, continue; } - gen_new_bssid(bssid, tmp[2], mbssid_index_ie[2], - new_bssid); + cfg80211_gen_new_bssid(bssid, tmp[2], + mbssid_index_ie[2], + new_bssid); memset(new_ie, 0, IEEE80211_MAX_DATA_LEN); - new_ie_len = gen_new_ie(ie, ielen, subelement + 2, - subie_len, new_ie, gfp); + new_ie_len = cfg80211_gen_new_ie(ie, ielen, + subelement + 2, + subie_len, new_ie, + gfp); if (!new_ie_len) continue; @@ -1431,17 +1437,18 @@ cfg80211_inform_bss_data(struct wiphy *wiphy, res = cfg80211_inform_single_bss_data(wiphy, data, ftype, bssid, tsf, capability, beacon_interval, ie, ielen, NULL, gfp); - parse_mbssid_data(wiphy, data, ftype, bssid, tsf, beacon_interval, - ie, ielen, res, gfp); + cfg80211_parse_mbssid_data(wiphy, data, ftype, bssid, tsf, + beacon_interval, ie, ielen, res, gfp); return res; } EXPORT_SYMBOL(cfg80211_inform_bss_data); -static void parse_mbssid_frame_data(struct wiphy *wiphy, - struct cfg80211_inform_bss *data, - struct ieee80211_mgmt *mgmt, size_t len, - struct cfg80211_bss *trans_bss, - gfp_t gfp) +static void +cfg80211_parse_mbssid_frame_data(struct wiphy *wiphy, + struct cfg80211_inform_bss *data, + struct ieee80211_mgmt *mgmt, size_t len, + struct cfg80211_bss *trans_bss, + gfp_t gfp) { enum cfg80211_bss_frame_type ftype; const u8 *ie = mgmt->u.probe_resp.variable; @@ -1451,42 +1458,43 @@ static void parse_mbssid_frame_data(struct wiphy *wiphy, ftype = ieee80211_is_beacon(mgmt->frame_control) ? CFG80211_BSS_FTYPE_BEACON : CFG80211_BSS_FTYPE_PRESP; - parse_mbssid_data(wiphy, data, ftype, mgmt->bssid, - le64_to_cpu(mgmt->u.probe_resp.timestamp), - le16_to_cpu(mgmt->u.probe_resp.beacon_int), - ie, ielen, trans_bss, gfp); + cfg80211_parse_mbssid_data(wiphy, data, ftype, mgmt->bssid, + le64_to_cpu(mgmt->u.probe_resp.timestamp), + le16_to_cpu(mgmt->u.probe_resp.beacon_int), + ie, ielen, trans_bss, gfp); } -static void update_notlisted_nontrans(struct wiphy *wiphy, - struct cfg80211_internal_bss - *nontrans_bss, - struct ieee80211_mgmt *mgmt, size_t len, - gfp_t gfp) +static void +cfg80211_update_notlisted_nontrans(struct wiphy *wiphy, + struct cfg80211_internal_bss *nontrans_bss, + struct ieee80211_mgmt *mgmt, size_t len, + gfp_t gfp) { u8 *ie, *new_ie, *pos; - const u8 *tmp, *tmp1; + const u8 *nontrans_ssid, *trans_ssid, *mbssid; size_t ielen = len - offsetof(struct ieee80211_mgmt, u.probe_resp.variable); size_t new_ie_len; struct cfg80211_bss_ies *new_ies; const struct cfg80211_bss_ies *old; + u8 cpy_len; - ie = mgmt->u.probe_resp.variable; + ie = mgmt->u.probe_resp.variable; new_ie_len = ielen; - tmp = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen); - if (!tmp) + trans_ssid = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen); + if (!trans_ssid) return; - new_ie_len -= tmp[1]; - tmp = cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen); - if (!tmp) + new_ie_len -= trans_ssid[1]; + mbssid = cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen); + if (!mbssid) return; - new_ie_len -= tmp[1]; - tmp = ieee80211_bss_get_ie(&nontrans_bss->pub, WLAN_EID_SSID); - if (!tmp) + new_ie_len -= mbssid[1]; + nontrans_ssid = ieee80211_bss_get_ie(&nontrans_bss->pub, WLAN_EID_SSID); + if (!nontrans_ssid) return; - new_ie_len += tmp[1]; + new_ie_len += nontrans_ssid[1]; /* generate new ie for nontrans BSS * 1. replace SSID with nontrans BSS' SSID @@ -1494,26 +1502,28 @@ static void update_notlisted_nontrans(struct wiphy *wiphy, */ new_ie = kzalloc(new_ie_len, gfp); if (!new_ie) - goto error; + return; + new_ies = kzalloc(sizeof(*new_ies) + new_ie_len, gfp); + if (!new_ies) { + kfree(new_ie); + return; + } + pos = new_ie; - tmp = ieee80211_bss_get_ie(&nontrans_bss->pub, WLAN_EID_SSID); - if (!tmp) - goto error; - - memcpy(pos, tmp, tmp[1] + 2); - pos += tmp[1] + 2; - tmp = cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen); - tmp1 = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen); - if (!tmp || !tmp1) - goto error; - memcpy(pos, (tmp1 + tmp1[1] + 2), (tmp - (tmp1 + tmp1[1] + 2))); - pos += (tmp - (tmp1 + tmp1[1] + 2)); - memcpy(pos, tmp + tmp[1] + 2, ((ie + ielen) - (tmp + tmp[1] + 2))); + + /* copy the nontransmitted SSID */ + cpy_len = nontrans_ssid[1] + 2; + memcpy(pos, nontrans_ssid, cpy_len); + pos += cpy_len; + /* copy the IEs between SSID and MBSSID */ + cpy_len = trans_ssid[1] + 2; + memcpy(pos, (trans_ssid + cpy_len), (mbssid - (trans_ssid + cpy_len))); + pos += (mbssid - (trans_ssid + cpy_len)); + /* copy the IEs after MBSSID */ + cpy_len = mbssid[1] + 2; + memcpy(pos, mbssid + cpy_len, ((ie + ielen) - (mbssid + cpy_len))); /* update ie */ - new_ies = kzalloc(sizeof(*new_ies) + new_ie_len, gfp); - if (!new_ies) - goto error; new_ies->len = new_ie_len; new_ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); new_ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control); @@ -1531,11 +1541,6 @@ static void update_notlisted_nontrans(struct wiphy *wiphy, if (old) kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head); } - - return; - -error: - kfree(new_ie); } /* cfg80211_inform_bss_width_frame helper */ @@ -1642,7 +1647,7 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy, return res; /* process each non-transmitting bss */ - parse_mbssid_frame_data(wiphy, data, mgmt, len, res, gfp); + cfg80211_parse_mbssid_frame_data(wiphy, data, mgmt, len, res, gfp); /* check if the res has other nontransmitting bss which is not * in MBSSID IE @@ -1660,8 +1665,8 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy, nontrans_list) { ies2 = rcu_access_pointer(tmp_bss->pub.ies); if (ies2->tsf < ies1->tsf) - update_notlisted_nontrans(wiphy, tmp_bss, mgmt, - len, gfp); + cfg80211_update_notlisted_nontrans(wiphy, tmp_bss, + mgmt, len, gfp); } return res; From patchwork Tue Aug 28 12:13:50 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johannes Berg X-Patchwork-Id: 10578349 X-Patchwork-Delegate: johannes@sipsolutions.net Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AD5E614BD for ; Tue, 28 Aug 2018 12:19:51 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9E7C829F01 for ; Tue, 28 Aug 2018 12:19:51 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 924E129F13; Tue, 28 Aug 2018 12:19:51 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 49FFE29F01 for ; Tue, 28 Aug 2018 12:19:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727749AbeH1QLO (ORCPT ); Tue, 28 Aug 2018 12:11:14 -0400 Received: from s3.sipsolutions.net ([144.76.43.62]:53018 "EHLO sipsolutions.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727162AbeH1QLN (ORCPT ); Tue, 28 Aug 2018 12:11:13 -0400 Received: by sipsolutions.net with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.91) (envelope-from ) id 1fucsm-00018J-Pt; Tue, 28 Aug 2018 14:14:04 +0200 From: Johannes Berg To: linux-wireless@vger.kernel.org Cc: Jouni Malinen , Peng Xu , Sara Sharon Subject: [RFC 3/6] cfg80211: protect against NULL dereference [SQUASH] Date: Tue, 28 Aug 2018 14:13:50 +0200 Message-Id: <20180828121353.11193-4-johannes@sipsolutions.net> X-Mailer: git-send-email 2.14.4 In-Reply-To: <20180828121353.11193-1-johannes@sipsolutions.net> References: <20180828121353.11193-1-johannes@sipsolutions.net> Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Sara Sharon Signed-off-by: Sara Sharon Signed-off-by: Johannes Berg --- net/wireless/scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 75e1fc79a890..c08b39a622b7 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -1643,7 +1643,7 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy, res = cfg80211_inform_single_bss_frame_data(wiphy, data, mgmt, len, NULL, gfp); - if (!cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen)) + if (!res || !cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen)) return res; /* process each non-transmitting bss */ From patchwork Tue Aug 28 12:13:51 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johannes Berg X-Patchwork-Id: 10578353 X-Patchwork-Delegate: johannes@sipsolutions.net Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 106E214BD for ; Tue, 28 Aug 2018 12:19:59 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 007F429F11 for ; Tue, 28 Aug 2018 12:19:59 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E8D3629F2B; Tue, 28 Aug 2018 12:19:58 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 845D729F11 for ; Tue, 28 Aug 2018 12:19:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727832AbeH1QLV (ORCPT ); Tue, 28 Aug 2018 12:11:21 -0400 Received: from s3.sipsolutions.net ([144.76.43.62]:53022 "EHLO sipsolutions.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727162AbeH1QLV (ORCPT ); Tue, 28 Aug 2018 12:11:21 -0400 Received: by sipsolutions.net with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.91) (envelope-from ) id 1fucsn-00018J-4p; Tue, 28 Aug 2018 14:14:05 +0200 From: Johannes Berg To: linux-wireless@vger.kernel.org Cc: Jouni Malinen , Peng Xu , Sara Sharon Subject: [RFC 4/6] cfg80211: properly track relation of transmitting and non-transmitting BSS Date: Tue, 28 Aug 2018 14:13:51 +0200 Message-Id: <20180828121353.11193-5-johannes@sipsolutions.net> X-Mailer: git-send-email 2.14.4 In-Reply-To: <20180828121353.11193-1-johannes@sipsolutions.net> References: <20180828121353.11193-1-johannes@sipsolutions.net> Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Sara Sharon When holding data of the non-transmitting BSS, we need to keep the transmitting BSS data on. Otherwise it will be released, and release the non-transmitting BSS with it. Signed-off-by: Sara Sharon Signed-off-by: Johannes Berg --- net/wireless/core.h | 9 +++++++++ net/wireless/scan.c | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/net/wireless/core.h b/net/wireless/core.h index 625c59653ed6..f9f0b9cdac6c 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -145,6 +145,7 @@ struct cfg80211_internal_bss { struct list_head list; struct list_head hidden_list; struct list_head nontrans_list; + struct cfg80211_bss *transmitted_bss; struct rb_node rbn; u64 ts_boottime; unsigned long ts; @@ -175,12 +176,20 @@ static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pu static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss) { atomic_inc(&bss->hold); + if (bss->transmitted_bss) + cfg80211_hold_bss(container_of(bss->transmitted_bss, + struct cfg80211_internal_bss, + pub)); } static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss) { int r = atomic_dec_return(&bss->hold); WARN_ON(r < 0); + if (bss->transmitted_bss) + cfg80211_unhold_bss(container_of(bss->transmitted_bss, + struct cfg80211_internal_bss, + pub)); } diff --git a/net/wireless/scan.c b/net/wireless/scan.c index c08b39a622b7..87526940178b 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -108,6 +108,12 @@ static inline void bss_ref_get(struct cfg80211_registered_device *rdev, pub); bss->refcount++; } + if (bss->transmitted_bss) { + bss = container_of(bss->transmitted_bss, + struct cfg80211_internal_bss, + pub); + bss->refcount++; + } } static inline void bss_ref_put(struct cfg80211_registered_device *rdev, @@ -124,6 +130,18 @@ static inline void bss_ref_put(struct cfg80211_registered_device *rdev, if (hbss->refcount == 0) bss_free(hbss); } + + if (bss->transmitted_bss) { + struct cfg80211_internal_bss *tbss; + + tbss = container_of(bss->transmitted_bss, + struct cfg80211_internal_bss, + pub); + tbss->refcount--; + if (tbss->refcount == 0) + bss_free(tbss); + } + bss->refcount--; if (bss->refcount == 0) bss_free(bss); @@ -886,6 +904,7 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev, static struct cfg80211_internal_bss * cfg80211_bss_update(struct cfg80211_registered_device *rdev, struct cfg80211_internal_bss *tmp, + struct cfg80211_bss *trans_bss, bool signal_valid) { struct cfg80211_internal_bss *found = NULL; @@ -1040,6 +1059,17 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev, goto drop; } + /* This must be before the call to bss_ref_get */ + if (trans_bss) { + struct cfg80211_internal_bss *pbss = + container_of(trans_bss, + struct cfg80211_internal_bss, + pub); + + new->transmitted_bss = trans_bss; + bss_ref_get(rdev, pbss); + } + list_add_tail(&new->list, &rdev->bss_list); rdev->bss_entries++; rb_insert_bss(rdev, new); @@ -1294,7 +1324,8 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, signal_valid = abs(data->chan->center_freq - channel->center_freq) <= wiphy->max_adj_channel_rssi_comp; - res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid); + res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, trans_bss, + signal_valid); if (!res) return NULL; @@ -1609,7 +1640,8 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy, signal_valid = abs(data->chan->center_freq - channel->center_freq) <= wiphy->max_adj_channel_rssi_comp; - res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid); + res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, trans_bss, + signal_valid); if (!res) return NULL; From patchwork Tue Aug 28 12:13:52 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johannes Berg X-Patchwork-Id: 10578351 X-Patchwork-Delegate: johannes@sipsolutions.net Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BBADC14BD for ; Tue, 28 Aug 2018 12:19:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id ABE6C29F11 for ; Tue, 28 Aug 2018 12:19:56 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A02D929F2B; Tue, 28 Aug 2018 12:19:56 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EC90729F11 for ; Tue, 28 Aug 2018 12:19:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727829AbeH1QLS (ORCPT ); Tue, 28 Aug 2018 12:11:18 -0400 Received: from s3.sipsolutions.net ([144.76.43.62]:53020 "EHLO sipsolutions.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727162AbeH1QLS (ORCPT ); Tue, 28 Aug 2018 12:11:18 -0400 Received: by sipsolutions.net with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.91) (envelope-from ) id 1fucsn-00018J-FF; Tue, 28 Aug 2018 14:14:05 +0200 From: Johannes Berg To: linux-wireless@vger.kernel.org Cc: Jouni Malinen , Peng Xu , Sara Sharon Subject: [RFC 5/6] cfg80211: move the multiple BSSID data to the visible part Date: Tue, 28 Aug 2018 14:13:52 +0200 Message-Id: <20180828121353.11193-6-johannes@sipsolutions.net> X-Mailer: git-send-email 2.14.4 In-Reply-To: <20180828121353.11193-1-johannes@sipsolutions.net> References: <20180828121353.11193-1-johannes@sipsolutions.net> Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Sara Sharon Mac80211 needs this info. Signed-off-by: Sara Sharon Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 2 ++ net/wireless/core.h | 10 +++---- net/wireless/scan.c | 80 ++++++++++++++++++++++++-------------------------- 3 files changed, 45 insertions(+), 47 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 45ea649fe88c..40b9ce8b3301 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1935,6 +1935,8 @@ struct cfg80211_bss { const struct cfg80211_bss_ies __rcu *proberesp_ies; struct cfg80211_bss *hidden_beacon_bss; + struct cfg80211_bss *transmitted_bss; + struct list_head nontrans_list; s32 signal; diff --git a/net/wireless/core.h b/net/wireless/core.h index f9f0b9cdac6c..05e552c65f9c 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -144,8 +144,6 @@ 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 cfg80211_bss *transmitted_bss; struct rb_node rbn; u64 ts_boottime; unsigned long ts; @@ -176,8 +174,8 @@ static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pu static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss) { atomic_inc(&bss->hold); - if (bss->transmitted_bss) - cfg80211_hold_bss(container_of(bss->transmitted_bss, + if (bss->pub.transmitted_bss) + cfg80211_hold_bss(container_of(bss->pub.transmitted_bss, struct cfg80211_internal_bss, pub)); } @@ -186,8 +184,8 @@ static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss) { int r = atomic_dec_return(&bss->hold); WARN_ON(r < 0); - if (bss->transmitted_bss) - cfg80211_unhold_bss(container_of(bss->transmitted_bss, + if (bss->pub.transmitted_bss) + cfg80211_unhold_bss(container_of(bss->pub.transmitted_bss, struct cfg80211_internal_bss, pub)); } diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 87526940178b..543551e3c44a 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -108,8 +108,8 @@ static inline void bss_ref_get(struct cfg80211_registered_device *rdev, pub); bss->refcount++; } - if (bss->transmitted_bss) { - bss = container_of(bss->transmitted_bss, + if (bss->pub.transmitted_bss) { + bss = container_of(bss->pub.transmitted_bss, struct cfg80211_internal_bss, pub); bss->refcount++; @@ -131,10 +131,10 @@ static inline void bss_ref_put(struct cfg80211_registered_device *rdev, bss_free(hbss); } - if (bss->transmitted_bss) { + if (bss->pub.transmitted_bss) { struct cfg80211_internal_bss *tbss; - tbss = container_of(bss->transmitted_bss, + tbss = container_of(bss->pub.transmitted_bss, struct cfg80211_internal_bss, pub); tbss->refcount--; @@ -167,7 +167,7 @@ static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev, } list_del_init(&bss->list); - list_del_init(&bss->nontrans_list); + list_del_init(&bss->pub.nontrans_list); rb_erase(&bss->rbn, &rdev->bss_tree); rdev->bss_entries--; WARN_ONCE((rdev->bss_entries == 0) ^ list_empty(&rdev->bss_list), @@ -1025,7 +1025,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev, memcpy(new, tmp, sizeof(*new)); new->refcount = 1; INIT_LIST_HEAD(&new->hidden_list); - INIT_LIST_HEAD(&new->nontrans_list); + INIT_LIST_HEAD(&new->pub.nontrans_list); if (rcu_access_pointer(tmp->pub.proberesp_ies)) { hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN); @@ -1066,7 +1066,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev, struct cfg80211_internal_bss, pub); - new->transmitted_bss = trans_bss; + new->pub.transmitted_bss = trans_bss; bss_ref_get(rdev, pbss); } @@ -1233,14 +1233,14 @@ static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen, } static int -cfg80211_add_nontrans_list(struct cfg80211_internal_bss *trans_bss, - struct cfg80211_internal_bss *nontrans_bss) +cfg80211_add_nontrans_list(struct cfg80211_bss *trans_bss, + struct cfg80211_bss *nontrans_bss) { const u8 *ssid; size_t ssid_len; - struct cfg80211_internal_bss *bss = NULL; + struct cfg80211_bss *bss = NULL; - ssid = ieee80211_bss_get_ie(&nontrans_bss->pub, WLAN_EID_SSID); + ssid = ieee80211_bss_get_ie(nontrans_bss, WLAN_EID_SSID); if (!ssid) return -EINVAL; ssid_len = ssid[1]; @@ -1248,7 +1248,7 @@ cfg80211_add_nontrans_list(struct cfg80211_internal_bss *trans_bss, /* check if nontrans_bss is in the list */ list_for_each_entry(bss, &trans_bss->nontrans_list, nontrans_list) { - if (is_bss(&bss->pub, nontrans_bss->pub.bssid, ssid, ssid_len)) + if (is_bss(bss, nontrans_bss->bssid, ssid, ssid_len)) return 0; } @@ -1270,7 +1270,7 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct cfg80211_bss_ies *ies; struct ieee80211_channel *channel; - struct cfg80211_internal_bss tmp = {}, *res, *trans_internal; + struct cfg80211_internal_bss tmp = {}, *res; int bss_type; bool signal_valid; @@ -1343,10 +1343,7 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, /* this is a nontransmitting bss, we need to add it to * transmitting bss' list if it is not there */ - trans_internal = container_of(trans_bss, - struct cfg80211_internal_bss, - pub); - if (cfg80211_add_nontrans_list(trans_internal, res)) { + if (cfg80211_add_nontrans_list(trans_bss, &res->pub)) { if (__cfg80211_unlink_bss(rdev, res)) rdev->bss_generation++; } @@ -1497,7 +1494,7 @@ cfg80211_parse_mbssid_frame_data(struct wiphy *wiphy, static void cfg80211_update_notlisted_nontrans(struct wiphy *wiphy, - struct cfg80211_internal_bss *nontrans_bss, + struct cfg80211_bss *nontrans_bss, struct ieee80211_mgmt *mgmt, size_t len, gfp_t gfp) @@ -1522,7 +1519,7 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy, if (!mbssid) return; new_ie_len -= mbssid[1]; - nontrans_ssid = ieee80211_bss_get_ie(&nontrans_bss->pub, WLAN_EID_SSID); + nontrans_ssid = ieee80211_bss_get_ie(nontrans_bss, WLAN_EID_SSID); if (!nontrans_ssid) return; new_ie_len += nontrans_ssid[1]; @@ -1560,15 +1557,15 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy, new_ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control); memcpy(new_ies->data, new_ie, new_ie_len); if (ieee80211_is_probe_resp(mgmt->frame_control)) { - old = rcu_access_pointer(nontrans_bss->pub.proberesp_ies); - rcu_assign_pointer(nontrans_bss->pub.proberesp_ies, new_ies); - rcu_assign_pointer(nontrans_bss->pub.ies, new_ies); + old = rcu_access_pointer(nontrans_bss->proberesp_ies); + rcu_assign_pointer(nontrans_bss->proberesp_ies, new_ies); + rcu_assign_pointer(nontrans_bss->ies, new_ies); if (old) kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head); } else { - old = rcu_access_pointer(nontrans_bss->pub.beacon_ies); - rcu_assign_pointer(nontrans_bss->pub.beacon_ies, new_ies); - rcu_assign_pointer(nontrans_bss->pub.ies, new_ies); + old = rcu_access_pointer(nontrans_bss->beacon_ies); + rcu_assign_pointer(nontrans_bss->beacon_ies, new_ies); + rcu_assign_pointer(nontrans_bss->ies, new_ies); if (old) kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head); } @@ -1666,8 +1663,7 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy, struct ieee80211_mgmt *mgmt, size_t len, gfp_t gfp) { - struct cfg80211_bss *res; - struct cfg80211_internal_bss *trans_bss, *tmp_bss; + struct cfg80211_bss *res, *tmp_bss; const u8 *ie = mgmt->u.probe_resp.variable; const struct cfg80211_bss_ies *ies1, *ies2; size_t ielen = len - offsetof(struct ieee80211_mgmt, @@ -1685,17 +1681,14 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy, * in MBSSID IE */ ies1 = rcu_access_pointer(res->ies); - trans_bss = container_of(res, struct cfg80211_internal_bss, pub); - if (!trans_bss) - return res; /* go through nontrans_list, if the timestamp of the BSS is * earlier than the timestamp of the transmitting BSS then * update it */ - list_for_each_entry(tmp_bss, &trans_bss->nontrans_list, + list_for_each_entry(tmp_bss, &res->nontrans_list, nontrans_list) { - ies2 = rcu_access_pointer(tmp_bss->pub.ies); + ies2 = rcu_access_pointer(tmp_bss->ies); if (ies2->tsf < ies1->tsf) cfg80211_update_notlisted_nontrans(wiphy, tmp_bss, mgmt, len, gfp); @@ -1740,7 +1733,8 @@ EXPORT_SYMBOL(cfg80211_put_bss); void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) { struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); - struct cfg80211_internal_bss *bss, *nontrans_bss, *tmp; + struct cfg80211_internal_bss *bss, *tmp1; + struct cfg80211_bss *nontrans_bss, *tmp; if (WARN_ON(!pub)) return; @@ -1748,17 +1742,21 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) bss = container_of(pub, struct cfg80211_internal_bss, pub); spin_lock_bh(&rdev->bss_lock); - if (!list_empty(&bss->list)) { - list_for_each_entry_safe(nontrans_bss, tmp, - &bss->nontrans_list, - nontrans_list) { - if (__cfg80211_unlink_bss(rdev, nontrans_bss)) - rdev->bss_generation++; - } + if (list_empty(&bss->list)) + goto out; - if (__cfg80211_unlink_bss(rdev, bss)) + list_for_each_entry_safe(nontrans_bss, tmp, + &pub->nontrans_list, + nontrans_list) { + tmp1 = container_of(nontrans_bss, + struct cfg80211_internal_bss, pub); + if (__cfg80211_unlink_bss(rdev, tmp1)) rdev->bss_generation++; } + + if (__cfg80211_unlink_bss(rdev, bss)) + rdev->bss_generation++; +out: spin_unlock_bh(&rdev->bss_lock); } EXPORT_SYMBOL(cfg80211_unlink_bss); From patchwork Tue Aug 28 12:13:53 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johannes Berg X-Patchwork-Id: 10578355 X-Patchwork-Delegate: johannes@sipsolutions.net Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AD65A15A7 for ; Tue, 28 Aug 2018 12:20:00 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9E71C29F11 for ; Tue, 28 Aug 2018 12:20:00 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 928BE29F40; Tue, 28 Aug 2018 12:20:00 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 378EA29F11 for ; Tue, 28 Aug 2018 12:20:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727840AbeH1QLW (ORCPT ); Tue, 28 Aug 2018 12:11:22 -0400 Received: from s3.sipsolutions.net ([144.76.43.62]:53028 "EHLO sipsolutions.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727162AbeH1QLW (ORCPT ); Tue, 28 Aug 2018 12:11:22 -0400 Received: by sipsolutions.net with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.91) (envelope-from ) id 1fucsn-00018J-Qv; Tue, 28 Aug 2018 14:14:05 +0200 From: Johannes Berg To: linux-wireless@vger.kernel.org Cc: Jouni Malinen , Peng Xu , Sara Sharon Subject: [RFC 6/6] mac80211: declare support for multi-BSSID if driver supports it Date: Tue, 28 Aug 2018 14:13:53 +0200 Message-Id: <20180828121353.11193-7-johannes@sipsolutions.net> X-Mailer: git-send-email 2.14.4 In-Reply-To: <20180828121353.11193-1-johannes@sipsolutions.net> References: <20180828121353.11193-1-johannes@sipsolutions.net> Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Sara Sharon Turn on the multi-BSSID bit for supporting drivers. Signed-off-by: Sara Sharon Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 5 +++++ include/net/mac80211.h | 3 +++ net/mac80211/debugfs.c | 1 + net/mac80211/main.c | 4 ++++ 4 files changed, 13 insertions(+) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 91378340bf4e..1267a8f0040a 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -2564,6 +2564,11 @@ enum ieee80211_tdls_actioncode { */ #define WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING BIT(2) +/* Multiple BSSID capability is set in the 6th bit of 3rd byte of the + * @WLAN_EID_EXT_CAPABILITY information element + */ +#define WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT BIT(6) + /* TDLS capabilities in the the 4th byte of @WLAN_EID_EXT_CAPABILITY */ #define WLAN_EXT_CAPA4_TDLS_BUFFER_STA BIT(4) #define WLAN_EXT_CAPA4_TDLS_PEER_PSM BIT(5) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 80ae58a35e73..75f4f3f67c3c 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2173,6 +2173,8 @@ struct ieee80211_txq { * The stack will not do fragmentation. * The callback for @set_frag_threshold should be set as well. * + * @IEEE80211_HW_SUPPORTS_MULTI_BSSID: Hardware supports multi BSSID + * * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays */ enum ieee80211_hw_flags { @@ -2215,6 +2217,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_TX_FRAG_LIST, IEEE80211_HW_REPORTS_LOW_ACK, IEEE80211_HW_SUPPORTS_TX_FRAG, + IEEE80211_HW_SUPPORTS_MULTI_BSSID, /* keep last, obviously */ NUM_IEEE80211_HW_FLAGS diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index d40ec17829a9..669fa78d1901 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -791,6 +791,7 @@ static const char *hw_flag_names[] = { FLAG(TX_FRAG_LIST), FLAG(REPORTS_LOW_ACK), FLAG(SUPPORTS_TX_FRAG), + FLAG(SUPPORTS_MULTI_BSSID), #undef FLAG }; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 7d7c1e7d1b5e..60e73dc74b63 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1070,6 +1070,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (ieee80211_hw_check(&local->hw, CHANCTX_STA_CSA)) local->ext_capa[0] |= WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING; + /* mac80211 supports multi BSSID, if the driver supports it */ + if (ieee80211_hw_check(&local->hw, SUPPORTS_MULTI_BSSID)) + local->ext_capa[2] |= WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT; + local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CSA_COUNTERS_NUM; result = wiphy_register(local->hw.wiphy);