cfg80211: properly send NL80211_ATTR_DISCONNECTED_BY_AP in disconnect
authorJohannes Berg <johannes.berg@intel.com>
Fri, 22 May 2015 14:22:20 +0000 (16:22 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 26 May 2015 13:21:27 +0000 (15:21 +0200)
When we disconnect from the AP, drivers call cfg80211_disconnect().
This doesn't know whether the disconnection was initiated locally
or by the AP though, which can cause problems with the supplicant,
for example with WPS. This issue obviously doesn't show up with any
mac80211 based driver since mac80211 doesn't call this function.

Fix this by requiring drivers to indicate whether the disconnect is
locally generated or not. I've tried to update the drivers, but may
not have gotten the values correct, and some drivers may currently
not be able to report correct values. In case of doubt I left it at
false, which is the current behaviour.

For libertas, make adjustments as indicated by Dan Williams.

Reported-by: Matthieu Mauger <matthieux.mauger@intel.com>
Tested-by: Matthieu Mauger <matthieux.mauger@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
16 files changed:
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/wil6210/main.c
drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/libertas/cfg.h
drivers/net/wireless/libertas/cmd.h
drivers/net/wireless/libertas/cmdresp.c
drivers/net/wireless/mwifiex/join.c
drivers/net/wireless/mwifiex/sta_event.c
drivers/net/wireless/rndis_wlan.c
drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
drivers/staging/wlan-ng/cfg80211.c
include/net/cfg80211.h
net/wireless/core.h
net/wireless/sme.c
net/wireless/util.c

index cce4625a53ad7eb630bef4b717cc9fe0177d96fc..a511ef3614b9ed098558d1d86a9fec88b2330235 100644 (file)
@@ -889,7 +889,7 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
                                        GFP_KERNEL);
        } else if (vif->sme_state == SME_CONNECTED) {
                cfg80211_disconnected(vif->ndev, proto_reason,
-                                     NULL, 0, GFP_KERNEL);
+                                     NULL, 0, false, GFP_KERNEL);
        }
 
        vif->sme_state = SME_DISCONNECTED;
@@ -3467,7 +3467,7 @@ void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
                                        GFP_KERNEL);
                break;
        case SME_CONNECTED:
-               cfg80211_disconnected(vif->ndev, 0, NULL, 0, GFP_KERNEL);
+               cfg80211_disconnected(vif->ndev, 0, NULL, 0, true, GFP_KERNEL);
                break;
        }
 
index c2a238426425462c7ff40f61c8e98fec9dadca6d..38b953e108a714d10b89b9cd61d1c2144376c191 100644 (file)
@@ -224,7 +224,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
                if (test_bit(wil_status_fwconnected, wil->status)) {
                        clear_bit(wil_status_fwconnected, wil->status);
                        cfg80211_disconnected(ndev, reason_code,
-                                             NULL, 0, GFP_KERNEL);
+                                             NULL, 0, false, GFP_KERNEL);
                } else if (test_bit(wil_status_fwconnecting, wil->status)) {
                        cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
                                                WLAN_STATUS_UNSPECIFIED_FAILURE,
index 8a15ebbce4a360ff054e08c197118ddf43f75381..2e4e42245b8f0c0e2b86882265d5bace5eb93b6b 100644 (file)
@@ -1262,7 +1262,7 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
                }
                clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
                cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0,
-                                     GFP_KERNEL);
+                                     true, GFP_KERNEL);
 
        }
        clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
@@ -1928,7 +1928,7 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
 
        clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
        clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
-       cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL);
+       cfg80211_disconnected(ndev, reason_code, NULL, 0, true, GFP_KERNEL);
 
        memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
        scbval.val = cpu_to_le32(reason_code);
index 1a4d558022d8c1dff78b1181c6f9bc79e7573a12..8317afd065b498fd8001a0e83ec82c9b9a5284aa 100644 (file)
@@ -835,14 +835,13 @@ static int lbs_cfg_scan(struct wiphy *wiphy,
  * Events
  */
 
-void lbs_send_disconnect_notification(struct lbs_private *priv)
+void lbs_send_disconnect_notification(struct lbs_private *priv,
+                                     bool locally_generated)
 {
        lbs_deb_enter(LBS_DEB_CFG80211);
 
-       cfg80211_disconnected(priv->dev,
-               0,
-               NULL, 0,
-               GFP_KERNEL);
+       cfg80211_disconnected(priv->dev, 0, NULL, 0, locally_generated,
+                             GFP_KERNEL);
 
        lbs_deb_leave(LBS_DEB_CFG80211);
 }
@@ -1458,7 +1457,7 @@ int lbs_disconnect(struct lbs_private *priv, u16 reason)
 
        cfg80211_disconnected(priv->dev,
                        reason,
-                       NULL, 0,
+                       NULL, 0, true,
                        GFP_KERNEL);
        priv->connect_status = LBS_DISCONNECTED;
 
@@ -2031,7 +2030,7 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
        ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd);
 
        /* TODO: consider doing this at MACREG_INT_CODE_ADHOC_BCN_LOST time */
