aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/mlme.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-09-14 13:37:28 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-14 13:37:28 -0400
commitd7e9660ad9d5e0845f52848bce31bcf5cdcdea6b (patch)
treec6c67d145771187b194d79d603742b31090a59d6 /net/wireless/mlme.c
parentb8cb48aae1b8c50b37dcb7710363aa69a7a0d9ca (diff)
parent13af7a6ea502fcdd4c0e3d7de6e332b102309491 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1623 commits) netxen: update copyright netxen: fix tx timeout recovery netxen: fix file firmware leak netxen: improve pci memory access netxen: change firmware write size tg3: Fix return ring size breakage netxen: build fix for INET=n cdc-phonet: autoconfigure Phonet address Phonet: back-end for autoconfigured addresses Phonet: fix netlink address dump error handling ipv6: Add IFA_F_DADFAILED flag net: Add DEVTYPE support for Ethernet based devices mv643xx_eth.c: remove unused txq_set_wrr() ucc_geth: Fix hangs after switching from full to half duplex ucc_geth: Rearrange some code to avoid forward declarations phy/marvell: Make non-aneg speed/duplex forcing work for 88E1111 PHYs drivers/net/phy: introduce missing kfree drivers/net/wan: introduce missing kfree net: force bridge module(s) to be GPL Subject: [PATCH] appletalk: Fix skb leak when ipddp interface is not loaded ... Fixed up trivial conflicts: - arch/x86/include/asm/socket.h converted to <asm-generic/socket.h> in the x86 tree. The generic header has the same new #define's, so that works out fine. - drivers/net/tun.c fix conflict between 89f56d1e9 ("tun: reuse struct sock fields") that switched over to using 'tun->socket.sk' instead of the redundantly available (and thus removed) 'tun->sk', and 2b980dbd ("lsm: Add hooks to the TUN driver") which added a new 'tun->sk' use. Noted in 'next' by Stephen Rothwell.
Diffstat (limited to 'net/wireless/mlme.c')
-rw-r--r--net/wireless/mlme.c627
1 files changed, 602 insertions, 25 deletions
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 42184361a109..79d2eec54cec 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -8,75 +8,652 @@
8#include <linux/module.h> 8#include <linux/module.h>
9#include <linux/netdevice.h> 9#include <linux/netdevice.h>
10#include <linux/nl80211.h> 10#include <linux/nl80211.h>
11#include <linux/wireless.h>
11#include <net/cfg80211.h> 12#include <net/cfg80211.h>
13#include <net/iw_handler.h>
12#include "core.h" 14#include "core.h"
13#include "nl80211.h" 15#include "nl80211.h"
14 16
15void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len) 17void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
16{ 18{
17 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; 19 struct wireless_dev *wdev = dev->ieee80211_ptr;
20 struct wiphy *wiphy = wdev->wiphy;
18 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 21 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
19 nl80211_send_rx_auth(rdev, dev, buf, len); 22 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
23 u8 *bssid = mgmt->bssid;
24 int i;
25 u16 status = le16_to_cpu(mgmt->u.auth.status_code);
26 bool done = false;
27
28 wdev_lock(wdev);
29
30 for (i = 0; i < MAX_AUTH_BSSES; i++) {
31 if (wdev->authtry_bsses[i] &&
32 memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid,
33 ETH_ALEN) == 0) {
34 if (status == WLAN_STATUS_SUCCESS) {
35 wdev->auth_bsses[i] = wdev->authtry_bsses[i];
36 } else {
37 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
38 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
39 }
40 wdev->authtry_bsses[i] = NULL;
41 done = true;
42 break;
43 }
44 }
45
46 WARN_ON(!done);
47
48 nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
49 cfg80211_sme_rx_auth(dev, buf, len);
50
51 wdev_unlock(wdev);
20} 52}
21EXPORT_SYMBOL(cfg80211_send_rx_auth); 53EXPORT_SYMBOL(cfg80211_send_rx_auth);
22 54
23void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) 55void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
24{ 56{
25 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; 57 u16 status_code;
58 struct wireless_dev *wdev = dev->ieee80211_ptr;
59 struct wiphy *wiphy = wdev->wiphy;
26 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 60 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
27 nl80211_send_rx_assoc(rdev, dev, buf, len); 61 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
62 u8 *ie = mgmt->u.assoc_resp.variable;
63 int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
64 struct cfg80211_internal_bss *bss = NULL;
65
66 wdev_lock(wdev);
67
68 status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
69
70 /*
71 * This is a bit of a hack, we don't notify userspace of
72 * a (re-)association reply if we tried to send a reassoc
73 * and got a reject -- we only try again with an assoc
74 * frame instead of reassoc.
75 */
76 if (status_code != WLAN_STATUS_SUCCESS && wdev->conn &&
77 cfg80211_sme_failed_reassoc(wdev))
78 goto out;
79
80 nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL);
81
82 if (status_code == WLAN_STATUS_SUCCESS) {
83 for (i = 0; i < MAX_AUTH_BSSES; i++) {
84 if (!wdev->auth_bsses[i])
85 continue;
86 if (memcmp(wdev->auth_bsses[i]->pub.bssid, mgmt->bssid,
87 ETH_ALEN) == 0) {
88 bss = wdev->auth_bsses[i];
89 wdev->auth_bsses[i] = NULL;
90 /* additional reference to drop hold */
91 cfg80211_ref_bss(bss);
92 break;
93 }
94 }
95
96 WARN_ON(!bss);
97 }
98
99 if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) {
100 /*
101 * This is for the userspace SME, the CONNECTING
102 * state will be changed to CONNECTED by
103 * __cfg80211_connect_result() below.
104 */
105 wdev->sme_state = CFG80211_SME_CONNECTING;
106 }
107
108 /* this consumes one bss reference (unless bss is NULL) */
109 __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
110 status_code,
111 status_code == WLAN_STATUS_SUCCESS,
112 bss ? &bss->pub : NULL);
113 /* drop hold now, and also reference acquired above */
114 if (bss) {
115 cfg80211_unhold_bss(bss);
116 cfg80211_put_bss(&bss->pub);
117 }
118
119 out:
120 wdev_unlock(wdev);
28} 121}
29EXPORT_SYMBOL(cfg80211_send_rx_assoc); 122EXPORT_SYMBOL(cfg80211_send_rx_assoc);
30 123
31void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len) 124static void __cfg80211_send_deauth(struct net_device *dev,
125 const u8 *buf, size_t len)
32{ 126{
33 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; 127 struct wireless_dev *wdev = dev->ieee80211_ptr;
128 struct wiphy *wiphy = wdev->wiphy;
34 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 129 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
35 nl80211_send_deauth(rdev, dev, buf, len); 130 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
131 const u8 *bssid = mgmt->bssid;
132 int i;
133 bool done = false;
134
135 ASSERT_WDEV_LOCK(wdev);
136
137 nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
138
139 if (wdev->current_bss &&
140 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
141 done = true;
142 cfg80211_unhold_bss(wdev->current_bss);
143 cfg80211_put_bss(&wdev->current_bss->pub);
144 wdev->current_bss = NULL;
145 } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
146 if (wdev->auth_bsses[i] &&
147 memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
148 cfg80211_unhold_bss(wdev->auth_bsses[i]);
149 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
150 wdev->auth_bsses[i] = NULL;
151 done = true;
152 break;
153 }
154 if (wdev->authtry_bsses[i] &&
155 memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
156 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
157 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
158 wdev->authtry_bsses[i] = NULL;
159 done = true;
160 break;
161 }
162 }
163
164 WARN_ON(!done);
165
166 if (wdev->sme_state == CFG80211_SME_CONNECTED) {
167 u16 reason_code;
168 bool from_ap;
169
170 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
171
172 from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
173 __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
174 } else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
175 __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
176 WLAN_STATUS_UNSPECIFIED_FAILURE,
177 false, NULL);
178 }
179}
180
181
182void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len,
183 void *cookie)
184{
185 struct wireless_dev *wdev = dev->ieee80211_ptr;
186
187 BUG_ON(cookie && wdev != cookie);
188
189 if (cookie) {
190 /* called within callback */
191 __cfg80211_send_deauth(dev, buf, len);
192 } else {
193 wdev_lock(wdev);
194 __cfg80211_send_deauth(dev, buf, len);
195 wdev_unlock(wdev);
196 }
36} 197}
37EXPORT_SYMBOL(cfg80211_send_deauth); 198EXPORT_SYMBOL(cfg80211_send_deauth);
38 199
39void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) 200static void __cfg80211_send_disassoc(struct net_device *dev,
201 const u8 *buf, size_t len)
40{ 202{
41 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; 203 struct wireless_dev *wdev = dev->ieee80211_ptr;
204 struct wiphy *wiphy = wdev->wiphy;
42 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 205 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
43 nl80211_send_disassoc(rdev, dev, buf, len); 206 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
207 const u8 *bssid = mgmt->bssid;
208 int i;
209 u16 reason_code;
210 bool from_ap;
211 bool done = false;
212
213 ASSERT_WDEV_LOCK(wdev);
214
215 nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL);
216
217 if (wdev->sme_state != CFG80211_SME_CONNECTED)
218 return;
219
220 if (wdev->current_bss &&
221 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
222 for (i = 0; i < MAX_AUTH_BSSES; i++) {
223 if (wdev->authtry_bsses[i] || wdev->auth_bsses[i])
224 continue;
225 wdev->auth_bsses[i] = wdev->current_bss;
226 wdev->current_bss = NULL;
227 done = true;
228 cfg80211_sme_disassoc(dev, i);
229 break;
230 }
231 WARN_ON(!done);
232 } else
233 WARN_ON(1);
234
235
236 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
237
238 from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
239 __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
44} 240}
45EXPORT_SYMBOL(cfg80211_send_disassoc);
46 241
47static void cfg80211_wext_disconnected(struct net_device *dev) 242void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len,
243 void *cookie)
48{ 244{
49#ifdef CONFIG_WIRELESS_EXT 245 struct wireless_dev *wdev = dev->ieee80211_ptr;
50 union iwreq_data wrqu; 246
51 memset(&wrqu, 0, sizeof(wrqu)); 247 BUG_ON(cookie && wdev != cookie);
52 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); 248
53#endif 249 if (cookie) {
250 /* called within callback */
251 __cfg80211_send_disassoc(dev, buf, len);
252 } else {
253 wdev_lock(wdev);
254 __cfg80211_send_disassoc(dev, buf, len);
255 wdev_unlock(wdev);
256 }
54} 257}
258EXPORT_SYMBOL(cfg80211_send_disassoc);
55 259
56void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) 260void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
57{ 261{
58 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; 262 struct wireless_dev *wdev = dev->ieee80211_ptr;
263 struct wiphy *wiphy = wdev->wiphy;
59 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 264 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
60 nl80211_send_auth_timeout(rdev, dev, addr); 265 int i;
61 cfg80211_wext_disconnected(dev); 266 bool done = false;
267
268 wdev_lock(wdev);
269
270 nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
271 if (wdev->sme_state == CFG80211_SME_CONNECTING)
272 __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
273 WLAN_STATUS_UNSPECIFIED_FAILURE,
274 false, NULL);
275
276 for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
277 if (wdev->authtry_bsses[i] &&
278 memcmp(wdev->authtry_bsses[i]->pub.bssid,
279 addr, ETH_ALEN) == 0) {
280 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
281 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
282 wdev->authtry_bsses[i] = NULL;
283 done = true;
284 break;
285 }
286 }
287
288 WARN_ON(!done);
289
290 wdev_unlock(wdev);
62} 291}
63EXPORT_SYMBOL(cfg80211_send_auth_timeout); 292EXPORT_SYMBOL(cfg80211_send_auth_timeout);
64 293
65void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr) 294void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
66{ 295{
67 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; 296 struct wireless_dev *wdev = dev->ieee80211_ptr;
297 struct wiphy *wiphy = wdev->wiphy;
68 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 298 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
69 nl80211_send_assoc_timeout(rdev, dev, addr); 299 int i;
70 cfg80211_wext_disconnected(dev); 300 bool done = false;
301
302 wdev_lock(wdev);
303
304 nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
305 if (wdev->sme_state == CFG80211_SME_CONNECTING)
306 __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
307 WLAN_STATUS_UNSPECIFIED_FAILURE,
308 false, NULL);
309
310 for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
311 if (wdev->auth_bsses[i] &&
312 memcmp(wdev->auth_bsses[i]->pub.bssid,
313 addr, ETH_ALEN) == 0) {
314 cfg80211_unhold_bss(wdev->auth_bsses[i]);
315 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
316 wdev->auth_bsses[i] = NULL;
317 done = true;
318 break;
319 }
320 }
321
322 WARN_ON(!done);
323
324 wdev_unlock(wdev);
71} 325}
72EXPORT_SYMBOL(cfg80211_send_assoc_timeout); 326EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
73 327
74void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, 328void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
75 enum nl80211_key_type key_type, int key_id, 329 enum nl80211_key_type key_type, int key_id,
76 const u8 *tsc) 330 const u8 *tsc, gfp_t gfp)
77{ 331{
78 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; 332 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
79 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 333 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
80 nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc); 334#ifdef CONFIG_WIRELESS_EXT
335 union iwreq_data wrqu;
336 char *buf = kmalloc(128, gfp);
337
338 if (buf) {
339 sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
340 "keyid=%d %scast addr=%pM)", key_id,
341 key_type == NL80211_KEYTYPE_GROUP ? "broad" : "uni",
342 addr);
343 memset(&wrqu, 0, sizeof(wrqu));
344 wrqu.data.length = strlen(buf);
345 wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
346 kfree(buf);
347 }
348#endif
349
350 nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp);
81} 351}
82EXPORT_SYMBOL(cfg80211_michael_mic_failure); 352EXPORT_SYMBOL(cfg80211_michael_mic_failure);
353
354/* some MLME handling for userspace SME */
355int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
356 struct net_device *dev,
357 struct ieee80211_channel *chan,
358 enum nl80211_auth_type auth_type,
359 const u8 *bssid,
360 const u8 *ssid, int ssid_len,
361 const u8 *ie, int ie_len,
362 const u8 *key, int key_len, int key_idx)
363{
364 struct wireless_dev *wdev = dev->ieee80211_ptr;
365 struct cfg80211_auth_request req;
366 struct cfg80211_internal_bss *bss;
367 int i, err, slot = -1, nfree = 0;
368
369 ASSERT_WDEV_LOCK(wdev);
370
371 if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
372 if (!key || !key_len || key_idx < 0 || key_idx > 4)
373 return -EINVAL;
374
375 if (wdev->current_bss &&
376 memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
377 return -EALREADY;
378
379 for (i = 0; i < MAX_AUTH_BSSES; i++) {
380 if (wdev->authtry_bsses[i] &&
381 memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid,
382 ETH_ALEN) == 0)
383 return -EALREADY;
384 if (wdev->auth_bsses[i] &&
385 memcmp(bssid, wdev->auth_bsses[i]->pub.bssid,
386 ETH_ALEN) == 0)
387 return -EALREADY;
388 }
389
390 memset(&req, 0, sizeof(req));
391
392 req.ie = ie;
393 req.ie_len = ie_len;
394 req.auth_type = auth_type;
395 req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
396 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
397 req.key = key;
398 req.key_len = key_len;
399 req.key_idx = key_idx;
400 if (!req.bss)
401 return -ENOENT;
402
403 bss = bss_from_pub(req.bss);
404
405 for (i = 0; i < MAX_AUTH_BSSES; i++) {
406 if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) {
407 slot = i;
408 nfree++;
409 }
410 }
411
412 /* we need one free slot for disassoc and one for this auth */
413 if (nfree < 2) {
414 err = -ENOSPC;
415 goto out;
416 }
417
418 wdev->authtry_bsses[slot] = bss;
419 cfg80211_hold_bss(bss);
420
421 err = rdev->ops->auth(&rdev->wiphy, dev, &req);
422 if (err) {
423 wdev->authtry_bsses[slot] = NULL;
424 cfg80211_unhold_bss(bss);
425 }
426
427 out:
428 if (err)
429 cfg80211_put_bss(req.bss);
430 return err;
431}
432
433int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
434 struct net_device *dev, struct ieee80211_channel *chan,
435 enum nl80211_auth_type auth_type, const u8 *bssid,
436 const u8 *ssid, int ssid_len,
437 const u8 *ie, int ie_len,
438 const u8 *key, int key_len, int key_idx)
439{
440 int err;
441
442 wdev_lock(dev->ieee80211_ptr);
443 err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
444 ssid, ssid_len, ie, ie_len,
445 key, key_len, key_idx);
446 wdev_unlock(dev->ieee80211_ptr);
447
448 return err;
449}
450
451int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
452 struct net_device *dev,
453 struct ieee80211_channel *chan,
454 const u8 *bssid, const u8 *prev_bssid,
455 const u8 *ssid, int ssid_len,
456 const u8 *ie, int ie_len, bool use_mfp,
457 struct cfg80211_crypto_settings *crypt)
458{
459 struct wireless_dev *wdev = dev->ieee80211_ptr;
460 struct cfg80211_assoc_request req;
461 struct cfg80211_internal_bss *bss;
462 int i, err, slot = -1;
463
464 ASSERT_WDEV_LOCK(wdev);
465
466 memset(&req, 0, sizeof(req));
467
468 if (wdev->current_bss)
469 return -EALREADY;
470
471 req.ie = ie;
472 req.ie_len = ie_len;
473 memcpy(&req.crypto, crypt, sizeof(req.crypto));
474 req.use_mfp = use_mfp;
475 req.prev_bssid = prev_bssid;
476 req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
477 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
478 if (!req.bss)
479 return -ENOENT;
480
481 bss = bss_from_pub(req.bss);
482
483 for (i = 0; i < MAX_AUTH_BSSES; i++) {
484 if (bss == wdev->auth_bsses[i]) {
485 slot = i;
486 break;
487 }
488 }
489
490 if (slot < 0) {
491 err = -ENOTCONN;
492 goto out;
493 }
494
495 err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
496 out:
497 /* still a reference in wdev->auth_bsses[slot] */
498 cfg80211_put_bss(req.bss);
499 return err;
500}
501
502int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
503 struct net_device *dev,
504 struct ieee80211_channel *chan,
505 const u8 *bssid, const u8 *prev_bssid,
506 const u8 *ssid, int ssid_len,
507 const u8 *ie, int ie_len, bool use_mfp,
508 struct cfg80211_crypto_settings *crypt)
509{
510 struct wireless_dev *wdev = dev->ieee80211_ptr;
511 int err;
512
513 wdev_lock(wdev);
514 err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
515 ssid, ssid_len, ie, ie_len, use_mfp, crypt);
516 wdev_unlock(wdev);
517
518 return err;
519}
520
521int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
522 struct net_device *dev, const u8 *bssid,
523 const u8 *ie, int ie_len, u16 reason)
524{
525 struct wireless_dev *wdev = dev->ieee80211_ptr;
526 struct cfg80211_deauth_request req;
527 int i;
528
529 ASSERT_WDEV_LOCK(wdev);
530
531 memset(&req, 0, sizeof(req));
532 req.reason_code = reason;
533 req.ie = ie;
534 req.ie_len = ie_len;
535 if (wdev->current_bss &&
536 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
537 req.bss = &wdev->current_bss->pub;
538 } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
539 if (wdev->auth_bsses[i] &&
540 memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
541 req.bss = &wdev->auth_bsses[i]->pub;
542 break;
543 }
544 if (wdev->authtry_bsses[i] &&
545 memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
546 req.bss = &wdev->authtry_bsses[i]->pub;
547 break;
548 }
549 }
550
551 if (!req.bss)
552 return -ENOTCONN;
553
554 return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
555}
556
557int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
558 struct net_device *dev, const u8 *bssid,
559 const u8 *ie, int ie_len, u16 reason)
560{
561 struct wireless_dev *wdev = dev->ieee80211_ptr;
562 int err;
563
564 wdev_lock(wdev);
565 err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason);
566 wdev_unlock(wdev);
567
568 return err;
569}
570
571static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
572 struct net_device *dev, const u8 *bssid,
573 const u8 *ie, int ie_len, u16 reason)
574{
575 struct wireless_dev *wdev = dev->ieee80211_ptr;
576 struct cfg80211_disassoc_request req;
577
578 ASSERT_WDEV_LOCK(wdev);
579
580 if (wdev->sme_state != CFG80211_SME_CONNECTED)
581 return -ENOTCONN;
582
583 if (WARN_ON(!wdev->current_bss))
584 return -ENOTCONN;
585
586 memset(&req, 0, sizeof(req));
587 req.reason_code = reason;
588 req.ie = ie;
589 req.ie_len = ie_len;
590 if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0)
591 req.bss = &wdev->current_bss->pub;
592 else
593 return -ENOTCONN;
594
595 return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev);
596}
597
598int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
599 struct net_device *dev, const u8 *bssid,
600 const u8 *ie, int ie_len, u16 reason)
601{
602 struct wireless_dev *wdev = dev->ieee80211_ptr;
603 int err;
604
605 wdev_lock(wdev);
606 err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason);
607 wdev_unlock(wdev);
608
609 return err;
610}
611
612void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
613 struct net_device *dev)
614{
615 struct wireless_dev *wdev = dev->ieee80211_ptr;
616 struct cfg80211_deauth_request req;
617 int i;
618
619 ASSERT_WDEV_LOCK(wdev);
620
621 if (!rdev->ops->deauth)
622 return;
623
624 memset(&req, 0, sizeof(req));
625 req.reason_code = WLAN_REASON_DEAUTH_LEAVING;
626 req.ie = NULL;
627 req.ie_len = 0;
628
629 if (wdev->current_bss) {
630 req.bss = &wdev->current_bss->pub;
631 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
632 if (wdev->current_bss) {
633 cfg80211_unhold_bss(wdev->current_bss);
634 cfg80211_put_bss(&wdev->current_bss->pub);
635 wdev->current_bss = NULL;
636 }
637 }
638
639 for (i = 0; i < MAX_AUTH_BSSES; i++) {
640 if (wdev->auth_bsses[i]) {
641 req.bss = &wdev->auth_bsses[i]->pub;
642 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
643 if (wdev->auth_bsses[i]) {
644 cfg80211_unhold_bss(wdev->auth_bsses[i]);
645 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
646 wdev->auth_bsses[i] = NULL;
647 }
648 }
649 if (wdev->authtry_bsses[i]) {
650 req.bss = &wdev->authtry_bsses[i]->pub;
651 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
652 if (wdev->authtry_bsses[i]) {
653 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
654 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
655 wdev->authtry_bsses[i] = NULL;
656 }
657 }
658 }
659}