diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index b73373aa0..e34545572 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -250,6 +250,7 @@ struct wpa_driver_nl80211_data { unsigned int scan_for_auth:1; unsigned int retry_auth:1; unsigned int use_monitor:1; + unsigned int ignore_next_local_disconnect:1; u64 remain_on_chan_cookie; u64 send_action_cookie; @@ -1191,6 +1192,7 @@ static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv, struct nlattr *by_ap) { union wpa_event_data data; + unsigned int locally_generated = by_ap == NULL; if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { /* @@ -1202,6 +1204,18 @@ static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv, return; } + if (drv->ignore_next_local_disconnect) { + drv->ignore_next_local_disconnect = 0; + if (locally_generated) { + wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect " + "event triggered during reassociation"); + return; + } + wpa_printf(MSG_WARNING, "nl80211: Was expecting local " + "disconnect but got another disconnect " + "event first"); + } + wpa_printf(MSG_DEBUG, "nl80211: Disconnect event"); drv->associated = 0; os_memset(&data, 0, sizeof(data)); @@ -4509,6 +4523,7 @@ static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv, { wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code); drv->associated = 0; + drv->ignore_next_local_disconnect = 0; /* Disconnect command doesn't need BSSID - it uses cached value */ return wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT, reason_code, 0); @@ -6663,7 +6678,7 @@ nla_put_failure: } -static int wpa_driver_nl80211_connect( +static int wpa_driver_nl80211_try_connect( struct wpa_driver_nl80211_data *drv, struct wpa_driver_associate_params *params) { @@ -6843,15 +6858,6 @@ skip_auth_type: if (ret) { wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d " "(%s)", ret, strerror(-ret)); - /* - * cfg80211 does not currently accept new connection if we are - * already connected. As a workaround, force disconnection and - * try again once the driver indicates it completed - * disconnection. - */ - if (ret == -EALREADY) - wpa_driver_nl80211_disconnect( - drv, WLAN_REASON_PREV_AUTH_NOT_VALID); goto nla_put_failure; } ret = 0; @@ -6864,6 +6870,31 @@ nla_put_failure: } +static int wpa_driver_nl80211_connect( + struct wpa_driver_nl80211_data *drv, + struct wpa_driver_associate_params *params) +{ + int ret = wpa_driver_nl80211_try_connect(drv, params); + if (ret == -EALREADY) { + /* + * cfg80211 does not currently accept new connections if + * we are already connected. As a workaround, force + * disconnection and try again. + */ + wpa_printf(MSG_DEBUG, "nl80211: Explicitly " + "disconnecting before reassociation " + "attempt"); + if (wpa_driver_nl80211_disconnect( + drv, WLAN_REASON_PREV_AUTH_NOT_VALID)) + return -1; + /* Ignore the next local disconnect message. */ + drv->ignore_next_local_disconnect = 1; + ret = wpa_driver_nl80211_try_connect(drv, params); + } + return ret; +} + + static int wpa_driver_nl80211_associate( void *priv, struct wpa_driver_associate_params *params) {