]> bbs.cooldavid.org Git - net-next-2.6.git/blame - net/wireless/mlme.c
cfg80211: Add local-state-change-only auth/deauth/disassoc
[net-next-2.6.git] / net / wireless / mlme.c
CommitLineData
6039f6d2
JM
1/*
2 * cfg80211 MLME SAP interface
3 *
4 * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
5 */
6
7#include <linux/kernel.h>
8#include <linux/module.h>
9#include <linux/netdevice.h>
10#include <linux/nl80211.h>
a9a11622 11#include <linux/wireless.h>
6039f6d2 12#include <net/cfg80211.h>
a9a11622 13#include <net/iw_handler.h>
6039f6d2
JM
14#include "core.h"
15#include "nl80211.h"
16
cb0b4beb 17void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
6039f6d2 18{
19957bb3
JB
19 struct wireless_dev *wdev = dev->ieee80211_ptr;
20 struct wiphy *wiphy = wdev->wiphy;
6039f6d2 21 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
19957bb3
JB
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
667503dd 28 wdev_lock(wdev);
cb0b4beb 29
19957bb3
JB
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);
6829c878 47
cb0b4beb 48 nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
6829c878 49 cfg80211_sme_rx_auth(dev, buf, len);
667503dd
JB
50
51 wdev_unlock(wdev);
6039f6d2
JM
52}
53EXPORT_SYMBOL(cfg80211_send_rx_auth);
54
cb0b4beb 55void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
6039f6d2 56{
6829c878
JB
57 u16 status_code;
58 struct wireless_dev *wdev = dev->ieee80211_ptr;
59 struct wiphy *wiphy = wdev->wiphy;
6039f6d2 60 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
6829c878
JB
61 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
62 u8 *ie = mgmt->u.assoc_resp.variable;
19957bb3 63 int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
df7fc0f9 64 struct cfg80211_internal_bss *bss = NULL;
6829c878 65
667503dd 66 wdev_lock(wdev);
cb0b4beb 67
6829c878
JB
68 status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
69
f401a6f7
JB
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
cb0b4beb 80 nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL);
6829c878 81
19957bb3 82 if (status_code == WLAN_STATUS_SUCCESS) {
df7fc0f9
JB
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];
19957bb3 89 wdev->auth_bsses[i] = NULL;
df7fc0f9
JB
90 /* additional reference to drop hold */
91 cfg80211_ref_bss(bss);
19957bb3
JB
92 break;
93 }
94 }
95
3bdb2d48
JB
96 /*
97 * We might be coming here because the driver reported
98 * a successful association at the same time as the
99 * user requested a deauth. In that case, we will have
100 * removed the BSS from the auth_bsses list due to the
101 * deauth request when the assoc response makes it. If
102 * the two code paths acquire the lock the other way
103 * around, that's just the standard situation of a
104 * deauth being requested while connected.
105 */
106 if (!bss)
107 goto out;
7d930bc3
JB
108 } else if (wdev->conn) {
109 cfg80211_sme_failed_assoc(wdev);
7d930bc3
JB
110 /*
111 * do not call connect_result() now because the
112 * sme will schedule work that does it later.
113 */
114 goto out;
df7fc0f9
JB
115 }
116
ea416a79
JB
117 if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) {
118 /*
119 * This is for the userspace SME, the CONNECTING
120 * state will be changed to CONNECTED by
121 * __cfg80211_connect_result() below.
122 */
123 wdev->sme_state = CFG80211_SME_CONNECTING;
124 }
125
df7fc0f9
JB
126 /* this consumes one bss reference (unless bss is NULL) */
127 __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
128 status_code,
129 status_code == WLAN_STATUS_SUCCESS,
130 bss ? &bss->pub : NULL);
131 /* drop hold now, and also reference acquired above */
132 if (bss) {
133 cfg80211_unhold_bss(bss);
134 cfg80211_put_bss(&bss->pub);
19957bb3 135 }
667503dd 136
f401a6f7 137 out:
667503dd 138 wdev_unlock(wdev);
6039f6d2
JM
139}
140EXPORT_SYMBOL(cfg80211_send_rx_assoc);
141
ce470613 142void __cfg80211_send_deauth(struct net_device *dev,
667503dd 143 const u8 *buf, size_t len)
6039f6d2 144{
6829c878
JB
145 struct wireless_dev *wdev = dev->ieee80211_ptr;
146 struct wiphy *wiphy = wdev->wiphy;
6039f6d2 147 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
6829c878 148 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
19957bb3
JB
149 const u8 *bssid = mgmt->bssid;
150 int i;
5fba4af3 151 bool found = false;
6829c878 152
667503dd 153 ASSERT_WDEV_LOCK(wdev);
cb0b4beb 154
19957bb3
JB
155 if (wdev->current_bss &&
156 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
19957bb3
JB
157 cfg80211_unhold_bss(wdev->current_bss);
158 cfg80211_put_bss(&wdev->current_bss->pub);
159 wdev->current_bss = NULL;
5fba4af3 160 found = true;
19957bb3
JB
161 } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
162 if (wdev->auth_bsses[i] &&
163 memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
164 cfg80211_unhold_bss(wdev->auth_bsses[i]);
165 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
166 wdev->auth_bsses[i] = NULL;
5fba4af3 167 found = true;
19957bb3
JB
168 break;
169 }
170 if (wdev->authtry_bsses[i] &&
171 memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
172 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
173 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
174 wdev->authtry_bsses[i] = NULL;
5fba4af3 175 found = true;
19957bb3
JB
176 break;
177 }
178 }
19957bb3 179
5fba4af3
JB
180 if (!found)
181 return;
182
183 nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
184
6829c878
JB
185 if (wdev->sme_state == CFG80211_SME_CONNECTED) {
186 u16 reason_code;
187 bool from_ap;
188
189 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
190
e458b8a2 191 from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
667503dd 192 __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
6829c878 193 } else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
667503dd
JB
194 __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
195 WLAN_STATUS_UNSPECIFIED_FAILURE,
df7fc0f9 196 false, NULL);
667503dd
JB
197 }
198}
ce470613 199EXPORT_SYMBOL(__cfg80211_send_deauth);
667503dd 200
ce470613 201void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len)
667503dd
JB
202{
203 struct wireless_dev *wdev = dev->ieee80211_ptr;
204
ce470613
HS
205 wdev_lock(wdev);
206 __cfg80211_send_deauth(dev, buf, len);
207 wdev_unlock(wdev);
6039f6d2 208}
53b46b84 209EXPORT_SYMBOL(cfg80211_send_deauth);
6039f6d2 210
ce470613 211void __cfg80211_send_disassoc(struct net_device *dev,
667503dd 212 const u8 *buf, size_t len)
6039f6d2 213{
6829c878
JB
214 struct wireless_dev *wdev = dev->ieee80211_ptr;
215 struct wiphy *wiphy = wdev->wiphy;
6039f6d2 216 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
6829c878 217 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
19957bb3
JB
218 const u8 *bssid = mgmt->bssid;
219 int i;
220 u16 reason_code;
221 bool from_ap;
222 bool done = false;
6829c878 223
596a07c1 224 ASSERT_WDEV_LOCK(wdev);
cb0b4beb
JB
225
226 nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL);
a3b8b056 227
596a07c1
JB
228 if (wdev->sme_state != CFG80211_SME_CONNECTED)
229 return;
6829c878 230
19957bb3 231 if (wdev->current_bss &&
b935df01 232 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
19957bb3
JB
233 for (i = 0; i < MAX_AUTH_BSSES; i++) {
234 if (wdev->authtry_bsses[i] || wdev->auth_bsses[i])
235 continue;
236 wdev->auth_bsses[i] = wdev->current_bss;
237 wdev->current_bss = NULL;
238 done = true;
239 cfg80211_sme_disassoc(dev, i);
240 break;
241 }
242 WARN_ON(!done);
243 } else
244 WARN_ON(1);
6829c878 245
6829c878 246
19957bb3
JB
247 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
248
e458b8a2 249 from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
667503dd 250 __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
667503dd 251}
ce470613 252EXPORT_SYMBOL(__cfg80211_send_disassoc);
667503dd 253
ce470613 254void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len)
667503dd
JB
255{
256 struct wireless_dev *wdev = dev->ieee80211_ptr;
257
ce470613
HS
258 wdev_lock(wdev);
259 __cfg80211_send_disassoc(dev, buf, len);
260 wdev_unlock(wdev);
1965c853 261}
6829c878 262EXPORT_SYMBOL(cfg80211_send_disassoc);
1965c853 263
a58ce43f 264static void __cfg80211_auth_remove(struct wireless_dev *wdev, const u8 *addr)
1965c853 265{
19957bb3
JB
266 int i;
267 bool done = false;
268
a58ce43f 269 ASSERT_WDEV_LOCK(wdev);
19957bb3
JB
270
271 for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
272 if (wdev->authtry_bsses[i] &&
273 memcmp(wdev->authtry_bsses[i]->pub.bssid,
274 addr, ETH_ALEN) == 0) {
275 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
276 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
277 wdev->authtry_bsses[i] = NULL;
278 done = true;
279 break;
280 }
281 }
282
283 WARN_ON(!done);
a58ce43f
JB
284}
285
286void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr)
287{
288 __cfg80211_auth_remove(dev->ieee80211_ptr, addr);
289}
290EXPORT_SYMBOL(__cfg80211_auth_canceled);
291
292void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
293{
294 struct wireless_dev *wdev = dev->ieee80211_ptr;
295 struct wiphy *wiphy = wdev->wiphy;
296 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
297
298 wdev_lock(wdev);
299
300 nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
301 if (wdev->sme_state == CFG80211_SME_CONNECTING)
302 __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
303 WLAN_STATUS_UNSPECIFIED_FAILURE,
304 false, NULL);
305
306 __cfg80211_auth_remove(wdev, addr);
667503dd
JB
307
308 wdev_unlock(wdev);
1965c853
JM
309}
310EXPORT_SYMBOL(cfg80211_send_auth_timeout);
311
cb0b4beb 312void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
1965c853 313{
6829c878
JB
314 struct wireless_dev *wdev = dev->ieee80211_ptr;
315 struct wiphy *wiphy = wdev->wiphy;
1965c853 316 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
19957bb3
JB
317 int i;
318 bool done = false;
319
667503dd 320 wdev_lock(wdev);
cb0b4beb
JB
321
322 nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
6829c878 323 if (wdev->sme_state == CFG80211_SME_CONNECTING)
667503dd
JB
324 __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
325 WLAN_STATUS_UNSPECIFIED_FAILURE,
df7fc0f9 326 false, NULL);
19957bb3
JB
327
328 for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
329 if (wdev->auth_bsses[i] &&
330 memcmp(wdev->auth_bsses[i]->pub.bssid,
331 addr, ETH_ALEN) == 0) {
332 cfg80211_unhold_bss(wdev->auth_bsses[i]);
333 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
334 wdev->auth_bsses[i] = NULL;
335 done = true;
336 break;
337 }
338 }
339
340 WARN_ON(!done);
667503dd
JB
341
342 wdev_unlock(wdev);
1965c853
JM
343}
344EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
345
a3b8b056
JM
346void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
347 enum nl80211_key_type key_type, int key_id,
e6d6e342 348 const u8 *tsc, gfp_t gfp)
a3b8b056
JM
349{
350 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
351 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
3d23e349 352#ifdef CONFIG_CFG80211_WEXT
f58d4ed9 353 union iwreq_data wrqu;
e6d6e342 354 char *buf = kmalloc(128, gfp);
f58d4ed9
JB
355
356 if (buf) {
357 sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
358 "keyid=%d %scast addr=%pM)", key_id,
359 key_type == NL80211_KEYTYPE_GROUP ? "broad" : "uni",
360 addr);
361 memset(&wrqu, 0, sizeof(wrqu));
362 wrqu.data.length = strlen(buf);
363 wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
364 kfree(buf);
365 }
366#endif
367
e6d6e342 368 nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp);
a3b8b056
JM
369}
370EXPORT_SYMBOL(cfg80211_michael_mic_failure);
19957bb3
JB
371
372/* some MLME handling for userspace SME */
667503dd
JB
373int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
374 struct net_device *dev,
375 struct ieee80211_channel *chan,
376 enum nl80211_auth_type auth_type,
377 const u8 *bssid,
378 const u8 *ssid, int ssid_len,
fffd0934 379 const u8 *ie, int ie_len,
d5cdfacb
JM
380 const u8 *key, int key_len, int key_idx,
381 bool local_state_change)
19957bb3
JB
382{
383 struct wireless_dev *wdev = dev->ieee80211_ptr;
384 struct cfg80211_auth_request req;
385 struct cfg80211_internal_bss *bss;
386 int i, err, slot = -1, nfree = 0;
387
667503dd
JB
388 ASSERT_WDEV_LOCK(wdev);
389
fffd0934
JB
390 if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
391 if (!key || !key_len || key_idx < 0 || key_idx > 4)
392 return -EINVAL;
393
0a9b5e17
JB
394 if (wdev->current_bss &&
395 memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
396 return -EALREADY;
397
398 for (i = 0; i < MAX_AUTH_BSSES; i++) {
399 if (wdev->authtry_bsses[i] &&
400 memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid,
401 ETH_ALEN) == 0)
402 return -EALREADY;
403 if (wdev->auth_bsses[i] &&
404 memcmp(bssid, wdev->auth_bsses[i]->pub.bssid,
405 ETH_ALEN) == 0)
406 return -EALREADY;
407 }
408
19957bb3
JB
409 memset(&req, 0, sizeof(req));
410
d5cdfacb 411 req.local_state_change = local_state_change;
19957bb3
JB
412 req.ie = ie;
413 req.ie_len = ie_len;
414 req.auth_type = auth_type;
415 req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
416 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
fffd0934
JB
417 req.key = key;
418 req.key_len = key_len;
419 req.key_idx = key_idx;
19957bb3
JB
420 if (!req.bss)
421 return -ENOENT;
422
423 bss = bss_from_pub(req.bss);
424
19957bb3
JB
425 for (i = 0; i < MAX_AUTH_BSSES; i++) {
426 if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) {
427 slot = i;
428 nfree++;
429 }
430 }
431
432 /* we need one free slot for disassoc and one for this auth */
433 if (nfree < 2) {
434 err = -ENOSPC;
435 goto out;
436 }
437
d5cdfacb
JM
438 if (local_state_change)
439 wdev->auth_bsses[slot] = bss;
440 else
441 wdev->authtry_bsses[slot] = bss;
19957bb3
JB
442 cfg80211_hold_bss(bss);
443
444 err = rdev->ops->auth(&rdev->wiphy, dev, &req);
445 if (err) {
d5cdfacb
JM
446 if (local_state_change)
447 wdev->auth_bsses[slot] = NULL;
448 else
449 wdev->authtry_bsses[slot] = NULL;
19957bb3
JB
450 cfg80211_unhold_bss(bss);
451 }
452
453 out:
454 if (err)
455 cfg80211_put_bss(req.bss);
456 return err;
457}
458
667503dd
JB
459int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
460 struct net_device *dev, struct ieee80211_channel *chan,
461 enum nl80211_auth_type auth_type, const u8 *bssid,
462 const u8 *ssid, int ssid_len,
fffd0934 463 const u8 *ie, int ie_len,
d5cdfacb
JM
464 const u8 *key, int key_len, int key_idx,
465 bool local_state_change)
667503dd
JB
466{
467 int err;
468
469 wdev_lock(dev->ieee80211_ptr);
470 err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
fffd0934 471 ssid, ssid_len, ie, ie_len,
d5cdfacb 472 key, key_len, key_idx, local_state_change);
667503dd
JB
473 wdev_unlock(dev->ieee80211_ptr);
474
475 return err;
476}
477
478int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
479 struct net_device *dev,
480 struct ieee80211_channel *chan,
481 const u8 *bssid, const u8 *prev_bssid,
482 const u8 *ssid, int ssid_len,
483 const u8 *ie, int ie_len, bool use_mfp,
484 struct cfg80211_crypto_settings *crypt)
19957bb3
JB
485{
486 struct wireless_dev *wdev = dev->ieee80211_ptr;
487 struct cfg80211_assoc_request req;
488 struct cfg80211_internal_bss *bss;
489 int i, err, slot = -1;
24b6b15f 490 bool was_connected = false;
19957bb3 491
667503dd
JB
492 ASSERT_WDEV_LOCK(wdev);
493
19957bb3
JB
494 memset(&req, 0, sizeof(req));
495
24b6b15f
JM
496 if (wdev->current_bss && prev_bssid &&
497 memcmp(wdev->current_bss->pub.bssid, prev_bssid, ETH_ALEN) == 0) {
498 /*
499 * Trying to reassociate: Allow this to proceed and let the old
500 * association to be dropped when the new one is completed.
501 */
502 if (wdev->sme_state == CFG80211_SME_CONNECTED) {
503 was_connected = true;
504 wdev->sme_state = CFG80211_SME_CONNECTING;
505 }
506 } else if (wdev->current_bss)
19957bb3
JB
507 return -EALREADY;
508
509 req.ie = ie;
510 req.ie_len = ie_len;
511 memcpy(&req.crypto, crypt, sizeof(req.crypto));
512 req.use_mfp = use_mfp;
3e5d7649 513 req.prev_bssid = prev_bssid;
19957bb3
JB
514 req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
515 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
24b6b15f
JM
516 if (!req.bss) {
517 if (was_connected)
518 wdev->sme_state = CFG80211_SME_CONNECTED;
19957bb3 519 return -ENOENT;
24b6b15f 520 }
19957bb3
JB
521
522 bss = bss_from_pub(req.bss);
523
524 for (i = 0; i < MAX_AUTH_BSSES; i++) {
525 if (bss == wdev->auth_bsses[i]) {
526 slot = i;
527 break;
528 }
529 }
530
531 if (slot < 0) {
532 err = -ENOTCONN;
533 goto out;
534 }
535
536 err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
537 out:
24b6b15f
JM
538 if (err && was_connected)
539 wdev->sme_state = CFG80211_SME_CONNECTED;
19957bb3
JB
540 /* still a reference in wdev->auth_bsses[slot] */
541 cfg80211_put_bss(req.bss);
542 return err;
543}
544
667503dd
JB
545int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
546 struct net_device *dev,
547 struct ieee80211_channel *chan,
548 const u8 *bssid, const u8 *prev_bssid,
549 const u8 *ssid, int ssid_len,
550 const u8 *ie, int ie_len, bool use_mfp,
551 struct cfg80211_crypto_settings *crypt)
552{
553 struct wireless_dev *wdev = dev->ieee80211_ptr;
554 int err;
555
556 wdev_lock(wdev);
557 err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
558 ssid, ssid_len, ie, ie_len, use_mfp, crypt);
559 wdev_unlock(wdev);
560
561 return err;
562}
563
564int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
565 struct net_device *dev, const u8 *bssid,
d5cdfacb
JM
566 const u8 *ie, int ie_len, u16 reason,
567 bool local_state_change)
19957bb3
JB
568{
569 struct wireless_dev *wdev = dev->ieee80211_ptr;
570 struct cfg80211_deauth_request req;
571 int i;
572
667503dd
JB
573 ASSERT_WDEV_LOCK(wdev);
574
19957bb3
JB
575 memset(&req, 0, sizeof(req));
576 req.reason_code = reason;
d5cdfacb 577 req.local_state_change = local_state_change;
19957bb3
JB
578 req.ie = ie;
579 req.ie_len = ie_len;
580 if (wdev->current_bss &&
581 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
582 req.bss = &wdev->current_bss->pub;
583 } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
584 if (wdev->auth_bsses[i] &&
585 memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
586 req.bss = &wdev->auth_bsses[i]->pub;
587 break;
588 }
589 if (wdev->authtry_bsses[i] &&
590 memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
591 req.bss = &wdev->authtry_bsses[i]->pub;
592 break;
593 }
594 }
595
596 if (!req.bss)
597 return -ENOTCONN;
598
667503dd 599 return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
19957bb3
JB
600}
601
667503dd
JB
602int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
603 struct net_device *dev, const u8 *bssid,
d5cdfacb
JM
604 const u8 *ie, int ie_len, u16 reason,
605 bool local_state_change)
667503dd
JB
606{
607 struct wireless_dev *wdev = dev->ieee80211_ptr;
608 int err;
609
610 wdev_lock(wdev);
d5cdfacb
JM
611 err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason,
612 local_state_change);
667503dd
JB
613 wdev_unlock(wdev);
614
615 return err;
616}
617
618static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
619 struct net_device *dev, const u8 *bssid,
d5cdfacb
JM
620 const u8 *ie, int ie_len, u16 reason,
621 bool local_state_change)
19957bb3
JB
622{
623 struct wireless_dev *wdev = dev->ieee80211_ptr;
624 struct cfg80211_disassoc_request req;
625
667503dd
JB
626 ASSERT_WDEV_LOCK(wdev);
627
f9d6b402
JB
628 if (wdev->sme_state != CFG80211_SME_CONNECTED)
629 return -ENOTCONN;
630
631 if (WARN_ON(!wdev->current_bss))
632 return -ENOTCONN;
633
19957bb3
JB
634 memset(&req, 0, sizeof(req));
635 req.reason_code = reason;
d5cdfacb 636 req.local_state_change = local_state_change;
19957bb3
JB
637 req.ie = ie;
638 req.ie_len = ie_len;
639 if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0)
640 req.bss = &wdev->current_bss->pub;
641 else
642 return -ENOTCONN;
643
667503dd
JB
644 return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev);
645}
646
647int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
648 struct net_device *dev, const u8 *bssid,
d5cdfacb
JM
649 const u8 *ie, int ie_len, u16 reason,
650 bool local_state_change)
667503dd
JB
651{
652 struct wireless_dev *wdev = dev->ieee80211_ptr;
653 int err;
654
655 wdev_lock(wdev);
d5cdfacb
JM
656 err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason,
657 local_state_change);
667503dd
JB
658 wdev_unlock(wdev);
659
660 return err;
19957bb3
JB
661}
662
663void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
664 struct net_device *dev)
665{
666 struct wireless_dev *wdev = dev->ieee80211_ptr;
667 struct cfg80211_deauth_request req;
668 int i;
669
667503dd
JB
670 ASSERT_WDEV_LOCK(wdev);
671
19957bb3
JB
672 if (!rdev->ops->deauth)
673 return;
674
675 memset(&req, 0, sizeof(req));
676 req.reason_code = WLAN_REASON_DEAUTH_LEAVING;
677 req.ie = NULL;
678 req.ie_len = 0;
679
680 if (wdev->current_bss) {
681 req.bss = &wdev->current_bss->pub;
667503dd 682 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
19957bb3
JB
683 if (wdev->current_bss) {
684 cfg80211_unhold_bss(wdev->current_bss);
685 cfg80211_put_bss(&wdev->current_bss->pub);
686 wdev->current_bss = NULL;
687 }
688 }
689
690 for (i = 0; i < MAX_AUTH_BSSES; i++) {
691 if (wdev->auth_bsses[i]) {
692 req.bss = &wdev->auth_bsses[i]->pub;
667503dd 693 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
19957bb3
JB
694 if (wdev->auth_bsses[i]) {
695 cfg80211_unhold_bss(wdev->auth_bsses[i]);
696 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
697 wdev->auth_bsses[i] = NULL;
698 }
699 }
700 if (wdev->authtry_bsses[i]) {
701 req.bss = &wdev->authtry_bsses[i]->pub;
667503dd 702 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
19957bb3
JB
703 if (wdev->authtry_bsses[i]) {
704 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
705 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
706 wdev->authtry_bsses[i] = NULL;
707 }
708 }
709 }
710}
9588bbd5
JM
711
712void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie,
713 struct ieee80211_channel *chan,
714 enum nl80211_channel_type channel_type,
715 unsigned int duration, gfp_t gfp)
716{
717 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
718 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
719
720 nl80211_send_remain_on_channel(rdev, dev, cookie, chan, channel_type,
721 duration, gfp);
722}
723EXPORT_SYMBOL(cfg80211_ready_on_channel);
724
725void cfg80211_remain_on_channel_expired(struct net_device *dev,
726 u64 cookie,
727 struct ieee80211_channel *chan,
728 enum nl80211_channel_type channel_type,
729 gfp_t gfp)
730{
731 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
732 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
733
734 nl80211_send_remain_on_channel_cancel(rdev, dev, cookie, chan,
735 channel_type, gfp);
736}
737EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
98b62183
JB
738
739void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
740 struct station_info *sinfo, gfp_t gfp)
741{
742 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
743 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
744
745 nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp);
746}
747EXPORT_SYMBOL(cfg80211_new_sta);
026331c4
JM
748
749struct cfg80211_action_registration {
750 struct list_head list;
751
752 u32 nlpid;
753
754 int match_len;
755
756 u8 match[];
757};
758
759int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid,
760 const u8 *match_data, int match_len)
761{
762 struct cfg80211_action_registration *reg, *nreg;
763 int err = 0;
764
765 nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL);
766 if (!nreg)
767 return -ENOMEM;
768
769 spin_lock_bh(&wdev->action_registrations_lock);
770
771 list_for_each_entry(reg, &wdev->action_registrations, list) {
772 int mlen = min(match_len, reg->match_len);
773
774 if (memcmp(reg->match, match_data, mlen) == 0) {
775 err = -EALREADY;
776 break;
777 }
778 }
779
780 if (err) {
781 kfree(nreg);
782 goto out;
783 }
784
785 memcpy(nreg->match, match_data, match_len);
786 nreg->match_len = match_len;
787 nreg->nlpid = snd_pid;
788 list_add(&nreg->list, &wdev->action_registrations);
789
790 out:
791 spin_unlock_bh(&wdev->action_registrations_lock);
792 return err;
793}
794
795void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid)
796{
797 struct cfg80211_action_registration *reg, *tmp;
798
799 spin_lock_bh(&wdev->action_registrations_lock);
800
801 list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) {
802 if (reg->nlpid == nlpid) {
803 list_del(&reg->list);
804 kfree(reg);
805 }
806 }
807
808 spin_unlock_bh(&wdev->action_registrations_lock);
809}
810
811void cfg80211_mlme_purge_actions(struct wireless_dev *wdev)
812{
813 struct cfg80211_action_registration *reg, *tmp;
814
815 spin_lock_bh(&wdev->action_registrations_lock);
816
817 list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) {
818 list_del(&reg->list);
819 kfree(reg);
820 }
821
822 spin_unlock_bh(&wdev->action_registrations_lock);
823}
824
825int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
826 struct net_device *dev,
827 struct ieee80211_channel *chan,
828 enum nl80211_channel_type channel_type,
829 const u8 *buf, size_t len, u64 *cookie)
830{
831 struct wireless_dev *wdev = dev->ieee80211_ptr;
832 const struct ieee80211_mgmt *mgmt;
833
834 if (rdev->ops->action == NULL)
835 return -EOPNOTSUPP;
836 if (len < 24 + 1)
837 return -EINVAL;
838
839 mgmt = (const struct ieee80211_mgmt *) buf;
840 if (!ieee80211_is_action(mgmt->frame_control))
841 return -EINVAL;
842 if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) {
843 /* Verify that we are associated with the destination AP */
844 if (!wdev->current_bss ||
845 memcmp(wdev->current_bss->pub.bssid, mgmt->bssid,
846 ETH_ALEN) != 0 ||
847 memcmp(wdev->current_bss->pub.bssid, mgmt->da,
848 ETH_ALEN) != 0)
849 return -ENOTCONN;
850 }
851
852 if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0)
853 return -EINVAL;
854
855 /* Transmit the Action frame as requested by user space */
856 return rdev->ops->action(&rdev->wiphy, dev, chan, channel_type,
857 buf, len, cookie);
858}
859
860bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf,
861 size_t len, gfp_t gfp)
862{
863 struct wireless_dev *wdev = dev->ieee80211_ptr;
864 struct wiphy *wiphy = wdev->wiphy;
865 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
866 struct cfg80211_action_registration *reg;
867 const u8 *action_data;
868 int action_data_len;
869 bool result = false;
870
871 /* frame length - min size excluding category */
872 action_data_len = len - (IEEE80211_MIN_ACTION_SIZE - 1);
873
874 /* action data starts with category */
875 action_data = buf + IEEE80211_MIN_ACTION_SIZE - 1;
876
877 spin_lock_bh(&wdev->action_registrations_lock);
878
879 list_for_each_entry(reg, &wdev->action_registrations, list) {
880 if (reg->match_len > action_data_len)
881 continue;
882
883 if (memcmp(reg->match, action_data, reg->match_len))
884 continue;
885
886 /* found match! */
887
888 /* Indicate the received Action frame to user space */
889 if (nl80211_send_action(rdev, dev, reg->nlpid, freq,
890 buf, len, gfp))
891 continue;
892
893 result = true;
894 break;
895 }
896
897 spin_unlock_bh(&wdev->action_registrations_lock);
898
899 return result;
900}
901EXPORT_SYMBOL(cfg80211_rx_action);
902
903void cfg80211_action_tx_status(struct net_device *dev, u64 cookie,
904 const u8 *buf, size_t len, bool ack, gfp_t gfp)
905{
906 struct wireless_dev *wdev = dev->ieee80211_ptr;
907 struct wiphy *wiphy = wdev->wiphy;
908 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
909
910 /* Indicate TX status of the Action frame to user space */
911 nl80211_send_action_tx_status(rdev, dev, cookie, buf, len, ack, gfp);
912}
913EXPORT_SYMBOL(cfg80211_action_tx_status);
d6dc1a38
JO
914
915void cfg80211_cqm_rssi_notify(struct net_device *dev,
916 enum nl80211_cqm_rssi_threshold_event rssi_event,
917 gfp_t gfp)
918{
919 struct wireless_dev *wdev = dev->ieee80211_ptr;
920 struct wiphy *wiphy = wdev->wiphy;
921 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
922
923 /* Indicate roaming trigger event to user space */
924 nl80211_send_cqm_rssi_notify(rdev, dev, rssi_event, gfp);
925}
926EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);