-       lbs_mac_event_disconnected(priv);
+       lbs_mac_event_disconnected(priv, true);
 
        lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
        return ret;
index 10995f59fe34a1796db45e914196fc7a03248c07..acccc29224016456f40e152dbe2cae340b9f73e3 100644 (file)
@@ -10,7 +10,8 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev);
 int lbs_cfg_register(struct lbs_private *priv);
 void lbs_cfg_free(struct lbs_private *priv);
 
-void lbs_send_disconnect_notification(struct lbs_private *priv);
+void lbs_send_disconnect_notification(struct lbs_private *priv,
+                                     bool locally_generated);
 void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
 
 void lbs_scan_done(struct lbs_private *priv);
index 4279e8ab95f2aa4545cef71daa5649b1314fdf3b..0c5444b02c64110d6f814983dd1bc8984ed442da 100644 (file)
@@ -68,7 +68,8 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len);
 
 /* From cmdresp.c */
 
-void lbs_mac_event_disconnected(struct lbs_private *priv);
+void lbs_mac_event_disconnected(struct lbs_private *priv,
+                               bool locally_generated);
 
 
 
index 65f18f1e869c86559b1fb8f608a4819b4c3c965e..e5442e8956f7ac3b1182058864816dc700548fe5 100644 (file)
  * reset link state etc.
  *
  * @priv:      A pointer to struct lbs_private structure
+ * @locally_generated: indicates disconnect was requested locally
+ *             (usually by userspace)
  *
  * returns:    n/a
  */
-void lbs_mac_event_disconnected(struct lbs_private *priv)
+void lbs_mac_event_disconnected(struct lbs_private *priv,
+                               bool locally_generated)
 {
        if (priv->connect_status != LBS_CONNECTED)
                return;
@@ -36,7 +39,7 @@ void lbs_mac_event_disconnected(struct lbs_private *priv)
        msleep_interruptible(1000);
 
        if (priv->wdev->iftype == NL80211_IFTYPE_STATION)
-               lbs_send_disconnect_notification(priv);
+               lbs_send_disconnect_notification(priv, locally_generated);
 
        /* report disconnect to upper layer */
        netif_stop_queue(priv->dev);
@@ -229,17 +232,17 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
 
        case MACREG_INT_CODE_DEAUTHENTICATED:
                lbs_deb_cmd("EVENT: deauthenticated\n");
-               lbs_mac_event_disconnected(priv);
+               lbs_mac_event_disconnected(priv, false);
                break;
 
        case MACREG_INT_CODE_DISASSOCIATED:
                lbs_deb_cmd("EVENT: disassociated\n");
-               lbs_mac_event_disconnected(priv);
+               lbs_mac_event_disconnected(priv, false);
                break;
 
        case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
                lbs_deb_cmd("EVENT: link lost\n");
-               lbs_mac_event_disconnected(priv);
+               lbs_mac_event_disconnected(priv, true);
                break;
 
        case MACREG_INT_CODE_PS_SLEEP:
index 411a6c2f4aca5da922409bf33c1aa7eae5a92f00..080ec3422db9f81238fcd02d07f5405eb097f189 100644 (file)
@@ -1421,7 +1421,7 @@ int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac)
                ret = mwifiex_deauthenticate_infra(priv, mac);
                if (ret)
                        cfg80211_disconnected(priv->netdev, 0, NULL, 0,
-                                             GFP_KERNEL);
+                                             true, GFP_KERNEL);
                break;
        case NL80211_IFTYPE_ADHOC:
                return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_STOP,
index 0dc7a1d3993d325a15f84fa447afaa884349eabc..c9064b88d6a4d6bbe33da26d09c4e296e14c7ed0 100644 (file)
@@ -133,7 +133,7 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)
        if (priv->bss_mode == NL80211_IFTYPE_STATION ||
            priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
                cfg80211_disconnected(priv->netdev, reason_code, NULL, 0,
-                                     GFP_KERNEL);
+                                     false, GFP_KERNEL);
        }
        eth_zero_addr(priv->cfg_bssid);
 
