Commit 80279fb7 authored by Johannes Berg's avatar Johannes Berg

cfg80211: properly send NL80211_ATTR_DISCONNECTED_BY_AP in disconnect

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: default avatarMatthieu Mauger <matthieux.mauger@intel.com>
Tested-by: default avatarMatthieu Mauger <matthieux.mauger@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent c5a71688
...@@ -889,7 +889,7 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason, ...@@ -889,7 +889,7 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
GFP_KERNEL); GFP_KERNEL);
} else if (vif->sme_state == SME_CONNECTED) { } else if (vif->sme_state == SME_CONNECTED) {
cfg80211_disconnected(vif->ndev, proto_reason, cfg80211_disconnected(vif->ndev, proto_reason,
NULL, 0, GFP_KERNEL); NULL, 0, false, GFP_KERNEL);
} }
vif->sme_state = SME_DISCONNECTED; vif->sme_state = SME_DISCONNECTED;
...@@ -3467,7 +3467,7 @@ void ath6kl_cfg80211_stop(struct ath6kl_vif *vif) ...@@ -3467,7 +3467,7 @@ void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
GFP_KERNEL); GFP_KERNEL);
break; break;
case SME_CONNECTED: case SME_CONNECTED:
cfg80211_disconnected(vif->ndev, 0, NULL, 0, GFP_KERNEL); cfg80211_disconnected(vif->ndev, 0, NULL, 0, true, GFP_KERNEL);
break; break;
} }
......
...@@ -224,7 +224,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, ...@@ -224,7 +224,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
if (test_bit(wil_status_fwconnected, wil->status)) { if (test_bit(wil_status_fwconnected, wil->status)) {
clear_bit(wil_status_fwconnected, wil->status); clear_bit(wil_status_fwconnected, wil->status);
cfg80211_disconnected(ndev, reason_code, cfg80211_disconnected(ndev, reason_code,
NULL, 0, GFP_KERNEL); NULL, 0, false, GFP_KERNEL);
} else if (test_bit(wil_status_fwconnecting, wil->status)) { } else if (test_bit(wil_status_fwconnecting, wil->status)) {
cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE, WLAN_STATUS_UNSPECIFIED_FAILURE,
......
...@@ -1262,7 +1262,7 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason) ...@@ -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); clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0, cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0,
GFP_KERNEL); true, GFP_KERNEL);
} }
clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state); clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
...@@ -1928,7 +1928,7 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, ...@@ -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_CONNECTED, &ifp->vif->sme_state);
clear_bit(BRCMF_VIF_STATUS_CONNECTING, &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); memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
scbval.val = cpu_to_le32(reason_code); scbval.val = cpu_to_le32(reason_code);
......
...@@ -835,14 +835,13 @@ static int lbs_cfg_scan(struct wiphy *wiphy, ...@@ -835,14 +835,13 @@ static int lbs_cfg_scan(struct wiphy *wiphy,
* Events * 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); lbs_deb_enter(LBS_DEB_CFG80211);
cfg80211_disconnected(priv->dev, cfg80211_disconnected(priv->dev, 0, NULL, 0, locally_generated,
0, GFP_KERNEL);
NULL, 0,
GFP_KERNEL);
lbs_deb_leave(LBS_DEB_CFG80211); lbs_deb_leave(LBS_DEB_CFG80211);
} }
...@@ -1458,7 +1457,7 @@ int lbs_disconnect(struct lbs_private *priv, u16 reason) ...@@ -1458,7 +1457,7 @@ int lbs_disconnect(struct lbs_private *priv, u16 reason)
cfg80211_disconnected(priv->dev, cfg80211_disconnected(priv->dev,
reason, reason,
NULL, 0, NULL, 0, true,
GFP_KERNEL); GFP_KERNEL);
priv->connect_status = LBS_DISCONNECTED; priv->connect_status = LBS_DISCONNECTED;
...@@ -2031,7 +2030,7 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev) ...@@ -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); 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 */ /* 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); lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
return ret; return ret;
......
...@@ -10,7 +10,8 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev); ...@@ -10,7 +10,8 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev);
int lbs_cfg_register(struct lbs_private *priv); int lbs_cfg_register(struct lbs_private *priv);
void lbs_cfg_free(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_send_mic_failureevent(struct lbs_private *priv, u32 event);
void lbs_scan_done(struct lbs_private *priv); void lbs_scan_done(struct lbs_private *priv);
......
...@@ -68,7 +68,8 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len); ...@@ -68,7 +68,8 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len);
/* From cmdresp.c */ /* From cmdresp.c */
void lbs_mac_event_disconnected(struct lbs_private *priv); void lbs_mac_event_disconnected(struct lbs_private *priv,
bool locally_generated);
......
...@@ -19,10 +19,13 @@ ...@@ -19,10 +19,13 @@
* reset link state etc. * reset link state etc.
* *
* @priv: A pointer to struct lbs_private structure * @priv: A pointer to struct lbs_private structure
* @locally_generated: indicates disconnect was requested locally
* (usually by userspace)
* *
* returns: n/a * 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) if (priv->connect_status != LBS_CONNECTED)
return; return;
...@@ -36,7 +39,7 @@ void lbs_mac_event_disconnected(struct lbs_private *priv) ...@@ -36,7 +39,7 @@ void lbs_mac_event_disconnected(struct lbs_private *priv)
msleep_interruptible(1000); msleep_interruptible(1000);
if (priv->wdev->iftype == NL80211_IFTYPE_STATION) if (priv->wdev->iftype == NL80211_IFTYPE_STATION)
lbs_send_disconnect_notification(priv); lbs_send_disconnect_notification(priv, locally_generated);
/* report disconnect to upper layer */ /* report disconnect to upper layer */
netif_stop_queue(priv->dev); netif_stop_queue(priv->dev);
...@@ -229,17 +232,17 @@ int lbs_process_event(struct lbs_private *priv, u32 event) ...@@ -229,17 +232,17 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
case MACREG_INT_CODE_DEAUTHENTICATED: case MACREG_INT_CODE_DEAUTHENTICATED:
lbs_deb_cmd("EVENT: deauthenticated\n"); lbs_deb_cmd("EVENT: deauthenticated\n");
lbs_mac_event_disconnected(priv); lbs_mac_event_disconnected(priv, false);
break; break;
case MACREG_INT_CODE_DISASSOCIATED: case MACREG_INT_CODE_DISASSOCIATED:
lbs_deb_cmd("EVENT: disassociated\n"); lbs_deb_cmd("EVENT: disassociated\n");
lbs_mac_event_disconnected(priv); lbs_mac_event_disconnected(priv, false);
break; break;
case MACREG_INT_CODE_LINK_LOST_NO_SCAN: case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
lbs_deb_cmd("EVENT: link lost\n"); lbs_deb_cmd("EVENT: link lost\n");
lbs_mac_event_disconnected(priv); lbs_mac_event_disconnected(priv, true);
break; break;
case MACREG_INT_CODE_PS_SLEEP: case MACREG_INT_CODE_PS_SLEEP:
......
...@@ -1421,7 +1421,7 @@ int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac) ...@@ -1421,7 +1421,7 @@ int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac)
ret = mwifiex_deauthenticate_infra(priv, mac); ret = mwifiex_deauthenticate_infra(priv, mac);
if (ret) if (ret)
cfg80211_disconnected(priv->netdev, 0, NULL, 0, cfg80211_disconnected(priv->netdev, 0, NULL, 0,
GFP_KERNEL); true, GFP_KERNEL);
break; break;
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_STOP, return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_STOP,
......
...@@ -133,7 +133,7 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code) ...@@ -133,7 +133,7 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)
if (priv->bss_mode == NL80211_IFTYPE_STATION || if (priv->bss_mode == NL80211_IFTYPE_STATION ||
priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) { priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
cfg80211_disconnected(priv->netdev, reason_code, NULL, 0, cfg80211_disconnected(priv->netdev, reason_code, NULL, 0,
GFP_KERNEL); false, GFP_KERNEL);
} }
eth_zero_addr(priv->cfg_bssid); eth_zero_addr(priv->cfg_bssid);
......
...@@ -2861,7 +2861,7 @@ static void rndis_wlan_do_link_down_work(struct usbnet *usbdev) ...@@ -2861,7 +2861,7 @@ static void rndis_wlan_do_link_down_work(struct usbnet *usbdev)
deauthenticate(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); netif_carrier_off(usbdev->net);
......
...@@ -379,7 +379,7 @@ void rtw_cfg80211_indicate_disconnect(struct rtw_adapter *padapter) ...@@ -379,7 +379,7 @@ void rtw_cfg80211_indicate_disconnect(struct rtw_adapter *padapter)
GFP_ATOMIC); GFP_ATOMIC);
} else { } else {
cfg80211_disconnected(padapter->pnetdev, 0, NULL, cfg80211_disconnected(padapter->pnetdev, 0, NULL,
0, GFP_ATOMIC); 0, false, GFP_ATOMIC);
} }
} }
} }
......
...@@ -722,7 +722,7 @@ void prism2_connect_result(wlandevice_t *wlandev, u8 failed) ...@@ -722,7 +722,7 @@ void prism2_connect_result(wlandevice_t *wlandev, u8 failed)
void prism2_disconnected(wlandevice_t *wlandev) void prism2_disconnected(wlandevice_t *wlandev)
{ {
cfg80211_disconnected(wlandev->netdev, 0, NULL, cfg80211_disconnected(wlandev->netdev, 0, NULL,
0, GFP_KERNEL); 0, false, GFP_KERNEL);
} }
void prism2_roamed(wlandevice_t *wlandev) void prism2_roamed(wlandevice_t *wlandev)
......
...@@ -4575,13 +4575,15 @@ void cfg80211_roamed_bss(struct net_device *dev, struct cfg80211_bss *bss, ...@@ -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: information elements of the deauth/disassoc frame (may be %NULL)
* @ie_len: length of IEs * @ie_len: length of IEs
* @reason: reason code for the disconnection, set it to 0 if unknown * @reason: reason code for the disconnection, set it to 0 if unknown
* @locally_generated: disconnection was requested locally
* @gfp: allocation flags * @gfp: allocation flags
* *
* After it calls this function, the driver should enter an idle state * After it calls this function, the driver should enter an idle state
* and not try to connect to any AP any more. * and not try to connect to any AP any more.
*/ */
void cfg80211_disconnected(struct net_device *dev, u16 reason, 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 * cfg80211_ready_on_channel - notification of remain_on_channel start
......
...@@ -222,6 +222,7 @@ struct cfg80211_event { ...@@ -222,6 +222,7 @@ struct cfg80211_event {
const u8 *ie; const u8 *ie;
size_t ie_len; size_t ie_len;
u16 reason; u16 reason;
bool locally_generated;
} dc; } dc;
struct { struct {
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];
......
...@@ -938,7 +938,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, ...@@ -938,7 +938,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
} }
void cfg80211_disconnected(struct net_device *dev, u16 reason, 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 wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
...@@ -954,6 +955,7 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason, ...@@ -954,6 +955,7 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason,
ev->dc.ie_len = ie_len; ev->dc.ie_len = ie_len;
memcpy((void *)ev->dc.ie, ie, ie_len); memcpy((void *)ev->dc.ie, ie, ie_len);
ev->dc.reason = reason; ev->dc.reason = reason;
ev->dc.locally_generated = locally_generated;
spin_lock_irqsave(&wdev->event_lock, flags); spin_lock_irqsave(&wdev->event_lock, flags);
list_add_tail(&ev->list, &wdev->event_list); list_add_tail(&ev->list, &wdev->event_list);
......
...@@ -887,7 +887,8 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev) ...@@ -887,7 +887,8 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
case EVENT_DISCONNECTED: case EVENT_DISCONNECTED:
__cfg80211_disconnected(wdev->netdev, __cfg80211_disconnected(wdev->netdev,
ev->dc.ie, ev->dc.ie_len, ev->dc.ie, ev->dc.ie_len,
ev->dc.reason, true); ev->dc.reason,
!ev->dc.locally_generated);
break; break;
case EVENT_IBSS_JOINED: case EVENT_IBSS_JOINED:
__cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid, __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid,
......
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