diff options
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/core.c | 1 | ||||
-rw-r--r-- | net/wireless/core.h | 30 | ||||
-rw-r--r-- | net/wireless/ibss.c | 6 | ||||
-rw-r--r-- | net/wireless/mlme.c | 191 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 5 | ||||
-rw-r--r-- | net/wireless/sme.c | 542 | ||||
-rw-r--r-- | net/wireless/wext-sme.c | 8 |
7 files changed, 335 insertions, 448 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index f553b9484c1e..221e76b53a97 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -821,7 +821,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
821 | pr_err("failed to add phy80211 symlink to netdev!\n"); | 821 | pr_err("failed to add phy80211 symlink to netdev!\n"); |
822 | } | 822 | } |
823 | wdev->netdev = dev; | 823 | wdev->netdev = dev; |
824 | wdev->sme_state = CFG80211_SME_IDLE; | ||
825 | #ifdef CONFIG_CFG80211_WEXT | 824 | #ifdef CONFIG_CFG80211_WEXT |
826 | wdev->wext.default_key = -1; | 825 | wdev->wext.default_key = -1; |
827 | wdev->wext.default_mgmt_key = -1; | 826 | wdev->wext.default_mgmt_key = -1; |
diff --git a/net/wireless/core.h b/net/wireless/core.h index a65eaf8a84c1..a6b45bf00f33 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -308,11 +308,6 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, | |||
308 | bool local_state_change); | 308 | bool local_state_change); |
309 | void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | 309 | void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, |
310 | struct net_device *dev); | 310 | struct net_device *dev); |
311 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | ||
312 | const u8 *req_ie, size_t req_ie_len, | ||
313 | const u8 *resp_ie, size_t resp_ie_len, | ||
314 | u16 status, bool wextev, | ||
315 | struct cfg80211_bss *bss); | ||
316 | int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, | 311 | int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, |
317 | u16 frame_type, const u8 *match_data, | 312 | u16 frame_type, const u8 *match_data, |
318 | int match_len); | 313 | int match_len); |
@@ -328,12 +323,19 @@ void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, | |||
328 | void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, | 323 | void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, |
329 | const struct ieee80211_vht_cap *vht_capa_mask); | 324 | const struct ieee80211_vht_cap *vht_capa_mask); |
330 | 325 | ||
331 | /* SME */ | 326 | /* SME events */ |
332 | int cfg80211_connect(struct cfg80211_registered_device *rdev, | 327 | int cfg80211_connect(struct cfg80211_registered_device *rdev, |
333 | struct net_device *dev, | 328 | struct net_device *dev, |
334 | struct cfg80211_connect_params *connect, | 329 | struct cfg80211_connect_params *connect, |
335 | struct cfg80211_cached_keys *connkeys, | 330 | struct cfg80211_cached_keys *connkeys, |
336 | const u8 *prev_bssid); | 331 | const u8 *prev_bssid); |
332 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | ||
333 | const u8 *req_ie, size_t req_ie_len, | ||
334 | const u8 *resp_ie, size_t resp_ie_len, | ||
335 | u16 status, bool wextev, | ||
336 | struct cfg80211_bss *bss); | ||
337 | void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | ||
338 | size_t ie_len, u16 reason, bool from_ap); | ||
337 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | 339 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, |
338 | struct net_device *dev, u16 reason, | 340 | struct net_device *dev, u16 reason, |
339 | bool wextev); | 341 | bool wextev); |
@@ -344,21 +346,21 @@ void __cfg80211_roamed(struct wireless_dev *wdev, | |||
344 | int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | 346 | int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, |
345 | struct wireless_dev *wdev); | 347 | struct wireless_dev *wdev); |
346 | 348 | ||
349 | /* SME implementation */ | ||
347 | void cfg80211_conn_work(struct work_struct *work); | 350 | void cfg80211_conn_work(struct work_struct *work); |
348 | void cfg80211_sme_failed_assoc(struct wireless_dev *wdev); | 351 | void cfg80211_sme_scan_done(struct net_device *dev); |
349 | bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev); | 352 | bool cfg80211_sme_rx_assoc_resp(struct wireless_dev *wdev, u16 status); |
353 | void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len); | ||
354 | void cfg80211_sme_disassoc(struct wireless_dev *wdev); | ||
355 | void cfg80211_sme_deauth(struct wireless_dev *wdev); | ||
356 | void cfg80211_sme_auth_timeout(struct wireless_dev *wdev); | ||
357 | void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev); | ||
350 | 358 | ||
351 | /* internal helpers */ | 359 | /* internal helpers */ |
352 | bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher); | 360 | bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher); |
353 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | 361 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, |
354 | struct key_params *params, int key_idx, | 362 | struct key_params *params, int key_idx, |
355 | bool pairwise, const u8 *mac_addr); | 363 | bool pairwise, const u8 *mac_addr); |
356 | void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | ||
357 | size_t ie_len, u16 reason, bool from_ap); | ||
358 | void cfg80211_sme_scan_done(struct net_device *dev); | ||
359 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); | ||
360 | void cfg80211_sme_disassoc(struct net_device *dev, | ||
361 | struct cfg80211_internal_bss *bss); | ||
362 | void __cfg80211_scan_done(struct work_struct *wk); | 364 | void __cfg80211_scan_done(struct work_struct *wk); |
363 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); | 365 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); |
364 | void __cfg80211_sched_scan_results(struct work_struct *wk); | 366 | void __cfg80211_sched_scan_results(struct work_struct *wk); |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 5449c5a6de84..39bff7d36768 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -43,7 +43,6 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) | |||
43 | cfg80211_hold_bss(bss_from_pub(bss)); | 43 | cfg80211_hold_bss(bss_from_pub(bss)); |
44 | wdev->current_bss = bss_from_pub(bss); | 44 | wdev->current_bss = bss_from_pub(bss); |
45 | 45 | ||
46 | wdev->sme_state = CFG80211_SME_CONNECTED; | ||
47 | cfg80211_upload_connect_keys(wdev); | 46 | cfg80211_upload_connect_keys(wdev); |
48 | 47 | ||
49 | nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, | 48 | nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, |
@@ -64,8 +63,6 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) | |||
64 | 63 | ||
65 | trace_cfg80211_ibss_joined(dev, bssid); | 64 | trace_cfg80211_ibss_joined(dev, bssid); |
66 | 65 | ||
67 | CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING); | ||
68 | |||
69 | ev = kzalloc(sizeof(*ev), gfp); | 66 | ev = kzalloc(sizeof(*ev), gfp); |
70 | if (!ev) | 67 | if (!ev) |
71 | return; | 68 | return; |
@@ -120,7 +117,6 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |||
120 | #ifdef CONFIG_CFG80211_WEXT | 117 | #ifdef CONFIG_CFG80211_WEXT |
121 | wdev->wext.ibss.chandef = params->chandef; | 118 | wdev->wext.ibss.chandef = params->chandef; |
122 | #endif | 119 | #endif |
123 | wdev->sme_state = CFG80211_SME_CONNECTING; | ||
124 | 120 | ||
125 | err = cfg80211_can_use_chan(rdev, wdev, params->chandef.chan, | 121 | err = cfg80211_can_use_chan(rdev, wdev, params->chandef.chan, |
126 | params->channel_fixed | 122 | params->channel_fixed |
@@ -134,7 +130,6 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |||
134 | err = rdev_join_ibss(rdev, dev, params); | 130 | err = rdev_join_ibss(rdev, dev, params); |
135 | if (err) { | 131 | if (err) { |
136 | wdev->connect_keys = NULL; | 132 | wdev->connect_keys = NULL; |
137 | wdev->sme_state = CFG80211_SME_IDLE; | ||
138 | return err; | 133 | return err; |
139 | } | 134 | } |
140 | 135 | ||
@@ -186,7 +181,6 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) | |||
186 | } | 181 | } |
187 | 182 | ||
188 | wdev->current_bss = NULL; | 183 | wdev->current_bss = NULL; |
189 | wdev->sme_state = CFG80211_SME_IDLE; | ||
190 | wdev->ssid_len = 0; | 184 | wdev->ssid_len = 0; |
191 | #ifdef CONFIG_CFG80211_WEXT | 185 | #ifdef CONFIG_CFG80211_WEXT |
192 | if (!nowext) | 186 | if (!nowext) |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 4b9c2be0d56d..a61a44bc6cf0 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -21,129 +21,85 @@ | |||
21 | void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss, | 21 | void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss, |
22 | const u8 *buf, size_t len) | 22 | const u8 *buf, size_t len) |
23 | { | 23 | { |
24 | u16 status_code; | ||
25 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 24 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
26 | struct wiphy *wiphy = wdev->wiphy; | 25 | struct wiphy *wiphy = wdev->wiphy; |
27 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 26 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
28 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; | 27 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
29 | u8 *ie = mgmt->u.assoc_resp.variable; | 28 | u8 *ie = mgmt->u.assoc_resp.variable; |
30 | int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); | 29 | int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); |
30 | u16 status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | ||
31 | 31 | ||
32 | trace_cfg80211_send_rx_assoc(dev, bss); | 32 | trace_cfg80211_send_rx_assoc(dev, bss); |
33 | 33 | ||
34 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | ||
35 | |||
36 | /* | 34 | /* |
37 | * This is a bit of a hack, we don't notify userspace of | 35 | * This is a bit of a hack, we don't notify userspace of |
38 | * a (re-)association reply if we tried to send a reassoc | 36 | * a (re-)association reply if we tried to send a reassoc |
39 | * and got a reject -- we only try again with an assoc | 37 | * and got a reject -- we only try again with an assoc |
40 | * frame instead of reassoc. | 38 | * frame instead of reassoc. |
41 | */ | 39 | */ |
42 | if (status_code != WLAN_STATUS_SUCCESS && wdev->conn && | 40 | if (cfg80211_sme_rx_assoc_resp(wdev, status_code)) { |
43 | cfg80211_sme_failed_reassoc(wdev)) { | ||
44 | cfg80211_put_bss(wiphy, bss); | 41 | cfg80211_put_bss(wiphy, bss); |
45 | return; | 42 | return; |
46 | } | 43 | } |
47 | 44 | ||
48 | nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); | 45 | nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); |
49 | 46 | /* update current_bss etc., consumes the bss reference */ | |
50 | if (status_code != WLAN_STATUS_SUCCESS && wdev->conn) { | ||
51 | cfg80211_sme_failed_assoc(wdev); | ||
52 | /* | ||
53 | * do not call connect_result() now because the | ||
54 | * sme will schedule work that does it later. | ||
55 | */ | ||
56 | cfg80211_put_bss(wiphy, bss); | ||
57 | return; | ||
58 | } | ||
59 | |||
60 | if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) { | ||
61 | /* | ||
62 | * This is for the userspace SME, the CONNECTING | ||
63 | * state will be changed to CONNECTED by | ||
64 | * __cfg80211_connect_result() below. | ||
65 | */ | ||
66 | wdev->sme_state = CFG80211_SME_CONNECTING; | ||
67 | } | ||
68 | |||
69 | /* this consumes the bss reference */ | ||
70 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, | 47 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, |
71 | status_code, | 48 | status_code, |
72 | status_code == WLAN_STATUS_SUCCESS, bss); | 49 | status_code == WLAN_STATUS_SUCCESS, bss); |
73 | } | 50 | } |
74 | EXPORT_SYMBOL(cfg80211_rx_assoc_resp); | 51 | EXPORT_SYMBOL(cfg80211_rx_assoc_resp); |
75 | 52 | ||
76 | static void cfg80211_process_deauth(struct net_device *dev, | 53 | static void cfg80211_process_auth(struct wireless_dev *wdev, |
54 | const u8 *buf, size_t len) | ||
55 | { | ||
56 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
57 | |||
58 | nl80211_send_rx_auth(rdev, wdev->netdev, buf, len, GFP_KERNEL); | ||
59 | cfg80211_sme_rx_auth(wdev, buf, len); | ||
60 | } | ||
61 | |||
62 | static void cfg80211_process_deauth(struct wireless_dev *wdev, | ||
77 | const u8 *buf, size_t len) | 63 | const u8 *buf, size_t len) |
78 | { | 64 | { |
79 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 65 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
80 | struct wiphy *wiphy = wdev->wiphy; | ||
81 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
82 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; | 66 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
83 | const u8 *bssid = mgmt->bssid; | 67 | const u8 *bssid = mgmt->bssid; |
84 | bool was_current = false; | 68 | u16 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); |
85 | 69 | bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr); | |
86 | if (wdev->current_bss && | ||
87 | ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) { | ||
88 | cfg80211_unhold_bss(wdev->current_bss); | ||
89 | cfg80211_put_bss(wiphy, &wdev->current_bss->pub); | ||
90 | wdev->current_bss = NULL; | ||
91 | was_current = true; | ||
92 | } | ||
93 | 70 | ||
94 | nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL); | 71 | nl80211_send_deauth(rdev, wdev->netdev, buf, len, GFP_KERNEL); |
95 | 72 | ||
96 | if (wdev->sme_state == CFG80211_SME_CONNECTED && was_current) { | 73 | if (!wdev->current_bss || |
97 | u16 reason_code; | 74 | !ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) |
98 | bool from_ap; | 75 | return; |
99 | |||
100 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); | ||
101 | 76 | ||
102 | from_ap = !ether_addr_equal(mgmt->sa, dev->dev_addr); | 77 | __cfg80211_disconnected(wdev->netdev, NULL, 0, reason_code, from_ap); |
103 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); | 78 | cfg80211_sme_deauth(wdev); |
104 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { | ||
105 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, | ||
106 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
107 | false, NULL); | ||
108 | } | ||
109 | } | 79 | } |
110 | 80 | ||
111 | static void cfg80211_process_disassoc(struct net_device *dev, | 81 | static void cfg80211_process_disassoc(struct wireless_dev *wdev, |
112 | const u8 *buf, size_t len) | 82 | const u8 *buf, size_t len) |
113 | { | 83 | { |
114 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 84 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
115 | struct wiphy *wiphy = wdev->wiphy; | ||
116 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
117 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; | 85 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
118 | const u8 *bssid = mgmt->bssid; | 86 | const u8 *bssid = mgmt->bssid; |
119 | u16 reason_code; | 87 | u16 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); |
120 | bool from_ap; | 88 | bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr); |
121 | 89 | ||
122 | nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL); | 90 | nl80211_send_disassoc(rdev, wdev->netdev, buf, len, GFP_KERNEL); |
123 | 91 | ||
124 | if (wdev->sme_state != CFG80211_SME_CONNECTED) | 92 | if (WARN_ON(!wdev->current_bss || |
93 | !ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) | ||
125 | return; | 94 | return; |
126 | 95 | ||
127 | if (wdev->current_bss && | 96 | __cfg80211_disconnected(wdev->netdev, NULL, 0, reason_code, from_ap); |
128 | ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) { | 97 | cfg80211_sme_disassoc(wdev); |
129 | cfg80211_sme_disassoc(dev, wdev->current_bss); | ||
130 | cfg80211_unhold_bss(wdev->current_bss); | ||
131 | cfg80211_put_bss(wiphy, &wdev->current_bss->pub); | ||
132 | wdev->current_bss = NULL; | ||
133 | } else | ||
134 | WARN_ON(1); | ||
135 | |||
136 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); | ||
137 | |||
138 | from_ap = !ether_addr_equal(mgmt->sa, dev->dev_addr); | ||
139 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); | ||
140 | } | 98 | } |
141 | 99 | ||
142 | void cfg80211_rx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len) | 100 | void cfg80211_rx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len) |
143 | { | 101 | { |
144 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 102 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
145 | struct wiphy *wiphy = wdev->wiphy; | ||
146 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
147 | struct ieee80211_mgmt *mgmt = (void *)buf; | 103 | struct ieee80211_mgmt *mgmt = (void *)buf; |
148 | 104 | ||
149 | ASSERT_WDEV_LOCK(wdev); | 105 | ASSERT_WDEV_LOCK(wdev); |
@@ -153,14 +109,12 @@ void cfg80211_rx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len) | |||
153 | if (WARN_ON(len < 2)) | 109 | if (WARN_ON(len < 2)) |
154 | return; | 110 | return; |
155 | 111 | ||
156 | if (ieee80211_is_auth(mgmt->frame_control)) { | 112 | if (ieee80211_is_auth(mgmt->frame_control)) |
157 | nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL); | 113 | cfg80211_process_auth(wdev, buf, len); |
158 | cfg80211_sme_rx_auth(dev, buf, len); | 114 | else if (ieee80211_is_deauth(mgmt->frame_control)) |
159 | } else if (ieee80211_is_deauth(mgmt->frame_control)) { | 115 | cfg80211_process_deauth(wdev, buf, len); |
160 | cfg80211_process_deauth(dev, buf, len); | 116 | else if (ieee80211_is_disassoc(mgmt->frame_control)) |
161 | } else if (ieee80211_is_disassoc(mgmt->frame_control)) { | 117 | cfg80211_process_disassoc(wdev, buf, len); |
162 | cfg80211_process_disassoc(dev, buf, len); | ||
163 | } | ||
164 | } | 118 | } |
165 | EXPORT_SYMBOL(cfg80211_rx_mlme_mgmt); | 119 | EXPORT_SYMBOL(cfg80211_rx_mlme_mgmt); |
166 | 120 | ||
@@ -173,10 +127,7 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr) | |||
173 | trace_cfg80211_send_auth_timeout(dev, addr); | 127 | trace_cfg80211_send_auth_timeout(dev, addr); |
174 | 128 | ||
175 | nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL); | 129 | nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL); |
176 | if (wdev->sme_state == CFG80211_SME_CONNECTING) | 130 | cfg80211_sme_auth_timeout(wdev); |
177 | __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, | ||
178 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
179 | false, NULL); | ||
180 | } | 131 | } |
181 | EXPORT_SYMBOL(cfg80211_auth_timeout); | 132 | EXPORT_SYMBOL(cfg80211_auth_timeout); |
182 | 133 | ||
@@ -189,10 +140,7 @@ void cfg80211_assoc_timeout(struct net_device *dev, const u8 *addr) | |||
189 | trace_cfg80211_send_assoc_timeout(dev, addr); | 140 | trace_cfg80211_send_assoc_timeout(dev, addr); |
190 | 141 | ||
191 | nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL); | 142 | nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL); |
192 | if (wdev->sme_state == CFG80211_SME_CONNECTING) | 143 | cfg80211_sme_assoc_timeout(wdev); |
193 | __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, | ||
194 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
195 | false, NULL); | ||
196 | } | 144 | } |
197 | EXPORT_SYMBOL(cfg80211_assoc_timeout); | 145 | EXPORT_SYMBOL(cfg80211_assoc_timeout); |
198 | 146 | ||
@@ -209,9 +157,9 @@ void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len) | |||
209 | return; | 157 | return; |
210 | 158 | ||
211 | if (ieee80211_is_deauth(mgmt->frame_control)) | 159 | if (ieee80211_is_deauth(mgmt->frame_control)) |
212 | cfg80211_process_deauth(dev, buf, len); | 160 | cfg80211_process_deauth(wdev, buf, len); |
213 | else | 161 | else |
214 | cfg80211_process_disassoc(dev, buf, len); | 162 | cfg80211_process_disassoc(wdev, buf, len); |
215 | } | 163 | } |
216 | EXPORT_SYMBOL(cfg80211_tx_mlme_mgmt); | 164 | EXPORT_SYMBOL(cfg80211_tx_mlme_mgmt); |
217 | 165 | ||
@@ -336,21 +284,12 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
336 | { | 284 | { |
337 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 285 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
338 | int err; | 286 | int err; |
339 | bool was_connected = false; | ||
340 | 287 | ||
341 | ASSERT_WDEV_LOCK(wdev); | 288 | ASSERT_WDEV_LOCK(wdev); |
342 | 289 | ||
343 | if (wdev->current_bss && req->prev_bssid && | 290 | if (wdev->current_bss && |
344 | ether_addr_equal(wdev->current_bss->pub.bssid, req->prev_bssid)) { | 291 | (!req->prev_bssid || !ether_addr_equal(wdev->current_bss->pub.bssid, |
345 | /* | 292 | req->prev_bssid))) |
346 | * Trying to reassociate: Allow this to proceed and let the old | ||
347 | * association to be dropped when the new one is completed. | ||
348 | */ | ||
349 | if (wdev->sme_state == CFG80211_SME_CONNECTED) { | ||
350 | was_connected = true; | ||
351 | wdev->sme_state = CFG80211_SME_CONNECTING; | ||
352 | } | ||
353 | } else if (wdev->current_bss) | ||
354 | return -EALREADY; | 293 | return -EALREADY; |
355 | 294 | ||
356 | cfg80211_oper_and_ht_capa(&req->ht_capa_mask, | 295 | cfg80211_oper_and_ht_capa(&req->ht_capa_mask, |
@@ -360,11 +299,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
360 | 299 | ||
361 | req->bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, | 300 | req->bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, |
362 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | 301 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); |
363 | if (!req->bss) { | 302 | if (!req->bss) |
364 | if (was_connected) | ||
365 | wdev->sme_state = CFG80211_SME_CONNECTED; | ||
366 | return -ENOENT; | 303 | return -ENOENT; |
367 | } | ||
368 | 304 | ||
369 | err = cfg80211_can_use_chan(rdev, wdev, chan, CHAN_MODE_SHARED); | 305 | err = cfg80211_can_use_chan(rdev, wdev, chan, CHAN_MODE_SHARED); |
370 | if (err) | 306 | if (err) |
@@ -373,11 +309,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
373 | err = rdev_assoc(rdev, dev, req); | 309 | err = rdev_assoc(rdev, dev, req); |
374 | 310 | ||
375 | out: | 311 | out: |
376 | if (err) { | 312 | if (err) |
377 | if (was_connected) | ||
378 | wdev->sme_state = CFG80211_SME_CONNECTED; | ||
379 | cfg80211_put_bss(&rdev->wiphy, req->bss); | 313 | cfg80211_put_bss(&rdev->wiphy, req->bss); |
380 | } | ||
381 | 314 | ||
382 | return err; | 315 | return err; |
383 | } | 316 | } |
@@ -398,8 +331,9 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | |||
398 | 331 | ||
399 | ASSERT_WDEV_LOCK(wdev); | 332 | ASSERT_WDEV_LOCK(wdev); |
400 | 333 | ||
401 | if (local_state_change && (!wdev->current_bss || | 334 | if (local_state_change && |
402 | !ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) | 335 | (!wdev->current_bss || |
336 | !ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) | ||
403 | return 0; | 337 | return 0; |
404 | 338 | ||
405 | return rdev_deauth(rdev, dev, &req); | 339 | return rdev_deauth(rdev, dev, &req); |
@@ -417,13 +351,11 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, | |||
417 | .ie = ie, | 351 | .ie = ie, |
418 | .ie_len = ie_len, | 352 | .ie_len = ie_len, |
419 | }; | 353 | }; |
354 | int err; | ||
420 | 355 | ||
421 | ASSERT_WDEV_LOCK(wdev); | 356 | ASSERT_WDEV_LOCK(wdev); |
422 | 357 | ||
423 | if (wdev->sme_state != CFG80211_SME_CONNECTED) | 358 | if (!wdev->current_bss) |
424 | return -ENOTCONN; | ||
425 | |||
426 | if (WARN(!wdev->current_bss, "sme_state=%d\n", wdev->sme_state)) | ||
427 | return -ENOTCONN; | 359 | return -ENOTCONN; |
428 | 360 | ||
429 | if (ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) | 361 | if (ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) |
@@ -431,7 +363,13 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, | |||
431 | else | 363 | else |
432 | return -ENOTCONN; | 364 | return -ENOTCONN; |
433 | 365 | ||
434 | return rdev_disassoc(rdev, dev, &req); | 366 | err = rdev_disassoc(rdev, dev, &req); |
367 | if (err) | ||
368 | return err; | ||
369 | |||
370 | /* driver should have reported the disassoc */ | ||
371 | WARN_ON(wdev->current_bss); | ||
372 | return 0; | ||
435 | } | 373 | } |
436 | 374 | ||
437 | void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | 375 | void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, |
@@ -439,10 +377,6 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | |||
439 | { | 377 | { |
440 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 378 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
441 | u8 bssid[ETH_ALEN]; | 379 | u8 bssid[ETH_ALEN]; |
442 | struct cfg80211_deauth_request req = { | ||
443 | .reason_code = WLAN_REASON_DEAUTH_LEAVING, | ||
444 | .bssid = bssid, | ||
445 | }; | ||
446 | 380 | ||
447 | ASSERT_WDEV_LOCK(wdev); | 381 | ASSERT_WDEV_LOCK(wdev); |
448 | 382 | ||
@@ -453,13 +387,8 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | |||
453 | return; | 387 | return; |
454 | 388 | ||
455 | memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); | 389 | memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); |
456 | rdev_deauth(rdev, dev, &req); | 390 | cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0, |
457 | 391 | WLAN_REASON_DEAUTH_LEAVING, false); | |
458 | if (wdev->current_bss) { | ||
459 | cfg80211_unhold_bss(wdev->current_bss); | ||
460 | cfg80211_put_bss(&rdev->wiphy, &wdev->current_bss->pub); | ||
461 | wdev->current_bss = NULL; | ||
462 | } | ||
463 | } | 392 | } |
464 | 393 | ||
465 | struct cfg80211_mgmt_registration { | 394 | struct cfg80211_mgmt_registration { |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 444f5effb77f..88e820b73674 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -800,12 +800,9 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) | |||
800 | case NL80211_IFTYPE_MESH_POINT: | 800 | case NL80211_IFTYPE_MESH_POINT: |
801 | break; | 801 | break; |
802 | case NL80211_IFTYPE_ADHOC: | 802 | case NL80211_IFTYPE_ADHOC: |
803 | if (!wdev->current_bss) | ||
804 | return -ENOLINK; | ||
805 | break; | ||
806 | case NL80211_IFTYPE_STATION: | 803 | case NL80211_IFTYPE_STATION: |
807 | case NL80211_IFTYPE_P2P_CLIENT: | 804 | case NL80211_IFTYPE_P2P_CLIENT: |
808 | if (wdev->sme_state != CFG80211_SME_CONNECTED) | 805 | if (!wdev->current_bss) |
809 | return -ENOLINK; | 806 | return -ENOLINK; |
810 | break; | 807 | break; |
811 | default: | 808 | default: |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 81be95f3be74..ae7e2cbf45cb 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -1,5 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * SME code for cfg80211's connect emulation. | 2 | * SME code for cfg80211 |
3 | * both driver SME event handling and the SME implementation | ||
4 | * (for nl80211's connect() and wext) | ||
3 | * | 5 | * |
4 | * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> | 6 | * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> |
5 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | 7 | * Copyright (C) 2009 Intel Corporation. All rights reserved. |
@@ -18,18 +20,24 @@ | |||
18 | #include "reg.h" | 20 | #include "reg.h" |
19 | #include "rdev-ops.h" | 21 | #include "rdev-ops.h" |
20 | 22 | ||
23 | /* | ||
24 | * Software SME in cfg80211, using auth/assoc/deauth calls to the | ||
25 | * driver. This is is for implementing nl80211's connect/disconnect | ||
26 | * and wireless extensions (if configured.) | ||
27 | */ | ||
28 | |||
21 | struct cfg80211_conn { | 29 | struct cfg80211_conn { |
22 | struct cfg80211_connect_params params; | 30 | struct cfg80211_connect_params params; |
23 | /* these are sub-states of the _CONNECTING sme_state */ | 31 | /* these are sub-states of the _CONNECTING sme_state */ |
24 | enum { | 32 | enum { |
25 | CFG80211_CONN_IDLE, | ||
26 | CFG80211_CONN_SCANNING, | 33 | CFG80211_CONN_SCANNING, |
27 | CFG80211_CONN_SCAN_AGAIN, | 34 | CFG80211_CONN_SCAN_AGAIN, |
28 | CFG80211_CONN_AUTHENTICATE_NEXT, | 35 | CFG80211_CONN_AUTHENTICATE_NEXT, |
29 | CFG80211_CONN_AUTHENTICATING, | 36 | CFG80211_CONN_AUTHENTICATING, |
30 | CFG80211_CONN_ASSOCIATE_NEXT, | 37 | CFG80211_CONN_ASSOCIATE_NEXT, |
31 | CFG80211_CONN_ASSOCIATING, | 38 | CFG80211_CONN_ASSOCIATING, |
32 | CFG80211_CONN_DEAUTH_ASSOC_FAIL, | 39 | CFG80211_CONN_DEAUTH, |
40 | CFG80211_CONN_CONNECTED, | ||
33 | } state; | 41 | } state; |
34 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; | 42 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; |
35 | u8 *ie; | 43 | u8 *ie; |
@@ -37,39 +45,16 @@ struct cfg80211_conn { | |||
37 | bool auto_auth, prev_bssid_valid; | 45 | bool auto_auth, prev_bssid_valid; |
38 | }; | 46 | }; |
39 | 47 | ||
40 | static bool cfg80211_is_all_idle(void) | 48 | static void cfg80211_sme_free(struct wireless_dev *wdev) |
41 | { | 49 | { |
42 | struct cfg80211_registered_device *rdev; | 50 | if (!wdev->conn) |
43 | struct wireless_dev *wdev; | 51 | return; |
44 | bool is_all_idle = true; | ||
45 | |||
46 | /* | ||
47 | * All devices must be idle as otherwise if you are actively | ||
48 | * scanning some new beacon hints could be learned and would | ||
49 | * count as new regulatory hints. | ||
50 | */ | ||
51 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | ||
52 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | ||
53 | wdev_lock(wdev); | ||
54 | if (wdev->sme_state != CFG80211_SME_IDLE) | ||
55 | is_all_idle = false; | ||
56 | wdev_unlock(wdev); | ||
57 | } | ||
58 | } | ||
59 | |||
60 | return is_all_idle; | ||
61 | } | ||
62 | 52 | ||
63 | static void disconnect_work(struct work_struct *work) | 53 | kfree(wdev->conn->ie); |
64 | { | 54 | kfree(wdev->conn); |
65 | rtnl_lock(); | 55 | wdev->conn = NULL; |
66 | if (cfg80211_is_all_idle()) | ||
67 | regulatory_hint_disconnect(); | ||
68 | rtnl_unlock(); | ||
69 | } | 56 | } |
70 | 57 | ||
71 | static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work); | ||
72 | |||
73 | static int cfg80211_conn_scan(struct wireless_dev *wdev) | 58 | static int cfg80211_conn_scan(struct wireless_dev *wdev) |
74 | { | 59 | { |
75 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 60 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
@@ -164,6 +149,9 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
164 | params = &wdev->conn->params; | 149 | params = &wdev->conn->params; |
165 | 150 | ||
166 | switch (wdev->conn->state) { | 151 | switch (wdev->conn->state) { |
152 | case CFG80211_CONN_SCANNING: | ||
153 | /* didn't find it during scan ... */ | ||
154 | return -ENOENT; | ||
167 | case CFG80211_CONN_SCAN_AGAIN: | 155 | case CFG80211_CONN_SCAN_AGAIN: |
168 | return cfg80211_conn_scan(wdev); | 156 | return cfg80211_conn_scan(wdev); |
169 | case CFG80211_CONN_AUTHENTICATE_NEXT: | 157 | case CFG80211_CONN_AUTHENTICATE_NEXT: |
@@ -200,12 +188,11 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
200 | WLAN_REASON_DEAUTH_LEAVING, | 188 | WLAN_REASON_DEAUTH_LEAVING, |
201 | false); | 189 | false); |
202 | return err; | 190 | return err; |
203 | case CFG80211_CONN_DEAUTH_ASSOC_FAIL: | 191 | case CFG80211_CONN_DEAUTH: |
204 | cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, | 192 | cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, |
205 | NULL, 0, | 193 | NULL, 0, |
206 | WLAN_REASON_DEAUTH_LEAVING, false); | 194 | WLAN_REASON_DEAUTH_LEAVING, false); |
207 | /* return an error so that we call __cfg80211_connect_result() */ | 195 | return 0; |
208 | return -EINVAL; | ||
209 | default: | 196 | default: |
210 | return 0; | 197 | return 0; |
211 | } | 198 | } |
@@ -229,7 +216,8 @@ void cfg80211_conn_work(struct work_struct *work) | |||
229 | wdev_unlock(wdev); | 216 | wdev_unlock(wdev); |
230 | continue; | 217 | continue; |
231 | } | 218 | } |
232 | if (wdev->sme_state != CFG80211_SME_CONNECTING || !wdev->conn) { | 219 | if (!wdev->conn || |
220 | wdev->conn->state == CFG80211_CONN_CONNECTED) { | ||
233 | wdev_unlock(wdev); | 221 | wdev_unlock(wdev); |
234 | continue; | 222 | continue; |
235 | } | 223 | } |
@@ -237,12 +225,14 @@ void cfg80211_conn_work(struct work_struct *work) | |||
237 | memcpy(bssid_buf, wdev->conn->params.bssid, ETH_ALEN); | 225 | memcpy(bssid_buf, wdev->conn->params.bssid, ETH_ALEN); |
238 | bssid = bssid_buf; | 226 | bssid = bssid_buf; |
239 | } | 227 | } |
240 | if (cfg80211_conn_do_work(wdev)) | 228 | if (cfg80211_conn_do_work(wdev)) { |
241 | __cfg80211_connect_result( | 229 | __cfg80211_connect_result( |
242 | wdev->netdev, bssid, | 230 | wdev->netdev, bssid, |
243 | NULL, 0, NULL, 0, | 231 | NULL, 0, NULL, 0, |
244 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 232 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
245 | false, NULL); | 233 | false, NULL); |
234 | cfg80211_sme_free(wdev); | ||
235 | } | ||
246 | wdev_unlock(wdev); | 236 | wdev_unlock(wdev); |
247 | } | 237 | } |
248 | 238 | ||
@@ -286,9 +276,6 @@ static void __cfg80211_sme_scan_done(struct net_device *dev) | |||
286 | 276 | ||
287 | ASSERT_WDEV_LOCK(wdev); | 277 | ASSERT_WDEV_LOCK(wdev); |
288 | 278 | ||
289 | if (wdev->sme_state != CFG80211_SME_CONNECTING) | ||
290 | return; | ||
291 | |||
292 | if (!wdev->conn) | 279 | if (!wdev->conn) |
293 | return; | 280 | return; |
294 | 281 | ||
@@ -297,20 +284,10 @@ static void __cfg80211_sme_scan_done(struct net_device *dev) | |||
297 | return; | 284 | return; |
298 | 285 | ||
299 | bss = cfg80211_get_conn_bss(wdev); | 286 | bss = cfg80211_get_conn_bss(wdev); |
300 | if (bss) { | 287 | if (bss) |
301 | cfg80211_put_bss(&rdev->wiphy, bss); | 288 | cfg80211_put_bss(&rdev->wiphy, bss); |
302 | } else { | 289 | else |
303 | /* not found */ | 290 | schedule_work(&rdev->conn_work); |
304 | if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) | ||
305 | schedule_work(&rdev->conn_work); | ||
306 | else | ||
307 | __cfg80211_connect_result( | ||
308 | wdev->netdev, | ||
309 | wdev->conn->params.bssid, | ||
310 | NULL, 0, NULL, 0, | ||
311 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
312 | false, NULL); | ||
313 | } | ||
314 | } | 291 | } |
315 | 292 | ||
316 | void cfg80211_sme_scan_done(struct net_device *dev) | 293 | void cfg80211_sme_scan_done(struct net_device *dev) |
@@ -322,10 +299,8 @@ void cfg80211_sme_scan_done(struct net_device *dev) | |||
322 | wdev_unlock(wdev); | 299 | wdev_unlock(wdev); |
323 | } | 300 | } |
324 | 301 | ||
325 | void cfg80211_sme_rx_auth(struct net_device *dev, | 302 | void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len) |
326 | const u8 *buf, size_t len) | ||
327 | { | 303 | { |
328 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
329 | struct wiphy *wiphy = wdev->wiphy; | 304 | struct wiphy *wiphy = wdev->wiphy; |
330 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 305 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
331 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; | 306 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
@@ -333,11 +308,7 @@ void cfg80211_sme_rx_auth(struct net_device *dev, | |||
333 | 308 | ||
334 | ASSERT_WDEV_LOCK(wdev); | 309 | ASSERT_WDEV_LOCK(wdev); |
335 | 310 | ||
336 | /* should only RX auth frames when connecting */ | 311 | if (!wdev->conn || wdev->conn->state == CFG80211_CONN_CONNECTED) |
337 | if (wdev->sme_state != CFG80211_SME_CONNECTING) | ||
338 | return; | ||
339 | |||
340 | if (WARN_ON(!wdev->conn)) | ||
341 | return; | 312 | return; |
342 | 313 | ||
343 | if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG && | 314 | if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG && |
@@ -366,46 +337,226 @@ void cfg80211_sme_rx_auth(struct net_device *dev, | |||
366 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; | 337 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; |
367 | schedule_work(&rdev->conn_work); | 338 | schedule_work(&rdev->conn_work); |
368 | } else if (status_code != WLAN_STATUS_SUCCESS) { | 339 | } else if (status_code != WLAN_STATUS_SUCCESS) { |
369 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, | 340 | __cfg80211_connect_result(wdev->netdev, mgmt->bssid, |
341 | NULL, 0, NULL, 0, | ||
370 | status_code, false, NULL); | 342 | status_code, false, NULL); |
371 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING && | 343 | } else if (wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { |
372 | wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { | ||
373 | wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; | 344 | wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; |
374 | schedule_work(&rdev->conn_work); | 345 | schedule_work(&rdev->conn_work); |
375 | } | 346 | } |
376 | } | 347 | } |
377 | 348 | ||
378 | bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev) | 349 | bool cfg80211_sme_rx_assoc_resp(struct wireless_dev *wdev, u16 status) |
379 | { | 350 | { |
380 | struct wiphy *wiphy = wdev->wiphy; | 351 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
381 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
382 | 352 | ||
383 | if (WARN_ON(!wdev->conn)) | 353 | if (!wdev->conn) |
384 | return false; | 354 | return false; |
385 | 355 | ||
386 | if (!wdev->conn->prev_bssid_valid) | 356 | if (status == WLAN_STATUS_SUCCESS) { |
357 | wdev->conn->state = CFG80211_CONN_CONNECTED; | ||
387 | return false; | 358 | return false; |
359 | } | ||
388 | 360 | ||
389 | /* | 361 | if (wdev->conn->prev_bssid_valid) { |
390 | * Some stupid APs don't accept reassoc, so we | 362 | /* |
391 | * need to fall back to trying regular assoc. | 363 | * Some stupid APs don't accept reassoc, so we |
392 | */ | 364 | * need to fall back to trying regular assoc; |
393 | wdev->conn->prev_bssid_valid = false; | 365 | * return true so no event is sent to userspace. |
394 | wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; | 366 | */ |
367 | wdev->conn->prev_bssid_valid = false; | ||
368 | wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; | ||
369 | schedule_work(&rdev->conn_work); | ||
370 | return true; | ||
371 | } | ||
372 | |||
373 | wdev->conn->state = CFG80211_CONN_DEAUTH; | ||
395 | schedule_work(&rdev->conn_work); | 374 | schedule_work(&rdev->conn_work); |
375 | return false; | ||
376 | } | ||
396 | 377 | ||
397 | return true; | 378 | void cfg80211_sme_deauth(struct wireless_dev *wdev) |
379 | { | ||
380 | cfg80211_sme_free(wdev); | ||
398 | } | 381 | } |
399 | 382 | ||
400 | void cfg80211_sme_failed_assoc(struct wireless_dev *wdev) | 383 | void cfg80211_sme_auth_timeout(struct wireless_dev *wdev) |
401 | { | 384 | { |
402 | struct wiphy *wiphy = wdev->wiphy; | 385 | cfg80211_sme_free(wdev); |
403 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 386 | } |
404 | 387 | ||
405 | wdev->conn->state = CFG80211_CONN_DEAUTH_ASSOC_FAIL; | 388 | void cfg80211_sme_disassoc(struct wireless_dev *wdev) |
389 | { | ||
390 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
391 | |||
392 | if (!wdev->conn) | ||
393 | return; | ||
394 | |||
395 | wdev->conn->state = CFG80211_CONN_DEAUTH; | ||
406 | schedule_work(&rdev->conn_work); | 396 | schedule_work(&rdev->conn_work); |
407 | } | 397 | } |
408 | 398 | ||
399 | void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev) | ||
400 | { | ||
401 | cfg80211_sme_disassoc(wdev); | ||
402 | } | ||
403 | |||
404 | static int cfg80211_sme_connect(struct wireless_dev *wdev, | ||
405 | struct cfg80211_connect_params *connect, | ||
406 | const u8 *prev_bssid) | ||
407 | { | ||
408 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
409 | struct cfg80211_bss *bss; | ||
410 | int err; | ||
411 | |||
412 | if (!rdev->ops->auth || !rdev->ops->assoc) | ||
413 | return -EOPNOTSUPP; | ||
414 | |||
415 | if (wdev->current_bss) | ||
416 | return -EALREADY; | ||
417 | |||
418 | if (WARN_ON(wdev->conn)) | ||
419 | return -EINPROGRESS; | ||
420 | |||
421 | wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL); | ||
422 | if (!wdev->conn) | ||
423 | return -ENOMEM; | ||
424 | |||
425 | /* | ||
426 | * Copy all parameters, and treat explicitly IEs, BSSID, SSID. | ||
427 | */ | ||
428 | memcpy(&wdev->conn->params, connect, sizeof(*connect)); | ||
429 | if (connect->bssid) { | ||
430 | wdev->conn->params.bssid = wdev->conn->bssid; | ||
431 | memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN); | ||
432 | } | ||
433 | |||
434 | if (connect->ie) { | ||
435 | wdev->conn->ie = kmemdup(connect->ie, connect->ie_len, | ||
436 | GFP_KERNEL); | ||
437 | wdev->conn->params.ie = wdev->conn->ie; | ||
438 | if (!wdev->conn->ie) { | ||
439 | kfree(wdev->conn); | ||
440 | wdev->conn = NULL; | ||
441 | return -ENOMEM; | ||
442 | } | ||
443 | } | ||
444 | |||
445 | if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) { | ||
446 | wdev->conn->auto_auth = true; | ||
447 | /* start with open system ... should mostly work */ | ||
448 | wdev->conn->params.auth_type = | ||
449 | NL80211_AUTHTYPE_OPEN_SYSTEM; | ||
450 | } else { | ||
451 | wdev->conn->auto_auth = false; | ||
452 | } | ||
453 | |||
454 | wdev->conn->params.ssid = wdev->ssid; | ||
455 | wdev->conn->params.ssid_len = connect->ssid_len; | ||
456 | |||
457 | /* see if we have the bss already */ | ||
458 | bss = cfg80211_get_conn_bss(wdev); | ||
459 | |||
460 | if (prev_bssid) { | ||
461 | memcpy(wdev->conn->prev_bssid, prev_bssid, ETH_ALEN); | ||
462 | wdev->conn->prev_bssid_valid = true; | ||
463 | } | ||
464 | |||
465 | /* we're good if we have a matching bss struct */ | ||
466 | if (bss) { | ||
467 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; | ||
468 | err = cfg80211_conn_do_work(wdev); | ||
469 | cfg80211_put_bss(wdev->wiphy, bss); | ||
470 | } else { | ||
471 | /* otherwise we'll need to scan for the AP first */ | ||
472 | err = cfg80211_conn_scan(wdev); | ||
473 | |||
474 | /* | ||
475 | * If we can't scan right now, then we need to scan again | ||
476 | * after the current scan finished, since the parameters | ||
477 | * changed (unless we find a good AP anyway). | ||
478 | */ | ||
479 | if (err == -EBUSY) { | ||
480 | err = 0; | ||
481 | wdev->conn->state = CFG80211_CONN_SCAN_AGAIN; | ||
482 | } | ||
483 | } | ||
484 | |||
485 | if (err) | ||
486 | cfg80211_sme_free(wdev); | ||
487 | |||
488 | return err; | ||
489 | } | ||
490 | |||
491 | static int cfg80211_sme_disconnect(struct wireless_dev *wdev, u16 reason) | ||
492 | { | ||
493 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
494 | int err; | ||
495 | |||
496 | if (!wdev->conn) | ||
497 | return 0; | ||
498 | |||
499 | if (!rdev->ops->deauth) | ||
500 | return -EOPNOTSUPP; | ||
501 | |||
502 | if (wdev->conn->state == CFG80211_CONN_SCANNING || | ||
503 | wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) { | ||
504 | err = 0; | ||
505 | goto out; | ||
506 | } | ||
507 | |||
508 | /* wdev->conn->params.bssid must be set if > SCANNING */ | ||
509 | err = cfg80211_mlme_deauth(rdev, wdev->netdev, | ||
510 | wdev->conn->params.bssid, | ||
511 | NULL, 0, reason, false); | ||
512 | out: | ||
513 | cfg80211_sme_free(wdev); | ||
514 | return err; | ||
515 | } | ||
516 | |||
517 | /* | ||
518 | * code shared for in-device and software SME | ||
519 | */ | ||
520 | |||
521 | static bool cfg80211_is_all_idle(void) | ||
522 | { | ||
523 | struct cfg80211_registered_device *rdev; | ||
524 | struct wireless_dev *wdev; | ||
525 | bool is_all_idle = true; | ||
526 | |||
527 | /* | ||
528 | * All devices must be idle as otherwise if you are actively | ||
529 | * scanning some new beacon hints could be learned and would | ||
530 | * count as new regulatory hints. | ||
531 | */ | ||
532 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | ||
533 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | ||
534 | wdev_lock(wdev); | ||
535 | if (wdev->conn || wdev->current_bss) | ||
536 | is_all_idle = false; | ||
537 | wdev_unlock(wdev); | ||
538 | } | ||
539 | } | ||
540 | |||
541 | return is_all_idle; | ||
542 | } | ||
543 | |||
544 | static void disconnect_work(struct work_struct *work) | ||
545 | { | ||
546 | rtnl_lock(); | ||
547 | if (cfg80211_is_all_idle()) | ||
548 | regulatory_hint_disconnect(); | ||
549 | rtnl_unlock(); | ||
550 | } | ||
551 | |||
552 | static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work); | ||
553 | |||
554 | |||
555 | /* | ||
556 | * API calls for drivers implementing connect/disconnect and | ||
557 | * SME event handling | ||
558 | */ | ||
559 | |||
409 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | 560 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, |
410 | const u8 *req_ie, size_t req_ie_len, | 561 | const u8 *req_ie, size_t req_ie_len, |
411 | const u8 *resp_ie, size_t resp_ie_len, | 562 | const u8 *resp_ie, size_t resp_ie_len, |
@@ -424,9 +575,6 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
424 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) | 575 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) |
425 | return; | 576 | return; |
426 | 577 | ||
427 | if (wdev->sme_state != CFG80211_SME_CONNECTING) | ||
428 | return; | ||
429 | |||
430 | nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, | 578 | nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, |
431 | bssid, req_ie, req_ie_len, | 579 | bssid, req_ie, req_ie_len, |
432 | resp_ie, resp_ie_len, | 580 | resp_ie, resp_ie_len, |
@@ -463,15 +611,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
463 | wdev->current_bss = NULL; | 611 | wdev->current_bss = NULL; |
464 | } | 612 | } |
465 | 613 | ||
466 | if (wdev->conn) | ||
467 | wdev->conn->state = CFG80211_CONN_IDLE; | ||
468 | |||
469 | if (status != WLAN_STATUS_SUCCESS) { | 614 | if (status != WLAN_STATUS_SUCCESS) { |
470 | wdev->sme_state = CFG80211_SME_IDLE; | ||
471 | if (wdev->conn) | ||
472 | kfree(wdev->conn->ie); | ||
473 | kfree(wdev->conn); | ||
474 | wdev->conn = NULL; | ||
475 | kfree(wdev->connect_keys); | 615 | kfree(wdev->connect_keys); |
476 | wdev->connect_keys = NULL; | 616 | wdev->connect_keys = NULL; |
477 | wdev->ssid_len = 0; | 617 | wdev->ssid_len = 0; |
@@ -480,21 +620,16 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
480 | } | 620 | } |
481 | 621 | ||
482 | if (!bss) | 622 | if (!bss) |
483 | bss = cfg80211_get_bss(wdev->wiphy, | 623 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, |
484 | wdev->conn ? wdev->conn->params.channel : | ||
485 | NULL, | ||
486 | bssid, | ||
487 | wdev->ssid, wdev->ssid_len, | 624 | wdev->ssid, wdev->ssid_len, |
488 | WLAN_CAPABILITY_ESS, | 625 | WLAN_CAPABILITY_ESS, |
489 | WLAN_CAPABILITY_ESS); | 626 | WLAN_CAPABILITY_ESS); |
490 | |||
491 | if (WARN_ON(!bss)) | 627 | if (WARN_ON(!bss)) |
492 | return; | 628 | return; |
493 | 629 | ||
494 | cfg80211_hold_bss(bss_from_pub(bss)); | 630 | cfg80211_hold_bss(bss_from_pub(bss)); |
495 | wdev->current_bss = bss_from_pub(bss); | 631 | wdev->current_bss = bss_from_pub(bss); |
496 | 632 | ||
497 | wdev->sme_state = CFG80211_SME_CONNECTED; | ||
498 | cfg80211_upload_connect_keys(wdev); | 633 | cfg80211_upload_connect_keys(wdev); |
499 | 634 | ||
500 | rcu_read_lock(); | 635 | rcu_read_lock(); |
@@ -530,8 +665,6 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
530 | struct cfg80211_event *ev; | 665 | struct cfg80211_event *ev; |
531 | unsigned long flags; | 666 | unsigned long flags; |
532 | 667 | ||
533 | CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING); | ||
534 | |||
535 | ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); | 668 | ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); |
536 | if (!ev) | 669 | if (!ev) |
537 | return; | 670 | return; |
@@ -572,13 +705,8 @@ void __cfg80211_roamed(struct wireless_dev *wdev, | |||
572 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) | 705 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) |
573 | goto out; | 706 | goto out; |
574 | 707 | ||
575 | if (wdev->sme_state != CFG80211_SME_CONNECTED) | 708 | if (WARN_ON(!wdev->current_bss)) |
576 | goto out; | ||
577 | |||
578 | /* internal error -- how did we get to CONNECTED w/o BSS? */ | ||
579 | if (WARN_ON(!wdev->current_bss)) { | ||
580 | goto out; | 709 | goto out; |
581 | } | ||
582 | 710 | ||
583 | cfg80211_unhold_bss(wdev->current_bss); | 711 | cfg80211_unhold_bss(wdev->current_bss); |
584 | cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); | 712 | cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); |
@@ -628,8 +756,6 @@ void cfg80211_roamed(struct net_device *dev, | |||
628 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 756 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
629 | struct cfg80211_bss *bss; | 757 | struct cfg80211_bss *bss; |
630 | 758 | ||
631 | CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED); | ||
632 | |||
633 | bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid, | 759 | bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid, |
634 | wdev->ssid_len, WLAN_CAPABILITY_ESS, | 760 | wdev->ssid_len, WLAN_CAPABILITY_ESS, |
635 | WLAN_CAPABILITY_ESS); | 761 | WLAN_CAPABILITY_ESS); |
@@ -651,8 +777,6 @@ void cfg80211_roamed_bss(struct net_device *dev, | |||
651 | struct cfg80211_event *ev; | 777 | struct cfg80211_event *ev; |
652 | unsigned long flags; | 778 | unsigned long flags; |
653 | 779 | ||
654 | CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED); | ||
655 | |||
656 | if (WARN_ON(!bss)) | 780 | if (WARN_ON(!bss)) |
657 | return; | 781 | return; |
658 | 782 | ||
@@ -694,25 +818,14 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | |||
694 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) | 818 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) |
695 | return; | 819 | return; |
696 | 820 | ||
697 | if (wdev->sme_state != CFG80211_SME_CONNECTED) | ||
698 | return; | ||
699 | |||
700 | if (wdev->current_bss) { | 821 | if (wdev->current_bss) { |
701 | cfg80211_unhold_bss(wdev->current_bss); | 822 | cfg80211_unhold_bss(wdev->current_bss); |
702 | cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); | 823 | cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); |
703 | } | 824 | } |
704 | 825 | ||
705 | wdev->current_bss = NULL; | 826 | wdev->current_bss = NULL; |
706 | wdev->sme_state = CFG80211_SME_IDLE; | ||
707 | wdev->ssid_len = 0; | 827 | wdev->ssid_len = 0; |
708 | 828 | ||
709 | if (wdev->conn) { | ||
710 | kfree(wdev->conn->ie); | ||
711 | wdev->conn->ie = NULL; | ||
712 | kfree(wdev->conn); | ||
713 | wdev->conn = NULL; | ||
714 | } | ||
715 | |||
716 | nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); | 829 | nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); |
717 | 830 | ||
718 | /* | 831 | /* |
@@ -741,8 +854,6 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason, | |||
741 | struct cfg80211_event *ev; | 854 | struct cfg80211_event *ev; |
742 | unsigned long flags; | 855 | unsigned long flags; |
743 | 856 | ||
744 | CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED); | ||
745 | |||
746 | ev = kzalloc(sizeof(*ev) + ie_len, gfp); | 857 | ev = kzalloc(sizeof(*ev) + ie_len, gfp); |
747 | if (!ev) | 858 | if (!ev) |
748 | return; | 859 | return; |
@@ -760,6 +871,9 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason, | |||
760 | } | 871 | } |
761 | EXPORT_SYMBOL(cfg80211_disconnected); | 872 | EXPORT_SYMBOL(cfg80211_disconnected); |
762 | 873 | ||
874 | /* | ||
875 | * API calls for nl80211/wext compatibility code | ||
876 | */ | ||
763 | int cfg80211_connect(struct cfg80211_registered_device *rdev, | 877 | int cfg80211_connect(struct cfg80211_registered_device *rdev, |
764 | struct net_device *dev, | 878 | struct net_device *dev, |
765 | struct cfg80211_connect_params *connect, | 879 | struct cfg80211_connect_params *connect, |
@@ -767,14 +881,10 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
767 | const u8 *prev_bssid) | 881 | const u8 *prev_bssid) |
768 | { | 882 | { |
769 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 883 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
770 | struct cfg80211_bss *bss = NULL; | ||
771 | int err; | 884 | int err; |
772 | 885 | ||
773 | ASSERT_WDEV_LOCK(wdev); | 886 | ASSERT_WDEV_LOCK(wdev); |
774 | 887 | ||
775 | if (wdev->sme_state != CFG80211_SME_IDLE) | ||
776 | return -EALREADY; | ||
777 | |||
778 | if (WARN_ON(wdev->connect_keys)) { | 888 | if (WARN_ON(wdev->connect_keys)) { |
779 | kfree(wdev->connect_keys); | 889 | kfree(wdev->connect_keys); |
780 | wdev->connect_keys = NULL; | 890 | wdev->connect_keys = NULL; |
@@ -810,105 +920,22 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
810 | } | 920 | } |
811 | } | 921 | } |
812 | 922 | ||
813 | if (!rdev->ops->connect) { | 923 | wdev->connect_keys = connkeys; |
814 | if (!rdev->ops->auth || !rdev->ops->assoc) | 924 | memcpy(wdev->ssid, connect->ssid, connect->ssid_len); |
815 | return -EOPNOTSUPP; | 925 | wdev->ssid_len = connect->ssid_len; |
816 | |||
817 | if (WARN_ON(wdev->conn)) | ||
818 | return -EINPROGRESS; | ||
819 | |||
820 | wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL); | ||
821 | if (!wdev->conn) | ||
822 | return -ENOMEM; | ||
823 | |||
824 | /* | ||
825 | * Copy all parameters, and treat explicitly IEs, BSSID, SSID. | ||
826 | */ | ||
827 | memcpy(&wdev->conn->params, connect, sizeof(*connect)); | ||
828 | if (connect->bssid) { | ||
829 | wdev->conn->params.bssid = wdev->conn->bssid; | ||
830 | memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN); | ||
831 | } | ||
832 | 926 | ||
833 | if (connect->ie) { | 927 | if (!rdev->ops->connect) |
834 | wdev->conn->ie = kmemdup(connect->ie, connect->ie_len, | 928 | err = cfg80211_sme_connect(wdev, connect, prev_bssid); |
835 | GFP_KERNEL); | 929 | else |
836 | wdev->conn->params.ie = wdev->conn->ie; | ||
837 | if (!wdev->conn->ie) { | ||
838 | kfree(wdev->conn); | ||
839 | wdev->conn = NULL; | ||
840 | return -ENOMEM; | ||
841 | } | ||
842 | } | ||
843 | |||
844 | if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) { | ||
845 | wdev->conn->auto_auth = true; | ||
846 | /* start with open system ... should mostly work */ | ||
847 | wdev->conn->params.auth_type = | ||
848 | NL80211_AUTHTYPE_OPEN_SYSTEM; | ||
849 | } else { | ||
850 | wdev->conn->auto_auth = false; | ||
851 | } | ||
852 | |||
853 | memcpy(wdev->ssid, connect->ssid, connect->ssid_len); | ||
854 | wdev->ssid_len = connect->ssid_len; | ||
855 | wdev->conn->params.ssid = wdev->ssid; | ||
856 | wdev->conn->params.ssid_len = connect->ssid_len; | ||
857 | |||
858 | /* see if we have the bss already */ | ||
859 | bss = cfg80211_get_conn_bss(wdev); | ||
860 | |||
861 | wdev->sme_state = CFG80211_SME_CONNECTING; | ||
862 | wdev->connect_keys = connkeys; | ||
863 | |||
864 | if (prev_bssid) { | ||
865 | memcpy(wdev->conn->prev_bssid, prev_bssid, ETH_ALEN); | ||
866 | wdev->conn->prev_bssid_valid = true; | ||
867 | } | ||
868 | |||
869 | /* we're good if we have a matching bss struct */ | ||
870 | if (bss) { | ||
871 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; | ||
872 | err = cfg80211_conn_do_work(wdev); | ||
873 | cfg80211_put_bss(wdev->wiphy, bss); | ||
874 | } else { | ||
875 | /* otherwise we'll need to scan for the AP first */ | ||
876 | err = cfg80211_conn_scan(wdev); | ||
877 | /* | ||
878 | * If we can't scan right now, then we need to scan again | ||
879 | * after the current scan finished, since the parameters | ||
880 | * changed (unless we find a good AP anyway). | ||
881 | */ | ||
882 | if (err == -EBUSY) { | ||
883 | err = 0; | ||
884 | wdev->conn->state = CFG80211_CONN_SCAN_AGAIN; | ||
885 | } | ||
886 | } | ||
887 | if (err) { | ||
888 | kfree(wdev->conn->ie); | ||
889 | kfree(wdev->conn); | ||
890 | wdev->conn = NULL; | ||
891 | wdev->sme_state = CFG80211_SME_IDLE; | ||
892 | wdev->connect_keys = NULL; | ||
893 | wdev->ssid_len = 0; | ||
894 | } | ||
895 | |||
896 | return err; | ||
897 | } else { | ||
898 | wdev->sme_state = CFG80211_SME_CONNECTING; | ||
899 | wdev->connect_keys = connkeys; | ||
900 | err = rdev_connect(rdev, dev, connect); | 930 | err = rdev_connect(rdev, dev, connect); |
901 | if (err) { | ||
902 | wdev->connect_keys = NULL; | ||
903 | wdev->sme_state = CFG80211_SME_IDLE; | ||
904 | return err; | ||
905 | } | ||
906 | 931 | ||
907 | memcpy(wdev->ssid, connect->ssid, connect->ssid_len); | 932 | if (err) { |
908 | wdev->ssid_len = connect->ssid_len; | 933 | wdev->connect_keys = NULL; |
909 | 934 | wdev->ssid_len = 0; | |
910 | return 0; | 935 | return err; |
911 | } | 936 | } |
937 | |||
938 | return 0; | ||
912 | } | 939 | } |
913 | 940 | ||
914 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | 941 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, |
@@ -919,78 +946,17 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | |||
919 | 946 | ||
920 | ASSERT_WDEV_LOCK(wdev); | 947 | ASSERT_WDEV_LOCK(wdev); |
921 | 948 | ||
922 | if (wdev->sme_state == CFG80211_SME_IDLE) | ||
923 | return -EINVAL; | ||
924 | |||
925 | kfree(wdev->connect_keys); | 949 | kfree(wdev->connect_keys); |
926 | wdev->connect_keys = NULL; | 950 | wdev->connect_keys = NULL; |
927 | 951 | ||
928 | if (!rdev->ops->disconnect) { | 952 | if (wdev->conn) { |
929 | if (!rdev->ops->deauth) | 953 | err = cfg80211_sme_disconnect(wdev, reason); |
930 | return -EOPNOTSUPP; | 954 | } else if (!rdev->ops->disconnect) { |
931 | 955 | cfg80211_mlme_down(rdev, dev); | |
932 | /* was it connected by userspace SME? */ | 956 | err = 0; |
933 | if (!wdev->conn) { | ||
934 | cfg80211_mlme_down(rdev, dev); | ||
935 | goto disconnect; | ||
936 | } | ||
937 | |||
938 | if (wdev->sme_state == CFG80211_SME_CONNECTING && | ||
939 | (wdev->conn->state == CFG80211_CONN_SCANNING || | ||
940 | wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) { | ||
941 | wdev->sme_state = CFG80211_SME_IDLE; | ||
942 | kfree(wdev->conn->ie); | ||
943 | kfree(wdev->conn); | ||
944 | wdev->conn = NULL; | ||
945 | wdev->ssid_len = 0; | ||
946 | return 0; | ||
947 | } | ||
948 | |||
949 | /* wdev->conn->params.bssid must be set if > SCANNING */ | ||
950 | err = cfg80211_mlme_deauth(rdev, dev, | ||
951 | wdev->conn->params.bssid, | ||
952 | NULL, 0, reason, false); | ||
953 | if (err) | ||
954 | return err; | ||
955 | } else { | 957 | } else { |
956 | err = rdev_disconnect(rdev, dev, reason); | 958 | err = rdev_disconnect(rdev, dev, reason); |
957 | if (err) | ||
958 | return err; | ||
959 | } | 959 | } |
960 | 960 | ||
961 | disconnect: | 961 | return err; |
962 | if (wdev->sme_state == CFG80211_SME_CONNECTED) | ||
963 | __cfg80211_disconnected(dev, NULL, 0, 0, false); | ||
964 | else if (wdev->sme_state == CFG80211_SME_CONNECTING) | ||
965 | __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0, | ||
966 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
967 | wextev, NULL); | ||
968 | |||
969 | return 0; | ||
970 | } | ||
971 | |||
972 | void cfg80211_sme_disassoc(struct net_device *dev, | ||
973 | struct cfg80211_internal_bss *bss) | ||
974 | { | ||
975 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
976 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
977 | u8 bssid[ETH_ALEN]; | ||
978 | |||
979 | ASSERT_WDEV_LOCK(wdev); | ||
980 | |||
981 | if (!wdev->conn) | ||
982 | return; | ||
983 | |||
984 | if (wdev->conn->state == CFG80211_CONN_IDLE) | ||
985 | return; | ||
986 | |||
987 | /* | ||
988 | * Ok, so the association was made by this SME -- we don't | ||
989 | * want it any more so deauthenticate too. | ||
990 | */ | ||
991 | |||
992 | memcpy(bssid, bss->pub.bssid, ETH_ALEN); | ||
993 | |||
994 | cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0, | ||
995 | WLAN_REASON_DEAUTH_LEAVING, false); | ||
996 | } | 962 | } |
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index a53f8404f451..14c9a2583ba0 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c | |||
@@ -89,7 +89,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, | |||
89 | 89 | ||
90 | wdev_lock(wdev); | 90 | wdev_lock(wdev); |
91 | 91 | ||
92 | if (wdev->sme_state != CFG80211_SME_IDLE) { | 92 | if (wdev->conn) { |
93 | bool event = true; | 93 | bool event = true; |
94 | 94 | ||
95 | if (wdev->wext.connect.channel == chan) { | 95 | if (wdev->wext.connect.channel == chan) { |
@@ -188,7 +188,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, | |||
188 | 188 | ||
189 | err = 0; | 189 | err = 0; |
190 | 190 | ||
191 | if (wdev->sme_state != CFG80211_SME_IDLE) { | 191 | if (wdev->conn) { |
192 | bool event = true; | 192 | bool event = true; |
193 | 193 | ||
194 | if (wdev->wext.connect.ssid && len && | 194 | if (wdev->wext.connect.ssid && len && |
@@ -277,7 +277,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, | |||
277 | 277 | ||
278 | wdev_lock(wdev); | 278 | wdev_lock(wdev); |
279 | 279 | ||
280 | if (wdev->sme_state != CFG80211_SME_IDLE) { | 280 | if (wdev->conn) { |
281 | err = 0; | 281 | err = 0; |
282 | /* both automatic */ | 282 | /* both automatic */ |
283 | if (!bssid && !wdev->wext.connect.bssid) | 283 | if (!bssid && !wdev->wext.connect.bssid) |
@@ -364,7 +364,7 @@ int cfg80211_wext_siwgenie(struct net_device *dev, | |||
364 | wdev->wext.ie = ie; | 364 | wdev->wext.ie = ie; |
365 | wdev->wext.ie_len = ie_len; | 365 | wdev->wext.ie_len = ie_len; |
366 | 366 | ||
367 | if (wdev->sme_state != CFG80211_SME_IDLE) { | 367 | if (wdev->conn) { |
368 | err = cfg80211_disconnect(rdev, dev, | 368 | err = cfg80211_disconnect(rdev, dev, |
369 | WLAN_REASON_DEAUTH_LEAVING, false); | 369 | WLAN_REASON_DEAUTH_LEAVING, false); |
370 | if (err) | 370 | if (err) |