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,
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;
}
......
......@@ -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,
......
......@@ -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);
......
......@@ -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;
......
......@@ -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);
......
......@@ -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);
......
......@@ -19,10 +19,13 @@
* 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:
......
......@@ -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,
......
......@@ -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);
......
......@@ -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);
......
......@@ -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);
}
}
}
......
......@@ -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)
......
......@@ -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
......
......@@ -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];
......
......@@ -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);
......
......@@ -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,
......
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