2 * cfg80211 MLME SAP interface
4 * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
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>
17 void cfg80211_send_rx_auth(struct net_device
*dev
, const u8
*buf
, size_t len
)
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
;
25 u16 status
= le16_to_cpu(mgmt
->u
.auth
.status_code
);
30 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
31 if (wdev
->authtry_bsses
[i
] &&
32 memcmp(wdev
->authtry_bsses
[i
]->pub
.bssid
, bssid
,
34 if (status
== WLAN_STATUS_SUCCESS
) {
35 wdev
->auth_bsses
[i
] = wdev
->authtry_bsses
[i
];
37 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
38 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
40 wdev
->authtry_bsses
[i
] = NULL
;
48 nl80211_send_rx_auth(rdev
, dev
, buf
, len
, GFP_KERNEL
);
49 cfg80211_sme_rx_auth(dev
, buf
, len
);
53 EXPORT_SYMBOL(cfg80211_send_rx_auth
);
55 void cfg80211_send_rx_assoc(struct net_device
*dev
, const u8
*buf
, size_t len
)
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
;
68 status_code
= le16_to_cpu(mgmt
->u
.assoc_resp
.status_code
);
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.
76 if (status_code
!= WLAN_STATUS_SUCCESS
&& wdev
->conn
&&
77 cfg80211_sme_failed_reassoc(wdev
))
80 nl80211_send_rx_assoc(rdev
, dev
, buf
, len
, GFP_KERNEL
);
82 if (status_code
== WLAN_STATUS_SUCCESS
) {
83 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
84 if (!wdev
->auth_bsses
[i
])
86 if (memcmp(wdev
->auth_bsses
[i
]->pub
.bssid
, mgmt
->bssid
,
88 bss
= wdev
->auth_bsses
[i
];
89 wdev
->auth_bsses
[i
] = NULL
;
90 /* additional reference to drop hold */
91 cfg80211_ref_bss(bss
);
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.
108 } else if (wdev
->conn
) {
109 cfg80211_sme_failed_assoc(wdev
);
111 * do not call connect_result() now because the
112 * sme will schedule work that does it later.
117 if (!wdev
->conn
&& wdev
->sme_state
== CFG80211_SME_IDLE
) {
119 * This is for the userspace SME, the CONNECTING
120 * state will be changed to CONNECTED by
121 * __cfg80211_connect_result() below.
123 wdev
->sme_state
= CFG80211_SME_CONNECTING
;
126 /* this consumes one bss reference (unless bss is NULL) */
127 __cfg80211_connect_result(dev
, mgmt
->bssid
, NULL
, 0, ie
, len
- ieoffs
,
129 status_code
== WLAN_STATUS_SUCCESS
,
130 bss
? &bss
->pub
: NULL
);
131 /* drop hold now, and also reference acquired above */
133 cfg80211_unhold_bss(bss
);
134 cfg80211_put_bss(&bss
->pub
);
140 EXPORT_SYMBOL(cfg80211_send_rx_assoc
);
142 void __cfg80211_send_deauth(struct net_device
*dev
,
143 const u8
*buf
, size_t len
)
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
;
153 ASSERT_WDEV_LOCK(wdev
);
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
;
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
;
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
;
183 nl80211_send_deauth(rdev
, dev
, buf
, len
, GFP_KERNEL
);
185 if (wdev
->sme_state
== CFG80211_SME_CONNECTED
) {
189 reason_code
= le16_to_cpu(mgmt
->u
.deauth
.reason_code
);
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
,
199 EXPORT_SYMBOL(__cfg80211_send_deauth
);
201 void cfg80211_send_deauth(struct net_device
*dev
, const u8
*buf
, size_t len
)
203 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
206 __cfg80211_send_deauth(dev
, buf
, len
);
209 EXPORT_SYMBOL(cfg80211_send_deauth
);
211 void __cfg80211_send_disassoc(struct net_device
*dev
,
212 const u8
*buf
, size_t len
)
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
;
224 ASSERT_WDEV_LOCK(wdev
);
226 nl80211_send_disassoc(rdev
, dev
, buf
, len
, GFP_KERNEL
);
228 if (wdev
->sme_state
!= CFG80211_SME_CONNECTED
)
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
])
236 wdev
->auth_bsses
[i
] = wdev
->current_bss
;
237 wdev
->current_bss
= NULL
;
239 cfg80211_sme_disassoc(dev
, i
);
247 reason_code
= le16_to_cpu(mgmt
->u
.disassoc
.reason_code
);
249 from_ap
= memcmp(mgmt
->sa
, dev
->dev_addr
, ETH_ALEN
) != 0;
250 __cfg80211_disconnected(dev
, NULL
, 0, reason_code
, from_ap
);
252 EXPORT_SYMBOL(__cfg80211_send_disassoc
);
254 void cfg80211_send_disassoc(struct net_device
*dev
, const u8
*buf
, size_t len
)
256 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
259 __cfg80211_send_disassoc(dev
, buf
, len
);
262 EXPORT_SYMBOL(cfg80211_send_disassoc
);
264 static void __cfg80211_auth_remove(struct wireless_dev
*wdev
, const u8
*addr
)
269 ASSERT_WDEV_LOCK(wdev
);
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
;
286 void __cfg80211_auth_canceled(struct net_device
*dev
, const u8
*addr
)
288 __cfg80211_auth_remove(dev
->ieee80211_ptr
, addr
);
290 EXPORT_SYMBOL(__cfg80211_auth_canceled
);
292 void cfg80211_send_auth_timeout(struct net_device
*dev
, const u8
*addr
)
294 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
295 struct wiphy
*wiphy
= wdev
->wiphy
;
296 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
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
,
306 __cfg80211_auth_remove(wdev
, addr
);
310 EXPORT_SYMBOL(cfg80211_send_auth_timeout
);
312 void cfg80211_send_assoc_timeout(struct net_device
*dev
, const u8
*addr
)
314 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
315 struct wiphy
*wiphy
= wdev
->wiphy
;
316 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
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
,
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
;
344 EXPORT_SYMBOL(cfg80211_send_assoc_timeout
);
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
)
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
);
357 sprintf(buf
, "MLME-MICHAELMICFAILURE.indication("
358 "keyid=%d %scast addr=%pM)", key_id
,
359 key_type
== NL80211_KEYTYPE_GROUP
? "broad" : "uni",
361 memset(&wrqu
, 0, sizeof(wrqu
));
362 wrqu
.data
.length
= strlen(buf
);
363 wireless_send_event(dev
, IWEVCUSTOM
, &wrqu
, buf
);
368 nl80211_michael_mic_failure(rdev
, dev
, addr
, key_type
, key_id
, tsc
, gfp
);
370 EXPORT_SYMBOL(cfg80211_michael_mic_failure
);
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
,
378 const u8
*ssid
, int ssid_len
,
379 const u8
*ie
, int ie_len
,
380 const u8
*key
, int key_len
, int key_idx
)
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;
387 ASSERT_WDEV_LOCK(wdev
);
389 if (auth_type
== NL80211_AUTHTYPE_SHARED_KEY
)
390 if (!key
|| !key_len
|| key_idx
< 0 || key_idx
> 4)
393 if (wdev
->current_bss
&&
394 memcmp(bssid
, wdev
->current_bss
->pub
.bssid
, ETH_ALEN
) == 0)
397 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
398 if (wdev
->authtry_bsses
[i
] &&
399 memcmp(bssid
, wdev
->authtry_bsses
[i
]->pub
.bssid
,
402 if (wdev
->auth_bsses
[i
] &&
403 memcmp(bssid
, wdev
->auth_bsses
[i
]->pub
.bssid
,
408 memset(&req
, 0, sizeof(req
));
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
);
416 req
.key_len
= key_len
;
417 req
.key_idx
= key_idx
;
421 bss
= bss_from_pub(req
.bss
);
423 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
424 if (!wdev
->auth_bsses
[i
] && !wdev
->authtry_bsses
[i
]) {
430 /* we need one free slot for disassoc and one for this auth */
436 wdev
->authtry_bsses
[slot
] = bss
;
437 cfg80211_hold_bss(bss
);
439 err
= rdev
->ops
->auth(&rdev
->wiphy
, dev
, &req
);
441 wdev
->authtry_bsses
[slot
] = NULL
;
442 cfg80211_unhold_bss(bss
);
447 cfg80211_put_bss(req
.bss
);
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
)
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
);
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
)
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;
483 ASSERT_WDEV_LOCK(wdev
);
485 memset(&req
, 0, sizeof(req
));
487 if (wdev
->current_bss
&& prev_bssid
&&
488 memcmp(wdev
->current_bss
->pub
.bssid
, prev_bssid
, ETH_ALEN
) == 0) {
490 * Trying to reassociate: Allow this to proceed and let the old
491 * association to be dropped when the new one is completed.
493 if (wdev
->sme_state
== CFG80211_SME_CONNECTED
) {
494 was_connected
= true;
495 wdev
->sme_state
= CFG80211_SME_CONNECTING
;
497 } else if (wdev
->current_bss
)
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
);
509 wdev
->sme_state
= CFG80211_SME_CONNECTED
;
513 bss
= bss_from_pub(req
.bss
);
515 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
516 if (bss
== wdev
->auth_bsses
[i
]) {
527 err
= rdev
->ops
->assoc(&rdev
->wiphy
, dev
, &req
);
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
);
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
)
544 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
548 err
= __cfg80211_mlme_assoc(rdev
, dev
, chan
, bssid
, prev_bssid
,
549 ssid
, ssid_len
, ie
, ie_len
, use_mfp
, crypt
);
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
)
559 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
560 struct cfg80211_deauth_request req
;
563 ASSERT_WDEV_LOCK(wdev
);
565 memset(&req
, 0, sizeof(req
));
566 req
.reason_code
= reason
;
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
;
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
;
588 return rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
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
)
595 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
599 err
= __cfg80211_mlme_deauth(rdev
, dev
, bssid
, ie
, ie_len
, reason
);
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
)
609 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
610 struct cfg80211_disassoc_request req
;
612 ASSERT_WDEV_LOCK(wdev
);
614 if (wdev
->sme_state
!= CFG80211_SME_CONNECTED
)
617 if (WARN_ON(!wdev
->current_bss
))
620 memset(&req
, 0, sizeof(req
));
621 req
.reason_code
= reason
;
624 if (memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0)
625 req
.bss
= &wdev
->current_bss
->pub
;
629 return rdev
->ops
->disassoc(&rdev
->wiphy
, dev
, &req
, wdev
);
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
)
636 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
640 err
= __cfg80211_mlme_disassoc(rdev
, dev
, bssid
, ie
, ie_len
, reason
);
646 void cfg80211_mlme_down(struct cfg80211_registered_device
*rdev
,
647 struct net_device
*dev
)
649 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
650 struct cfg80211_deauth_request req
;
653 ASSERT_WDEV_LOCK(wdev
);
655 if (!rdev
->ops
->deauth
)
658 memset(&req
, 0, sizeof(req
));
659 req
.reason_code
= WLAN_REASON_DEAUTH_LEAVING
;
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
;
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
;
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
;
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
)
700 struct wiphy
*wiphy
= dev
->ieee80211_ptr
->wiphy
;
701 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
703 nl80211_send_remain_on_channel(rdev
, dev
, cookie
, chan
, channel_type
,
706 EXPORT_SYMBOL(cfg80211_ready_on_channel
);
708 void cfg80211_remain_on_channel_expired(struct net_device
*dev
,
710 struct ieee80211_channel
*chan
,
711 enum nl80211_channel_type channel_type
,
714 struct wiphy
*wiphy
= dev
->ieee80211_ptr
->wiphy
;
715 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
717 nl80211_send_remain_on_channel_cancel(rdev
, dev
, cookie
, chan
,
720 EXPORT_SYMBOL(cfg80211_remain_on_channel_expired
);
722 void cfg80211_new_sta(struct net_device
*dev
, const u8
*mac_addr
,
723 struct station_info
*sinfo
, gfp_t gfp
)
725 struct wiphy
*wiphy
= dev
->ieee80211_ptr
->wiphy
;
726 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
728 nl80211_send_sta_event(rdev
, dev
, mac_addr
, sinfo
, gfp
);
730 EXPORT_SYMBOL(cfg80211_new_sta
);
732 struct cfg80211_action_registration
{
733 struct list_head list
;
742 int cfg80211_mlme_register_action(struct wireless_dev
*wdev
, u32 snd_pid
,
743 const u8
*match_data
, int match_len
)
745 struct cfg80211_action_registration
*reg
, *nreg
;
748 nreg
= kzalloc(sizeof(*reg
) + match_len
, GFP_KERNEL
);
752 spin_lock_bh(&wdev
->action_registrations_lock
);
754 list_for_each_entry(reg
, &wdev
->action_registrations
, list
) {
755 int mlen
= min(match_len
, reg
->match_len
);
757 if (memcmp(reg
->match
, match_data
, mlen
) == 0) {
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
);
774 spin_unlock_bh(&wdev
->action_registrations_lock
);
778 void cfg80211_mlme_unregister_actions(struct wireless_dev
*wdev
, u32 nlpid
)
780 struct cfg80211_action_registration
*reg
, *tmp
;
782 spin_lock_bh(&wdev
->action_registrations_lock
);
784 list_for_each_entry_safe(reg
, tmp
, &wdev
->action_registrations
, list
) {
785 if (reg
->nlpid
== nlpid
) {
786 list_del(®
->list
);
791 spin_unlock_bh(&wdev
->action_registrations_lock
);
794 void cfg80211_mlme_purge_actions(struct wireless_dev
*wdev
)
796 struct cfg80211_action_registration
*reg
, *tmp
;
798 spin_lock_bh(&wdev
->action_registrations_lock
);
800 list_for_each_entry_safe(reg
, tmp
, &wdev
->action_registrations
, list
) {
801 list_del(®
->list
);
805 spin_unlock_bh(&wdev
->action_registrations_lock
);
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
)
814 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
815 const struct ieee80211_mgmt
*mgmt
;
817 if (rdev
->ops
->action
== NULL
)
822 mgmt
= (const struct ieee80211_mgmt
*) buf
;
823 if (!ieee80211_is_action(mgmt
->frame_control
))
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
,
830 memcmp(wdev
->current_bss
->pub
.bssid
, mgmt
->da
,
835 if (memcmp(mgmt
->sa
, dev
->dev_addr
, ETH_ALEN
) != 0)
838 /* Transmit the Action frame as requested by user space */
839 return rdev
->ops
->action(&rdev
->wiphy
, dev
, chan
, channel_type
,
843 bool cfg80211_rx_action(struct net_device
*dev
, int freq
, const u8
*buf
,
844 size_t len
, gfp_t gfp
)
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
;
854 /* frame length - min size excluding category */
855 action_data_len
= len
- (IEEE80211_MIN_ACTION_SIZE
- 1);
857 /* action data starts with category */
858 action_data
= buf
+ IEEE80211_MIN_ACTION_SIZE
- 1;
860 spin_lock_bh(&wdev
->action_registrations_lock
);
862 list_for_each_entry(reg
, &wdev
->action_registrations
, list
) {
863 if (reg
->match_len
> action_data_len
)
866 if (memcmp(reg
->match
, action_data
, reg
->match_len
))
871 /* Indicate the received Action frame to user space */
872 if (nl80211_send_action(rdev
, dev
, reg
->nlpid
, freq
,
880 spin_unlock_bh(&wdev
->action_registrations_lock
);
884 EXPORT_SYMBOL(cfg80211_rx_action
);
886 void cfg80211_action_tx_status(struct net_device
*dev
, u64 cookie
,
887 const u8
*buf
, size_t len
, bool ack
, gfp_t gfp
)
889 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
890 struct wiphy
*wiphy
= wdev
->wiphy
;
891 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
893 /* Indicate TX status of the Action frame to user space */
894 nl80211_send_action_tx_status(rdev
, dev
, cookie
, buf
, len
, ack
, gfp
);
896 EXPORT_SYMBOL(cfg80211_action_tx_status
);