index d72ff8e7125d4525d1761c60d3828dba22b63296..43db6976102f940c9e670f20996dd803467edb8a 100644 (file)
@@ -2861,7 +2861,7 @@ static void rndis_wlan_do_link_down_work(struct usbnet *usbdev)
 
                deauthenticate(usbdev);
 
-               cfg80211_disconnected(usbdev->net, 0, NULL, 0, GFP_KERNEL);
+               cfg80211_disconnected(usbdev->net, 0, NULL, 0, true, GFP_KERNEL);
        }
 
        netif_carrier_off(usbdev->net);
index bc95ce89af0671f97a7c7f1128dab96cbc442e39..5ab2f6978209d8ac165d717bdeec16f8c1810c4e 100644 (file)
@@ -379,7 +379,7 @@ void rtw_cfg80211_indicate_disconnect(struct rtw_adapter *padapter)
                                                GFP_ATOMIC);
                } else {
                        cfg80211_disconnected(padapter->pnetdev, 0, NULL,
-                                             0, GFP_ATOMIC);
+                                             0, false, GFP_ATOMIC);
                }
        }
 }
index 7c87aecf474444a908dd02f780a7649f9f93a187..342e2b30c48f92a5a1b98541e4af9cf2d2c40432 100644 (file)
@@ -722,7 +722,7 @@ void prism2_connect_result(wlandevice_t *wlandev, u8 failed)
 void prism2_disconnected(wlandevice_t *wlandev)
 {
        cfg80211_disconnected(wlandev->netdev, 0, NULL,
-               0, GFP_KERNEL);
+               0, false, GFP_KERNEL);
 }
 
 void prism2_roamed(wlandevice_t *wlandev)
index d63ecec730907fb15321114d2eec7262cdeeea64..a741678f24a26d712e08775e213b1b1c50c8ca8a 100644 (file)
@@ -4575,13 +4575,15 @@ void cfg80211_roamed_bss(struct net_device *dev, struct cfg80211_bss *bss,
  * @ie: information elements of the deauth/disassoc frame (may be %NULL)
  * @ie_len: length of IEs
  * @reason: reason code for the disconnection, set it to 0 if unknown
+ * @locally_generated: disconnection was requested locally
  * @gfp: allocation flags
  *
  * After it calls this function, the driver should enter an idle state
  * and not try to connect to any AP any more.
  */
 void cfg80211_disconnected(struct net_device *dev, u16 reason,
-                          const u8 *ie, size_t ie_len, gfp_t gfp);
+                          const u8 *ie, size_t ie_len,
+                          bool locally_generated, gfp_t gfp);
 
 /**
  * cfg80211_ready_on_channel - notification of remain_on_channel start
index 801cd49c5a0c5f2748ff4aba595d865645208745..311eef26bf88b9a0e8125678498583fa19edf688 100644 (file)
@@ -222,6 +222,7 @@ struct cfg80211_event {
                        const u8 *ie;
                        size_t ie_len;
                        u16 reason;
+                       bool locally_generated;
                } dc;
                struct {
                        u8 bssid[ETH_ALEN];
index d11454f87bacf9396241bd5bbc3ba643ef0b3302..8020b5b094d4c8fba0c0f2431f8af7d8ecc40dca 100644 (file)
@@ -938,7 +938,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
 }
 
 void cfg80211_disconnected(struct net_device *dev, u16 reason,
-                          const u8 *ie, size_t ie_len, gfp_t gfp)
+                          const u8 *ie, size_t ie_len,
+                          bool locally_generated, gfp_t gfp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
@@ -954,6 +955,7 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason,
        ev->dc.ie_len = ie_len;
        memcpy((void *)ev->dc.ie, ie, ie_len);
        ev->dc.reason = reason;
+       ev->dc.locally_generated = locally_generated;
 
        spin_lock_irqsave(&wdev->event_lock, flags);
        list_add_tail(&ev->list, &wdev->event_list);
index 70051ab52f4f34d2817e76210aafa70bbda62e60..4cb34557b8731fe8297f302856f191fba3fca68c 100644 (file)
@@ -887,7 +887,8 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
                case EVENT_DISCONNECTED:
                        __cfg80211_disconnected(wdev->netdev,
                                                ev->dc.ie, ev->dc.ie_len,
-                                               ev->dc.reason, true);
+                                               ev->dc.reason,
+                                               !ev->dc.locally_generated);
                        break;
                case EVENT_IBSS_JOINED:
                        __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid,