aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorZhu Yi <yi.zhu@intel.com>2009-09-01 09:14:02 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-09-01 12:48:27 -0400
commitc7436273889e0ce511b317041f35344e92344885 (patch)
tree6b18a0a3d5308226afac15e1a545ef30119c925a /drivers/net/wireless
parentde15fd31fcabb4b81a556736dd67ec4f71462f07 (diff)
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>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/iwmc3200wifi/iwm.h1
-rw-r--r--drivers/net/wireless/iwmc3200wifi/main.c21
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.c32
3 files changed, 49 insertions, 5 deletions
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
index f054cc828d8d..da49df6f4020 100644
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -273,6 +273,7 @@ struct iwm_priv {
273 273
274 struct iw_statistics wstats; 274 struct iw_statistics wstats;
275 struct delayed_work stats_request; 275 struct delayed_work stats_request;
276 struct delayed_work disconnect;
276 277
277 struct iwm_debugfs dbg; 278 struct iwm_debugfs dbg;
278 279
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c
index cf2574442b57..c41fa8c5fa11 100644
--- a/drivers/net/wireless/iwmc3200wifi/main.c
+++ b/drivers/net/wireless/iwmc3200wifi/main.c
@@ -108,6 +108,26 @@ static void iwm_statistics_request(struct work_struct *work)
108 iwm_send_umac_stats_req(iwm, 0); 108 iwm_send_umac_stats_req(iwm, 0);
109} 109}
110 110
111static void iwm_disconnect_work(struct work_struct *work)
112{
113 struct iwm_priv *iwm =
114 container_of(work, struct iwm_priv, disconnect.work);
115
116 if (iwm->umac_profile_active)
117 iwm_invalidate_mlme_profile(iwm);
118
119 clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
120 iwm->umac_profile_active = 0;
121 memset(iwm->bssid, 0, ETH_ALEN);
122 iwm->channel = 0;
123
124 iwm_link_off(iwm);
125
126 wake_up_interruptible(&iwm->mlme_queue);
127
128 cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL);
129}
130
111int __iwm_up(struct iwm_priv *iwm); 131int __iwm_up(struct iwm_priv *iwm);
112int __iwm_down(struct iwm_priv *iwm); 132int __iwm_down(struct iwm_priv *iwm);
113 133
@@ -198,6 +218,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
198 spin_lock_init(&iwm->cmd_lock); 218 spin_lock_init(&iwm->cmd_lock);
199 iwm->scan_id = 1; 219 iwm->scan_id = 1;
200 INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request); 220 INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request);
221 INIT_DELAYED_WORK(&iwm->disconnect, iwm_disconnect_work);
201 INIT_WORK(&iwm->reset_worker, iwm_reset_worker); 222 INIT_WORK(&iwm->reset_worker, iwm_reset_worker);
202 INIT_LIST_HEAD(&iwm->bss_list); 223 INIT_LIST_HEAD(&iwm->bss_list);
203 224
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index 9e6f2cd38d60..4d9793e68650 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -514,6 +514,7 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
514 /* Internal roaming state, avoid notifying SME. */ 514 /* Internal roaming state, avoid notifying SME. */
515 if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status) 515 if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)
516 && iwm->conf.mode == UMAC_MODE_BSS) { 516 && iwm->conf.mode == UMAC_MODE_BSS) {
517 cancel_delayed_work(&iwm->disconnect);
517 cfg80211_roamed(iwm_to_ndev(iwm), 518 cfg80211_roamed(iwm_to_ndev(iwm),
518 complete->bssid, 519 complete->bssid,
519 iwm->req_ie, iwm->req_ie_len, 520 iwm->req_ie, iwm->req_ie_len,
@@ -540,8 +541,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
540 541
541 /* Internal roaming state, avoid notifying SME. */ 542 /* Internal roaming state, avoid notifying SME. */
542 if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status) 543 if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)
543 && iwm->conf.mode == UMAC_MODE_BSS) 544 && iwm->conf.mode == UMAC_MODE_BSS) {
545 cancel_delayed_work(&iwm->disconnect);
544 break; 546 break;
547 }
545 548
546 iwm_link_off(iwm); 549 iwm_link_off(iwm);
547 550
@@ -569,11 +572,18 @@ static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf,
569 struct iwm_wifi_cmd *cmd) 572 struct iwm_wifi_cmd *cmd)
570{ 573{
571 struct iwm_umac_notif_profile_invalidate *invalid; 574 struct iwm_umac_notif_profile_invalidate *invalid;
575 u32 reason;
572 576
573 invalid = (struct iwm_umac_notif_profile_invalidate *)buf; 577 invalid = (struct iwm_umac_notif_profile_invalidate *)buf;
578 reason = le32_to_cpu(invalid->reason);
579
580 IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n", reason);
574 581
575 IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n", 582 if (reason != UMAC_PROFILE_INVALID_REQUEST &&
576 le32_to_cpu(invalid->reason)); 583 test_bit(IWM_STATUS_SME_CONNECTING, &iwm->status))
584 cfg80211_connect_result(iwm_to_ndev(iwm), NULL, NULL, 0, NULL,
585 0, WLAN_STATUS_UNSPECIFIED_FAILURE,
586 GFP_KERNEL);
577 587
578 clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status); 588 clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status);
579 clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); 589 clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
@@ -589,6 +599,19 @@ static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf,
589 return 0; 599 return 0;
590} 600}
591 601
602#define IWM_DISCONNECT_INTERVAL (5 * HZ)
603
604static int iwm_mlme_connection_terminated(struct iwm_priv *iwm, u8 *buf,
605 unsigned long buf_size,
606 struct iwm_wifi_cmd *cmd)
607{
608 IWM_DBG_MLME(iwm, DBG, "Connection terminated\n");
609
610 schedule_delayed_work(&iwm->disconnect, IWM_DISCONNECT_INTERVAL);
611
612 return 0;
613}
614
592static int iwm_mlme_scan_complete(struct iwm_priv *iwm, u8 *buf, 615static int iwm_mlme_scan_complete(struct iwm_priv *iwm, u8 *buf,
593 unsigned long buf_size, 616 unsigned long buf_size,
594 struct iwm_wifi_cmd *cmd) 617 struct iwm_wifi_cmd *cmd)
@@ -848,8 +871,7 @@ static int iwm_ntf_mlme(struct iwm_priv *iwm, u8 *buf,
848 case WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE: 871 case WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE:
849 return iwm_mlme_profile_invalidate(iwm, buf, buf_size, cmd); 872 return iwm_mlme_profile_invalidate(iwm, buf, buf_size, cmd);
850 case WIFI_IF_NTFY_CONNECTION_TERMINATED: 873 case WIFI_IF_NTFY_CONNECTION_TERMINATED:
851 IWM_DBG_MLME(iwm, DBG, "Connection terminated\n"); 874 return iwm_mlme_connection_terminated(iwm, buf, buf_size, cmd);
852 break;
853 case WIFI_IF_NTFY_SCAN_COMPLETE: 875 case WIFI_IF_NTFY_SCAN_COMPLETE:
854 return iwm_mlme_scan_complete(iwm, buf, buf_size, cmd); 876 return iwm_mlme_scan_complete(iwm, buf, buf_size, cmd);
855 case WIFI_IF_NTFY_STA_TABLE_CHANGE: 877 case WIFI_IF_NTFY_STA_TABLE_CHANGE: