]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
cfg80211: Handle bss expiry during connection
authorChaitanya Tata <chaitanya.tata@bluwireless.co.uk>
Wed, 1 May 2019 12:55:24 +0000 (18:25 +0530)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 28 May 2019 07:35:39 +0000 (09:35 +0200)
If the BSS is expired during connection, the connect result will
trigger a kernel warning. Ideally cfg80211 should hold the BSS
before the connection is attempted, but as the BSSID is not known
in case of auth/assoc MLME offload (connect op) it doesn't.

For those drivers without the connect op cfg80211 holds down the
reference so it wil not be removed from list.

Fix this by removing the warning and silently adding the BSS back to
the bss list which is return by the driver (with proper BSSID set) or
in case the BSS is already added use that.

The requirements for drivers are documented in the API's.

Signed-off-by: Chaitanya Tata <chaitanya.tata@bluwireless.co.uk>
[formatting fixes, keep old timestamp]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/cfg80211.h
net/wireless/core.h
net/wireless/scan.c
net/wireless/sme.c

index 87dae868707e2a7fb92e483651c4e6cb2a524011..c1968783349360f912b04c2880853eae6a006147 100644 (file)
@@ -6231,8 +6231,11 @@ struct cfg80211_fils_resp_params {
  *     case.
  * @bssid: The BSSID of the AP (may be %NULL)
  * @bss: Entry of bss to which STA got connected to, can be obtained through
- *     cfg80211_get_bss() (may be %NULL). Only one parameter among @bssid and
- *     @bss needs to be specified.
+ *     cfg80211_get_bss() (may be %NULL). But it is recommended to store the
+ *     bss from the connect_request and hold a reference to it and return
+ *     through this param to avoid a warning if the bss is expired during the
+ *     connection, esp. for those drivers implementing connect op.
+ *     Only one parameter among @bssid and @bss needs to be specified.
  * @req_ie: Association request IEs (may be %NULL)
  * @req_ie_len: Association request IEs length
  * @resp_ie: Association response IEs (may be %NULL)
@@ -6280,8 +6283,12 @@ void cfg80211_connect_done(struct net_device *dev,
  *
  * @dev: network device
  * @bssid: the BSSID of the AP
- * @bss: entry of bss to which STA got connected to, can be obtained
- *     through cfg80211_get_bss (may be %NULL)
+ * @bss: Entry of bss to which STA got connected to, can be obtained through
+ *     cfg80211_get_bss() (may be %NULL). But it is recommended to store the
+ *     bss from the connect_request and hold a reference to it and return
+ *     through this param to avoid a warning if the bss is expired during the
+ *     connection, esp. for those drivers implementing connect op.
+ *     Only one parameter among @bssid and @bss needs to be specified.
  * @req_ie: association request IEs (maybe be %NULL)
  * @req_ie_len: association request IEs length
  * @resp_ie: association response IEs (may be %NULL)
index 84d36ca7a7aba9195bfbe2dccddae035ce92680d..ee8388fe4a92cb8849f5a83ca0be13b9766f176c 100644 (file)
@@ -531,6 +531,10 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
 void cfg80211_stop_nan(struct cfg80211_registered_device *rdev,
                       struct wireless_dev *wdev);
 
+struct cfg80211_internal_bss *
+cfg80211_bss_update(struct cfg80211_registered_device *rdev,
+                   struct cfg80211_internal_bss *tmp,
+                   bool signal_valid, unsigned long ts);
 #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
 #define CFG80211_DEV_WARN_ON(cond)     WARN_ON(cond)
 #else
index c04f5451f89b114cb98c43b1b3ce6724858f2a4f..f347387f195ad7679607364c2eea258195c6c653 100644 (file)
@@ -1092,17 +1092,17 @@ struct cfg80211_non_tx_bss {
 };
 
 /* Returned bss is reference counted and must be cleaned up appropriately. */
-static struct cfg80211_internal_bss *
+struct cfg80211_internal_bss *
 cfg80211_bss_update(struct cfg80211_registered_device *rdev,
                    struct cfg80211_internal_bss *tmp,
-                   bool signal_valid)
+                   bool signal_valid, unsigned long ts)
 {
        struct cfg80211_internal_bss *found = NULL;
 
        if (WARN_ON(!tmp->pub.channel))
                return NULL;
 
-       tmp->ts = jiffies;
+       tmp->ts = ts;
 
        spin_lock_bh(&rdev->bss_lock);
 
@@ -1425,7 +1425,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, signal_valid,
+                                 jiffies);
        if (!res)
                return NULL;
 
@@ -1842,7 +1843,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, signal_valid,
+                                 jiffies);
        if (!res)
                return NULL;
 
index 7d34cb884840e96d68b43e5f90036d3d3cd306dd..7a6c38ddc65adbaf60855749a22f120a86f05a2b 100644 (file)
@@ -796,12 +796,36 @@ void cfg80211_connect_done(struct net_device *dev,
        u8 *next;
 
        if (params->bss) {
-               /* Make sure the bss entry provided by the driver is valid. */
                struct cfg80211_internal_bss *ibss = bss_from_pub(params->bss);
 
-               if (WARN_ON(list_empty(&ibss->list))) {
-                       cfg80211_put_bss(wdev->wiphy, params->bss);
-                       return;
+               if (list_empty(&ibss->list)) {
+                       struct cfg80211_bss *found = NULL, *tmp = params->bss;
+
+                       found = cfg80211_get_bss(wdev->wiphy, NULL,
+                                                params->bss->bssid,
+                                                wdev->ssid, wdev->ssid_len,
+                                                wdev->conn_bss_type,
+                                                IEEE80211_PRIVACY_ANY);
+                       if (found) {
+                               /* The same BSS is already updated so use it
+                                * instead, as it has latest info.
+                                */
+                               params->bss = found;
+                       } else {
+                               /* Update with BSS provided by driver, it will
+                                * be freshly added and ref cnted, we can free
+                                * the old one.
+                                *
+                                * signal_valid can be false, as we are not
+                                * expecting the BSS to be found.
+                                *
+                                * keep the old timestamp to avoid confusion
+                                */
+                               cfg80211_bss_update(rdev, ibss, false,
+                                                   ibss->ts);
+                       }
+
+                       cfg80211_put_bss(wdev->wiphy, tmp);
                }
        }