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