cfg80211: Add local-state-change-only auth/deauth/disassoc
[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                          bool local_state_change)
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
388         ASSERT_WDEV_LOCK(wdev);
389
390         if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
391                 if (!key || !key_len || key_idx < 0 || key_idx > 4)
392                         return -EINVAL;
393
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
409         memset(&req, 0, sizeof(req));
410
411         req.local_state_change = local_state_change;
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);
417         req.key = key;
418         req.key_len = key_len;
419         req.key_idx = key_idx;
420         if (!req.bss)
421                 return -ENOENT;
422
423         bss = bss_from_pub(req.bss);
424
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
438         if (local_state_change)
439                 wdev->auth_bsses[slot] = bss;
440         else
441                 wdev->authtry_bsses[slot] = bss;
442         cfg80211_hold_bss(bss);
443
444         err = rdev->ops->auth(&rdev->wiphy, dev, &req);
445         if (err) {
446                 if (local_state_change)
447                         wdev->auth_bsses[slot] = NULL;
448                 else
449                         wdev->authtry_bsses[slot] = NULL;
450                 cfg80211_unhold_bss(bss);
451         }
452
453  out:
454         if (err)
455                 cfg80211_put_bss(req.bss);
456         return err;
457 }
458
459 int 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,
463                        const u8 *ie, int ie_len,
464                        const u8 *key, int key_len, int key_idx,
465                        bool local_state_change)
466 {
467         int err;
468
469         wdev_lock(dev->ieee80211_ptr);
470         err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
471                                    ssid, ssid_len, ie, ie_len,
472                                    key, key_len, key_idx, local_state_change);
473         wdev_unlock(dev->ieee80211_ptr);
474
475         return err;
476 }
477
478 int __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)
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;
490         bool was_connected = false;
491
492         ASSERT_WDEV_LOCK(wdev);
493
494         memset(&req, 0, sizeof(req));
495
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)
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;
513         req.prev_bssid = prev_bssid;
514         req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
515                                    WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
516         if (!req.bss) {
517                 if (was_connected)
518                         wdev->sme_state = CFG80211_SME_CONNECTED;
519                 return -ENOENT;
520         }
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:
538         if (err && was_connected)
539                 wdev->sme_state = CFG80211_SME_CONNECTED;
540         /* still a reference in wdev->auth_bsses[slot] */
541         cfg80211_put_bss(req.bss);
542         return err;
543 }
544
545 int 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
564 int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
565                            struct net_device *dev, const u8 *bssid,
566                            const u8 *ie, int ie_len, u16 reason,
567                            bool local_state_change)
568 {
569         struct wireless_dev *wdev = dev->ieee80211_ptr;
570         struct cfg80211_deauth_request req;
571         int i;
572
573         ASSERT_WDEV_LOCK(wdev);
574
575         memset(&req, 0, sizeof(req));
576         req.reason_code = reason;
577         req.local_state_change = local_state_change;
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
599         return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
600 }
601
602 int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
603                          struct net_device *dev, const u8 *bssid,
604                          const u8 *ie, int ie_len, u16 reason,
605                          bool local_state_change)
606 {
607         struct wireless_dev *wdev = dev->ieee80211_ptr;
608         int err;
609
610         wdev_lock(wdev);
611         err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason,
612                                      local_state_change);
613         wdev_unlock(wdev);
614
615         return err;
616 }
617
618 static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
619                                     struct net_device *dev, const u8 *bssid,
620                                     const u8 *ie, int ie_len, u16 reason,
621                                     bool local_state_change)
622 {
623         struct wireless_dev *wdev = dev->ieee80211_ptr;
624         struct cfg80211_disassoc_request req;
625
626         ASSERT_WDEV_LOCK(wdev);
627
628         if (wdev->sme_state != CFG80211_SME_CONNECTED)
629                 return -ENOTCONN;
630
631         if (WARN_ON(!wdev->current_bss))
632                 return -ENOTCONN;
633
634         memset(&req, 0, sizeof(req));
635         req.reason_code = reason;
636         req.local_state_change = local_state_change;
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
644         return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev);
645 }
646
647 int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
648                            struct net_device *dev, const u8 *bssid,
649                            const u8 *ie, int ie_len, u16 reason,
650                            bool local_state_change)
651 {
652         struct wireless_dev *wdev = dev->ieee80211_ptr;
653         int err;
654
655         wdev_lock(wdev);
656         err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason,
657                                        local_state_change);
658         wdev_unlock(wdev);
659
660         return err;
661 }
662
663 void 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
670         ASSERT_WDEV_LOCK(wdev);
671
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;
682                 rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
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;
693                         rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
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;
702                         rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
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 }
711
712 void 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 }
723 EXPORT_SYMBOL(cfg80211_ready_on_channel);
724
725 void 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 }
737 EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
738
739 void 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 }
747 EXPORT_SYMBOL(cfg80211_new_sta);
748
749 struct cfg80211_action_registration {
750         struct list_head list;
751
752         u32 nlpid;
753
754         int match_len;
755
756         u8 match[];
757 };
758
759 int 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
795 void 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
811 void 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
825 int 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
860 bool 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 }
901 EXPORT_SYMBOL(cfg80211_rx_action);
902
903 void 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 }
913 EXPORT_SYMBOL(cfg80211_action_tx_status);
914
915 void 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 }
926 EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);