iwmc3200wifi: add disconnect work
When the driver receives "connection terminated" event from device, it could be caused by 2 reasons: the firmware is roaming or the connection is lost (AP disappears). For the former, an association complete event is supposed to come within 3 seconds. For the latter, the driver won't receive any event except the connection terminated. So we kick a delayed work (5*HZ) when we receive the connection terminated event. It will be canceled if it turns out to be a roaming event later. Otherwise we notify SME and userspace the disconnection. Signed-off-by: Zhu Yi <yi.zhu@intel.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
de15fd31fc
commit
c743627388
|
@ -273,6 +273,7 @@ struct iwm_priv {
|
||||||
|
|
||||||
struct iw_statistics wstats;
|
struct iw_statistics wstats;
|
||||||
struct delayed_work stats_request;
|
struct delayed_work stats_request;
|
||||||
|
struct delayed_work disconnect;
|
||||||
|
|
||||||
struct iwm_debugfs dbg;
|
struct iwm_debugfs dbg;
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,26 @@ static void iwm_statistics_request(struct work_struct *work)
|
||||||
iwm_send_umac_stats_req(iwm, 0);
|
iwm_send_umac_stats_req(iwm, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void iwm_disconnect_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct iwm_priv *iwm =
|
||||||
|
container_of(work, struct iwm_priv, disconnect.work);
|
||||||
|
|
||||||
|
if (iwm->umac_profile_active)
|
||||||
|
iwm_invalidate_mlme_profile(iwm);
|
||||||
|
|
||||||
|
clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
|
||||||
|
iwm->umac_profile_active = 0;
|
||||||
|
memset(iwm->bssid, 0, ETH_ALEN);
|
||||||
|
iwm->channel = 0;
|
||||||
|
|
||||||
|
iwm_link_off(iwm);
|
||||||
|
|
||||||
|
wake_up_interruptible(&iwm->mlme_queue);
|
||||||
|
|
||||||
|
cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL);
|
||||||
|
}
|
||||||
|
|
||||||
int __iwm_up(struct iwm_priv *iwm);
|
int __iwm_up(struct iwm_priv *iwm);
|
||||||
int __iwm_down(struct iwm_priv *iwm);
|
int __iwm_down(struct iwm_priv *iwm);
|
||||||
|
|
||||||
|
@ -198,6 +218,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
|
||||||
spin_lock_init(&iwm->cmd_lock);
|
spin_lock_init(&iwm->cmd_lock);
|
||||||
iwm->scan_id = 1;
|
iwm->scan_id = 1;
|
||||||
INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request);
|
INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request);
|
||||||
|
INIT_DELAYED_WORK(&iwm->disconnect, iwm_disconnect_work);
|
||||||
INIT_WORK(&iwm->reset_worker, iwm_reset_worker);
|
INIT_WORK(&iwm->reset_worker, iwm_reset_worker);
|
||||||
INIT_LIST_HEAD(&iwm->bss_list);
|
INIT_LIST_HEAD(&iwm->bss_list);
|
||||||
|
|
||||||
|
|
|
@ -514,6 +514,7 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
|
||||||
/* Internal roaming state, avoid notifying SME. */
|
/* Internal roaming state, avoid notifying SME. */
|
||||||
if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)
|
if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)
|
||||||
&& iwm->conf.mode == UMAC_MODE_BSS) {
|
&& iwm->conf.mode == UMAC_MODE_BSS) {
|
||||||
|
cancel_delayed_work(&iwm->disconnect);
|
||||||
cfg80211_roamed(iwm_to_ndev(iwm),
|
cfg80211_roamed(iwm_to_ndev(iwm),
|
||||||
complete->bssid,
|
complete->bssid,
|
||||||
iwm->req_ie, iwm->req_ie_len,
|
iwm->req_ie, iwm->req_ie_len,
|
||||||
|
@ -540,8 +541,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
|
||||||
|
|
||||||
/* Internal roaming state, avoid notifying SME. */
|
/* Internal roaming state, avoid notifying SME. */
|
||||||
if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)
|
if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)
|
||||||
&& iwm->conf.mode == UMAC_MODE_BSS)
|
&& iwm->conf.mode == UMAC_MODE_BSS) {
|
||||||
|
cancel_delayed_work(&iwm->disconnect);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
iwm_link_off(iwm);
|
iwm_link_off(iwm);
|
||||||
|
|
||||||
|
@ -569,11 +572,18 @@ static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf,
|
||||||
struct iwm_wifi_cmd *cmd)
|
struct iwm_wifi_cmd *cmd)
|
||||||
{
|
{
|
||||||
struct iwm_umac_notif_profile_invalidate *invalid;
|
struct iwm_umac_notif_profile_invalidate *invalid;
|
||||||
|
u32 reason;
|
||||||
|
|
||||||
invalid = (struct iwm_umac_notif_profile_invalidate *)buf;
|
invalid = (struct iwm_umac_notif_profile_invalidate *)buf;
|
||||||
|
reason = le32_to_cpu(invalid->reason);
|
||||||
|
|
||||||
IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n",
|
IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n", reason);
|
||||||
le32_to_cpu(invalid->reason));
|
|
||||||
|
if (reason != UMAC_PROFILE_INVALID_REQUEST &&
|
||||||
|
test_bit(IWM_STATUS_SME_CONNECTING, &iwm->status))
|
||||||
|
cfg80211_connect_result(iwm_to_ndev(iwm), NULL, NULL, 0, NULL,
|
||||||
|
0, WLAN_STATUS_UNSPECIFIED_FAILURE,
|
||||||
|
GFP_KERNEL);
|
||||||
|
|
||||||
clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status);
|
clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status);
|
||||||
clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
|
clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
|
||||||
|
@ -589,6 +599,19 @@ static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define IWM_DISCONNECT_INTERVAL (5 * HZ)
|
||||||
|
|
||||||
|
static int iwm_mlme_connection_terminated(struct iwm_priv *iwm, u8 *buf,
|
||||||
|
unsigned long buf_size,
|
||||||
|
struct iwm_wifi_cmd *cmd)
|
||||||
|
{
|
||||||
|
IWM_DBG_MLME(iwm, DBG, "Connection terminated\n");
|
||||||
|
|
||||||
|
schedule_delayed_work(&iwm->disconnect, IWM_DISCONNECT_INTERVAL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int iwm_mlme_scan_complete(struct iwm_priv *iwm, u8 *buf,
|
static int iwm_mlme_scan_complete(struct iwm_priv *iwm, u8 *buf,
|
||||||
unsigned long buf_size,
|
unsigned long buf_size,
|
||||||
struct iwm_wifi_cmd *cmd)
|
struct iwm_wifi_cmd *cmd)
|
||||||
|
@ -848,8 +871,7 @@ static int iwm_ntf_mlme(struct iwm_priv *iwm, u8 *buf,
|
||||||
case WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE:
|
case WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE:
|
||||||
return iwm_mlme_profile_invalidate(iwm, buf, buf_size, cmd);
|
return iwm_mlme_profile_invalidate(iwm, buf, buf_size, cmd);
|
||||||
case WIFI_IF_NTFY_CONNECTION_TERMINATED:
|
case WIFI_IF_NTFY_CONNECTION_TERMINATED:
|
||||||
IWM_DBG_MLME(iwm, DBG, "Connection terminated\n");
|
return iwm_mlme_connection_terminated(iwm, buf, buf_size, cmd);
|
||||||
break;
|
|
||||||
case WIFI_IF_NTFY_SCAN_COMPLETE:
|
case WIFI_IF_NTFY_SCAN_COMPLETE:
|
||||||
return iwm_mlme_scan_complete(iwm, buf, buf_size, cmd);
|
return iwm_mlme_scan_complete(iwm, buf, buf_size, cmd);
|
||||||
case WIFI_IF_NTFY_STA_TABLE_CHANGE:
|
case WIFI_IF_NTFY_STA_TABLE_CHANGE:
|
||||||
|
|
Loading…
Reference in New Issue