Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
[linux-2.6.git] / net / wireless / mlme.c
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>
11 #include <linux/wireless.h>
12 #include <net/cfg80211.h>
13 #include <net/iw_handler.h>
14 #include "core.h"
15 #include "nl80211.h"
16
17 void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
18 {
19         struct wireless_dev *wdev = dev->ieee80211_ptr;
20         struct wiphy *wiphy = wdev->wiphy;
21         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
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);
52 }
53 EXPORT_SYMBOL(cfg80211_send_rx_auth);
54
55 void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
56 {
57         u16 status_code;
58         struct wireless_dev *wdev = dev->ieee80211_ptr;
59         struct wiphy *wiphy = wdev->wiphy;
60         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
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                 /*
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;
108         } else if (wdev->conn) {
109                 cfg80211_sme_failed_assoc(wdev);
110                 /*
111                  * do not call connect_result() now because the
112                  * sme will schedule work that does it later.
113                  */
114                 goto out;
115         }
116
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
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);
135         }
136
137  out:
138         wdev_unlock(wdev);
139 }
140 EXPORT_SYMBOL(cfg80211_send_rx_assoc);
141
142 void __cfg80211_send_deauth(struct net_device *dev,
143                                    const u8 *buf, size_t len)
144 {
145         struct wireless_dev *wdev = dev->ieee80211_ptr;
146         struct wiphy *wiphy = wdev->wiphy;
147         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
148         struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
149         const u8 *bssid = mgmt->bssid;
150         int i;
151         bool found = false;
152
153         ASSERT_WDEV_LOCK(wdev);
154
155         if (wdev->current_bss &&
156             memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
157                 cfg80211_unhold_bss(wdev->current_bss);
158                 cfg80211_put_bss(&wdev->current_bss->pub);
159                 wdev->current_bss = NULL;
160                 found = true;
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;
167                         found = true;
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;
175                         found = true;
176                         break;
177                 }
178         }
179
180         if (!found)
181                 return;
182
183         nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
184
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
191                 from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
192                 __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
193         } else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
194                 __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
195                                           WLAN_STATUS_UNSPECIFIED_FAILURE,
196                                           false, NULL);
197         }
198 }
199 EXPORT_SYMBOL(__cfg80211_send_deauth);
200
201 void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len)
202 {
203         struct wireless_dev *wdev = dev->ieee80211_ptr;
204
205         wdev_lock(wdev);
206         __cfg80211_send_deauth(dev, buf, len);
207         wdev_unlock(wdev);
208 }
209 EXPORT_SYMBOL(cfg80211_send_deauth);
210
211 void __cfg80211_send_disassoc(struct net_device *dev,
212                                      const u8 *buf, size_t len)
213 {
214         struct wireless_dev *wdev = dev->ieee80211_ptr;
215         struct wiphy *wiphy = wdev->wiphy;
216         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
217         struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
218         const u8 *bssid = mgmt->bssid;
219         int i;
220         u16 reason_code;
221         bool from_ap;
222         bool done = false;
223
224         ASSERT_WDEV_LOCK(wdev);
225
226         nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL);
227
228         if (wdev->sme_state != CFG80211_SME_CONNECTED)
229                 return;
230
231         if (wdev->current_bss &&
232             memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
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);
245
246
247         reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
248
249         from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
250         __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
251 }
252 EXPORT_SYMBOL(__cfg80211_send_disassoc);
253
254 void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len)
255 {
256         struct wireless_dev *wdev = dev->ieee80211_ptr;
257
258         wdev_lock(wdev);
259         __cfg80211_send_disassoc(dev, buf, len);
260         wdev_unlock(wdev);
261 }
262 EXPORT_SYMBOL(cfg80211_send_disassoc);
263
264 static void __cfg80211_auth_remove(struct wireless_dev *wdev, const u8 *addr)
265 {
266         int i;
267         bool done = false;
268
269         ASSERT_WDEV_LOCK(wdev);
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);
284 }
285
286 void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr)
287 {
288         __cfg80211_auth_remove(dev->ieee80211_ptr, addr);
289 }
290 EXPORT_SYMBOL(__cfg80211_auth_canceled);
291
292 void 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);
307
308         wdev_unlock(wdev);
309 }
310 EXPORT_SYMBOL(cfg80211_send_auth_timeout);
311
312 void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
313 {
314         struct wireless_dev *wdev = dev->ieee80211_ptr;
315         struct wiphy *wiphy = wdev->wiphy;
316         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
317         int i;
318         bool done = false;
319
320         wdev_lock(wdev);
321
322         nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
323         if (wdev->sme_state == CFG80211_SME_CONNECTING)
324                 __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
325                                           WLAN_STATUS_UNSPECIFIED_FAILURE,
326                                           false, NULL);
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);
341
342         wdev_unlock(wdev);
343 }
344 EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
345
346 void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
347                                   enum nl80211_key_type key_type, int key_id,
348                                   const u8 *tsc, gfp_t gfp)
349 {
350         struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
351         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
352 #ifdef CONFIG_CFG80211_WEXT
353         union iwreq_data wrqu;
354         char *buf = kmalloc(128, gfp);
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
368         nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp);
369 }
370 EXPORT_SYMBOL(cfg80211_michael_mic_failure);
371
372 /* some MLME handling for userspace SME */
373 int __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,
379                          const u8 *ie, int ie_len,
380                          const u8 *key, int key_len, int key_idx)
381 {
382         struct wireless_dev *wdev = dev->ieee80211_ptr;
383         struct cfg80211_auth_request req;
384         struct cfg80211_internal_bss *bss;
385         int i, err, slot = -1, nfree = 0;
386
387         ASSERT_WDEV_LOCK(wdev);
388
389         if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
390                 if (!key || !key_len || key_idx < 0 || key_idx > 4)
391                         return -EINVAL;
392
393         if (wdev->current_bss &&
394             memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
395                 return -EALREADY;
396
397         for (i = 0; i < MAX_AUTH_BSSES; i++) {
398                 if (wdev->authtry_bsses[i] &&
399                     memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid,
400                                                 ETH_ALEN) == 0)
401                         return -EALREADY;
402                 if (wdev->auth_bsses[i] &&
403                     memcmp(bssid, wdev->auth_bsses[i]->pub.bssid,
404                                                 ETH_ALEN) == 0)
405                         return -EALREADY;
406         }
407
408         memset(&req, 0, sizeof(req));
409
410         req.ie = ie;
411         req.ie_len = ie_len;
412         req.auth_type = auth_type;
413         req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
414                                    WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
415         req.key = key;
416         req.key_len = key_len;
417         req.key_idx = key_idx;
418         if (!req.bss)
419                 return -ENOENT;
420
421         bss = bss_from_pub(req.bss);
422
423         for (i = 0; i < MAX_AUTH_BSSES; i++) {
424                 if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) {
425                         slot = i;
426                         nfree++;
427                 }
428         }
429
430         /* we need one free slot for disassoc and one for this auth */
431         if (nfree < 2) {
432                 err = -ENOSPC;
433                 goto out;
434         }
435
436         wdev->authtry_bsses[slot] = bss;
437         cfg80211_hold_bss(bss);
438
439         err = rdev->ops->auth(&rdev->wiphy, dev, &req);
440         if (err) {
441                 wdev->authtry_bsses[slot] = NULL;
442                 cfg80211_unhold_bss(bss);
443         }
444
445  out:
446         if (err)
447                 cfg80211_put_bss(req.bss);
448         return err;
449 }
450
451 int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
452                        struct net_device *dev, struct ieee80211_channel *chan,
453                        enum nl80211_auth_type auth_type, const u8 *bssid,
454                        const u8 *ssid, int ssid_len,
455                        const u8 *ie, int ie_len,
456                        const u8 *key, int key_len, int key_idx)
457 {
458         int err;
459
460         wdev_lock(dev->ieee80211_ptr);
461         err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
462                                    ssid, ssid_len, ie, ie_len,
463                                    key, key_len, key_idx);
464         wdev_unlock(dev->ieee80211_ptr);
465
466         return err;
467 }
468
469 int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
470                           struct net_device *dev,
471                           struct ieee80211_channel *chan,
472                           const u8 *bssid, const u8 *prev_bssid,
473                           const u8 *ssid, int ssid_len,
474                           const u8 *ie, int ie_len, bool use_mfp,
475                           struct cfg80211_crypto_settings *crypt)
476 {
477         struct wireless_dev *wdev = dev->ieee80211_ptr;
478         struct cfg80211_assoc_request req;
479         struct cfg80211_internal_bss *bss;
480         int i, err, slot = -1;
481         bool was_connected = false;
482
483         ASSERT_WDEV_LOCK(wdev);
484
485         memset(&req, 0, sizeof(req));
486
487         if (wdev->current_bss && prev_bssid &&
488             memcmp(wdev->current_bss->pub.bssid, prev_bssid, ETH_ALEN) == 0) {
489                 /*
490                  * Trying to reassociate: Allow this to proceed and let the old
491                  * association to be dropped when the new one is completed.
492                  */
493                 if (wdev->sme_state == CFG80211_SME_CONNECTED) {
494                         was_connected = true;
495                         wdev->sme_state = CFG80211_SME_CONNECTING;
496                 }
497         } else if (wdev->current_bss)
498                 return -EALREADY;
499
500         req.ie = ie;
501         req.ie_len = ie_len;
502         memcpy(&req.crypto, crypt, sizeof(req.crypto));
503         req.use_mfp = use_mfp;
504         req.prev_bssid = prev_bssid;
505         req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
506                                    WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
507         if (!req.bss) {
508                 if (was_connected)
509                         wdev->sme_state = CFG80211_SME_CONNECTED;
510                 return -ENOENT;
511         }
512
513         bss = bss_from_pub(req.bss);
514
515         for (i = 0; i < MAX_AUTH_BSSES; i++) {
516                 if (bss == wdev->auth_bsses[i]) {
517                         slot = i;
518                         break;
519                 }
520         }
521
522         if (slot < 0) {
523                 err = -ENOTCONN;
524                 goto out;
525         }
526
527         err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
528  out:
529         if (err && was_connected)
530                 wdev->sme_state = CFG80211_SME_CONNECTED;
531         /* still a reference in wdev->auth_bsses[slot] */
532         cfg80211_put_bss(req.bss);
533         return err;
534 }
535
536 int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
537                         struct net_device *dev,
538                         struct ieee80211_channel *chan,
539                         const u8 *bssid, const u8 *prev_bssid,
540                         const u8 *ssid, int ssid_len,
541                         const u8 *ie, int ie_len, bool use_mfp,
542                         struct cfg80211_crypto_settings *crypt)
543 {
544         struct wireless_dev *wdev = dev->ieee80211_ptr;
545         int err;
546
547         wdev_lock(wdev);
548         err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
549                                     ssid, ssid_len, ie, ie_len, use_mfp, crypt);
550         wdev_unlock(wdev);
551
552         return err;
553 }
554
555 int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
556                            struct net_device *dev, const u8 *bssid,
557                            const u8 *ie, int ie_len, u16 reason)
558 {
559         struct wireless_dev *wdev = dev->ieee80211_ptr;
560         struct cfg80211_deauth_request req;
561         int i;
562
563         ASSERT_WDEV_LOCK(wdev);
564
565         memset(&req, 0, sizeof(req));
566         req.reason_code = reason;
567         req.ie = ie;
568         req.ie_len = ie_len;
569         if (wdev->current_bss &&
570             memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
571                 req.bss = &wdev->current_bss->pub;
572         } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
573                 if (wdev->auth_bsses[i] &&
574                     memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
575                         req.bss = &wdev->auth_bsses[i]->pub;
576                         break;
577                 }
578                 if (wdev->authtry_bsses[i] &&
579                     memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
580                         req.bss = &wdev->authtry_bsses[i]->pub;
581                         break;
582                 }
583         }
584
585         if (!req.bss)
586                 return -ENOTCONN;
587
588         return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
589 }
590
591 int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
592                          struct net_device *dev, const u8 *bssid,
593                          const u8 *ie, int ie_len, u16 reason)
594 {
595         struct wireless_dev *wdev = dev->ieee80211_ptr;
596         int err;
597
598         wdev_lock(wdev);
599         err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason);
600         wdev_unlock(wdev);
601
602         return err;
603 }
604
605 static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
606                                     struct net_device *dev, const u8 *bssid,
607                                     const u8 *ie, int ie_len, u16 reason)
608 {
609         struct wireless_dev *wdev = dev->ieee80211_ptr;
610         struct cfg80211_disassoc_request req;
611
612         ASSERT_WDEV_LOCK(wdev);
613
614         if (wdev->sme_state != CFG80211_SME_CONNECTED)
615                 return -ENOTCONN;
616
617         if (WARN_ON(!wdev->current_bss))
618                 return -ENOTCONN;
619
620         memset(&req, 0, sizeof(req));
621         req.reason_code = reason;
622         req.ie = ie;
623         req.ie_len = ie_len;
624         if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0)
625                 req.bss = &wdev->current_bss->pub;
626         else
627                 return -ENOTCONN;
628
629         return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev);
630 }
631
632 int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
633                            struct net_device *dev, const u8 *bssid,
634                            const u8 *ie, int ie_len, u16 reason)
635 {
636         struct wireless_dev *wdev = dev->ieee80211_ptr;
637         int err;
638
639         wdev_lock(wdev);
640         err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason);
641         wdev_unlock(wdev);
642
643         return err;
644 }
645
646 void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
647                         struct net_device *dev)
648 {
649         struct wireless_dev *wdev = dev->ieee80211_ptr;
650         struct cfg80211_deauth_request req;
651         int i;
652
653         ASSERT_WDEV_LOCK(wdev);
654
655         if (!rdev->ops->deauth)
656                 return;
657
658         memset(&req, 0, sizeof(req));
659         req.reason_code = WLAN_REASON_DEAUTH_LEAVING;
660         req.ie = NULL;
661         req.ie_len = 0;
662
663         if (wdev->current_bss) {
664                 req.bss = &wdev->current_bss->pub;
665                 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
666                 if (wdev->current_bss) {
667                         cfg80211_unhold_bss(wdev->current_bss);
668                         cfg80211_put_bss(&wdev->current_bss->pub);
669                         wdev->current_bss = NULL;
670                 }
671         }
672
673         for (i = 0; i < MAX_AUTH_BSSES; i++) {
674                 if (wdev->auth_bsses[i]) {
675                         req.bss = &wdev->auth_bsses[i]->pub;
676                         rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
677                         if (wdev->auth_bsses[i]) {
678                                 cfg80211_unhold_bss(wdev->auth_bsses[i]);
679                                 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
680                                 wdev->auth_bsses[i] = NULL;
681                         }
682                 }
683                 if (wdev->authtry_bsses[i]) {
684                         req.bss = &wdev->authtry_bsses[i]->pub;
685                         rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
686                         if (wdev->authtry_bsses[i]) {
687                                 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
688                                 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
689                                 wdev->authtry_bsses[i] = NULL;
690                         }
691                 }
692         }
693 }
694
695 void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie,
696                                struct ieee80211_channel *chan,
697                                enum nl80211_channel_type channel_type,
698                                unsigned int duration, gfp_t gfp)
699 {
700         struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
701         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
702
703         nl80211_send_remain_on_channel(rdev, dev, cookie, chan, channel_type,
704                                        duration, gfp);
705 }
706 EXPORT_SYMBOL(cfg80211_ready_on_channel);
707
708 void cfg80211_remain_on_channel_expired(struct net_device *dev,
709                                         u64 cookie,
710                                         struct ieee80211_channel *chan,
711                                         enum nl80211_channel_type channel_type,
712                                         gfp_t gfp)
713 {
714         struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
715         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
716
717         nl80211_send_remain_on_channel_cancel(rdev, dev, cookie, chan,
718                                               channel_type, gfp);
719 }
720 EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
721
722 void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
723                       struct station_info *sinfo, gfp_t gfp)
724 {
725         struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
726         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
727
728         nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp);
729 }
730 EXPORT_SYMBOL(cfg80211_new_sta);
731
732 struct cfg80211_action_registration {
733         struct list_head list;
734
735         u32 nlpid;
736
737         int match_len;
738
739         u8 match[];
740 };
741
742 int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid,
743                                   const u8 *match_data, int match_len)
744 {
745         struct cfg80211_action_registration *reg, *nreg;
746         int err = 0;
747
748         nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL);
749         if (!nreg)
750                 return -ENOMEM;
751
752         spin_lock_bh(&wdev->action_registrations_lock);
753
754         list_for_each_entry(reg, &wdev->action_registrations, list) {
755                 int mlen = min(match_len, reg->match_len);
756
757                 if (memcmp(reg->match, match_data, mlen) == 0) {
758                         err = -EALREADY;
759                         break;
760                 }
761         }
762
763         if (err) {
764                 kfree(nreg);
765                 goto out;
766         }
767
768         memcpy(nreg->match, match_data, match_len);
769         nreg->match_len = match_len;
770         nreg->nlpid = snd_pid;
771         list_add(&nreg->list, &wdev->action_registrations);
772
773  out:
774         spin_unlock_bh(&wdev->action_registrations_lock);
775         return err;
776 }
777
778 void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid)
779 {
780         struct cfg80211_action_registration *reg, *tmp;
781
782         spin_lock_bh(&wdev->action_registrations_lock);
783
784         list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) {
785                 if (reg->nlpid == nlpid) {
786                         list_del(&reg->list);
787                         kfree(reg);
788                 }
789         }
790
791         spin_unlock_bh(&wdev->action_registrations_lock);
792 }
793
794 void cfg80211_mlme_purge_actions(struct wireless_dev *wdev)
795 {
796         struct cfg80211_action_registration *reg, *tmp;
797
798         spin_lock_bh(&wdev->action_registrations_lock);
799
800         list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) {
801                 list_del(&reg->list);
802                 kfree(reg);
803         }
804
805         spin_unlock_bh(&wdev->action_registrations_lock);
806 }
807
808 int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
809                          struct net_device *dev,
810                          struct ieee80211_channel *chan,
811                          enum nl80211_channel_type channel_type,
812                          const u8 *buf, size_t len, u64 *cookie)
813 {
814         struct wireless_dev *wdev = dev->ieee80211_ptr;
815         const struct ieee80211_mgmt *mgmt;
816
817         if (rdev->ops->action == NULL)
818                 return -EOPNOTSUPP;
819         if (len < 24 + 1)
820                 return -EINVAL;
821
822         mgmt = (const struct ieee80211_mgmt *) buf;
823         if (!ieee80211_is_action(mgmt->frame_control))
824                 return -EINVAL;
825         if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) {
826                 /* Verify that we are associated with the destination AP */
827                 if (!wdev->current_bss ||
828                     memcmp(wdev->current_bss->pub.bssid, mgmt->bssid,
829                            ETH_ALEN) != 0 ||
830                     memcmp(wdev->current_bss->pub.bssid, mgmt->da,
831                            ETH_ALEN) != 0)
832                         return -ENOTCONN;
833         }
834
835         if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0)
836                 return -EINVAL;
837
838         /* Transmit the Action frame as requested by user space */
839         return rdev->ops->action(&rdev->wiphy, dev, chan, channel_type,
840                                  buf, len, cookie);
841 }
842
843 bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf,
844                         size_t len, gfp_t gfp)
845 {
846         struct wireless_dev *wdev = dev->ieee80211_ptr;
847         struct wiphy *wiphy = wdev->wiphy;
848         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
849         struct cfg80211_action_registration *reg;
850         const u8 *action_data;
851         int action_data_len;
852         bool result = false;
853
854         /* frame length - min size excluding category */
855         action_data_len = len - (IEEE80211_MIN_ACTION_SIZE - 1);
856
857         /* action data starts with category */
858         action_data = buf + IEEE80211_MIN_ACTION_SIZE - 1;
859
860         spin_lock_bh(&wdev->action_registrations_lock);
861
862         list_for_each_entry(reg, &wdev->action_registrations, list) {
863                 if (reg->match_len > action_data_len)
864                         continue;
865
866                 if (memcmp(reg->match, action_data, reg->match_len))
867                         continue;
868
869                 /* found match! */
870
871                 /* Indicate the received Action frame to user space */
872                 if (nl80211_send_action(rdev, dev, reg->nlpid, freq,
873                                         buf, len, gfp))
874                         continue;
875
876                 result = true;
877                 break;
878         }
879
880         spin_unlock_bh(&wdev->action_registrations_lock);
881
882         return result;
883 }
884 EXPORT_SYMBOL(cfg80211_rx_action);
885
886 void cfg80211_action_tx_status(struct net_device *dev, u64 cookie,
887                                const u8 *buf, size_t len, bool ack, gfp_t gfp)
888 {
889         struct wireless_dev *wdev = dev->ieee80211_ptr;
890         struct wiphy *wiphy = wdev->wiphy;
891         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
892
893         /* Indicate TX status of the Action frame to user space */
894         nl80211_send_action_tx_status(rdev, dev, cookie, buf, len, ack, gfp);
895 }
896 EXPORT_SYMBOL(cfg80211_action_tx_status);