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/slab.h>
12 #include <linux/wireless.h>
13 #include <net/cfg80211.h>
14 #include <net/iw_handler.h>
18 void cfg80211_send_rx_auth(struct net_device
*dev
, const u8
*buf
, size_t len
)
20 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
21 struct wiphy
*wiphy
= wdev
->wiphy
;
22 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
26 nl80211_send_rx_auth(rdev
, dev
, buf
, len
, GFP_KERNEL
);
27 cfg80211_sme_rx_auth(dev
, buf
, len
);
31 EXPORT_SYMBOL(cfg80211_send_rx_auth
);
33 void cfg80211_send_rx_assoc(struct net_device
*dev
, struct cfg80211_bss
*bss
,
34 const u8
*buf
, size_t len
)
37 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
38 struct wiphy
*wiphy
= wdev
->wiphy
;
39 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
40 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
41 u8
*ie
= mgmt
->u
.assoc_resp
.variable
;
42 int ieoffs
= offsetof(struct ieee80211_mgmt
, u
.assoc_resp
.variable
);
46 status_code
= le16_to_cpu(mgmt
->u
.assoc_resp
.status_code
);
49 * This is a bit of a hack, we don't notify userspace of
50 * a (re-)association reply if we tried to send a reassoc
51 * and got a reject -- we only try again with an assoc
52 * frame instead of reassoc.
54 if (status_code
!= WLAN_STATUS_SUCCESS
&& wdev
->conn
&&
55 cfg80211_sme_failed_reassoc(wdev
)) {
56 cfg80211_put_bss(bss
);
60 nl80211_send_rx_assoc(rdev
, dev
, buf
, len
, GFP_KERNEL
);
62 if (status_code
!= WLAN_STATUS_SUCCESS
&& wdev
->conn
) {
63 cfg80211_sme_failed_assoc(wdev
);
65 * do not call connect_result() now because the
66 * sme will schedule work that does it later.
68 cfg80211_put_bss(bss
);
72 if (!wdev
->conn
&& wdev
->sme_state
== CFG80211_SME_IDLE
) {
74 * This is for the userspace SME, the CONNECTING
75 * state will be changed to CONNECTED by
76 * __cfg80211_connect_result() below.
78 wdev
->sme_state
= CFG80211_SME_CONNECTING
;
81 /* this consumes the bss reference */
82 __cfg80211_connect_result(dev
, mgmt
->bssid
, NULL
, 0, ie
, len
- ieoffs
,
84 status_code
== WLAN_STATUS_SUCCESS
, bss
);
88 EXPORT_SYMBOL(cfg80211_send_rx_assoc
);
90 void __cfg80211_send_deauth(struct net_device
*dev
,
91 const u8
*buf
, size_t len
)
93 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
94 struct wiphy
*wiphy
= wdev
->wiphy
;
95 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
96 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
97 const u8
*bssid
= mgmt
->bssid
;
98 bool was_current
= false;
100 ASSERT_WDEV_LOCK(wdev
);
102 if (wdev
->current_bss
&&
103 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
104 cfg80211_unhold_bss(wdev
->current_bss
);
105 cfg80211_put_bss(&wdev
->current_bss
->pub
);
106 wdev
->current_bss
= NULL
;
110 nl80211_send_deauth(rdev
, dev
, buf
, len
, GFP_KERNEL
);
112 if (wdev
->sme_state
== CFG80211_SME_CONNECTED
&& was_current
) {
116 reason_code
= le16_to_cpu(mgmt
->u
.deauth
.reason_code
);
118 from_ap
= memcmp(mgmt
->sa
, dev
->dev_addr
, ETH_ALEN
) != 0;
119 __cfg80211_disconnected(dev
, NULL
, 0, reason_code
, from_ap
);
120 } else if (wdev
->sme_state
== CFG80211_SME_CONNECTING
) {
121 __cfg80211_connect_result(dev
, mgmt
->bssid
, NULL
, 0, NULL
, 0,
122 WLAN_STATUS_UNSPECIFIED_FAILURE
,
126 EXPORT_SYMBOL(__cfg80211_send_deauth
);
128 void cfg80211_send_deauth(struct net_device
*dev
, const u8
*buf
, size_t len
)
130 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
133 __cfg80211_send_deauth(dev
, buf
, len
);
136 EXPORT_SYMBOL(cfg80211_send_deauth
);
138 void __cfg80211_send_disassoc(struct net_device
*dev
,
139 const u8
*buf
, size_t len
)
141 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
142 struct wiphy
*wiphy
= wdev
->wiphy
;
143 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
144 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
145 const u8
*bssid
= mgmt
->bssid
;
149 ASSERT_WDEV_LOCK(wdev
);
151 nl80211_send_disassoc(rdev
, dev
, buf
, len
, GFP_KERNEL
);
153 if (wdev
->sme_state
!= CFG80211_SME_CONNECTED
)
156 if (wdev
->current_bss
&&
157 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
158 cfg80211_sme_disassoc(dev
, wdev
->current_bss
);
159 cfg80211_unhold_bss(wdev
->current_bss
);
160 cfg80211_put_bss(&wdev
->current_bss
->pub
);
161 wdev
->current_bss
= NULL
;
166 reason_code
= le16_to_cpu(mgmt
->u
.disassoc
.reason_code
);
168 from_ap
= memcmp(mgmt
->sa
, dev
->dev_addr
, ETH_ALEN
) != 0;
169 __cfg80211_disconnected(dev
, NULL
, 0, reason_code
, from_ap
);
171 EXPORT_SYMBOL(__cfg80211_send_disassoc
);
173 void cfg80211_send_disassoc(struct net_device
*dev
, const u8
*buf
, size_t len
)
175 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
178 __cfg80211_send_disassoc(dev
, buf
, len
);
181 EXPORT_SYMBOL(cfg80211_send_disassoc
);
183 void cfg80211_send_unprot_deauth(struct net_device
*dev
, const u8
*buf
,
186 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
187 struct wiphy
*wiphy
= wdev
->wiphy
;
188 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
190 nl80211_send_unprot_deauth(rdev
, dev
, buf
, len
, GFP_ATOMIC
);
192 EXPORT_SYMBOL(cfg80211_send_unprot_deauth
);
194 void cfg80211_send_unprot_disassoc(struct net_device
*dev
, const u8
*buf
,
197 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
198 struct wiphy
*wiphy
= wdev
->wiphy
;
199 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
201 nl80211_send_unprot_disassoc(rdev
, dev
, buf
, len
, GFP_ATOMIC
);
203 EXPORT_SYMBOL(cfg80211_send_unprot_disassoc
);
205 void cfg80211_send_auth_timeout(struct net_device
*dev
, const u8
*addr
)
207 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
208 struct wiphy
*wiphy
= wdev
->wiphy
;
209 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
213 nl80211_send_auth_timeout(rdev
, dev
, addr
, GFP_KERNEL
);
214 if (wdev
->sme_state
== CFG80211_SME_CONNECTING
)
215 __cfg80211_connect_result(dev
, addr
, NULL
, 0, NULL
, 0,
216 WLAN_STATUS_UNSPECIFIED_FAILURE
,
221 EXPORT_SYMBOL(cfg80211_send_auth_timeout
);
223 void cfg80211_send_assoc_timeout(struct net_device
*dev
, const u8
*addr
)
225 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
226 struct wiphy
*wiphy
= wdev
->wiphy
;
227 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
231 nl80211_send_assoc_timeout(rdev
, dev
, addr
, GFP_KERNEL
);
232 if (wdev
->sme_state
== CFG80211_SME_CONNECTING
)
233 __cfg80211_connect_result(dev
, addr
, NULL
, 0, NULL
, 0,
234 WLAN_STATUS_UNSPECIFIED_FAILURE
,
239 EXPORT_SYMBOL(cfg80211_send_assoc_timeout
);
241 void cfg80211_michael_mic_failure(struct net_device
*dev
, const u8
*addr
,
242 enum nl80211_key_type key_type
, int key_id
,
243 const u8
*tsc
, gfp_t gfp
)
245 struct wiphy
*wiphy
= dev
->ieee80211_ptr
->wiphy
;
246 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
247 #ifdef CONFIG_CFG80211_WEXT
248 union iwreq_data wrqu
;
249 char *buf
= kmalloc(128, gfp
);
252 sprintf(buf
, "MLME-MICHAELMICFAILURE.indication("
253 "keyid=%d %scast addr=%pM)", key_id
,
254 key_type
== NL80211_KEYTYPE_GROUP
? "broad" : "uni",
256 memset(&wrqu
, 0, sizeof(wrqu
));
257 wrqu
.data
.length
= strlen(buf
);
258 wireless_send_event(dev
, IWEVCUSTOM
, &wrqu
, buf
);
263 nl80211_michael_mic_failure(rdev
, dev
, addr
, key_type
, key_id
, tsc
, gfp
);
265 EXPORT_SYMBOL(cfg80211_michael_mic_failure
);
267 /* some MLME handling for userspace SME */
268 int __cfg80211_mlme_auth(struct cfg80211_registered_device
*rdev
,
269 struct net_device
*dev
,
270 struct ieee80211_channel
*chan
,
271 enum nl80211_auth_type auth_type
,
273 const u8
*ssid
, int ssid_len
,
274 const u8
*ie
, int ie_len
,
275 const u8
*key
, int key_len
, int key_idx
)
277 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
278 struct cfg80211_auth_request req
;
281 ASSERT_WDEV_LOCK(wdev
);
283 if (auth_type
== NL80211_AUTHTYPE_SHARED_KEY
)
284 if (!key
|| !key_len
|| key_idx
< 0 || key_idx
> 4)
287 if (wdev
->current_bss
&&
288 memcmp(bssid
, wdev
->current_bss
->pub
.bssid
, ETH_ALEN
) == 0)
291 memset(&req
, 0, sizeof(req
));
295 req
.auth_type
= auth_type
;
296 req
.bss
= cfg80211_get_bss(&rdev
->wiphy
, chan
, bssid
, ssid
, ssid_len
,
297 WLAN_CAPABILITY_ESS
, WLAN_CAPABILITY_ESS
);
299 req
.key_len
= key_len
;
300 req
.key_idx
= key_idx
;
304 err
= rdev
->ops
->auth(&rdev
->wiphy
, dev
, &req
);
306 cfg80211_put_bss(req
.bss
);
310 int cfg80211_mlme_auth(struct cfg80211_registered_device
*rdev
,
311 struct net_device
*dev
, struct ieee80211_channel
*chan
,
312 enum nl80211_auth_type auth_type
, const u8
*bssid
,
313 const u8
*ssid
, int ssid_len
,
314 const u8
*ie
, int ie_len
,
315 const u8
*key
, int key_len
, int key_idx
)
319 wdev_lock(dev
->ieee80211_ptr
);
320 err
= __cfg80211_mlme_auth(rdev
, dev
, chan
, auth_type
, bssid
,
321 ssid
, ssid_len
, ie
, ie_len
,
322 key
, key_len
, key_idx
);
323 wdev_unlock(dev
->ieee80211_ptr
);
328 /* Do a logical ht_capa &= ht_capa_mask. */
329 void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap
*ht_capa
,
330 const struct ieee80211_ht_cap
*ht_capa_mask
)
335 memset(ht_capa
, 0, sizeof(*ht_capa
));
340 p2
= (u8
*)(ht_capa_mask
);
341 for (i
= 0; i
<sizeof(*ht_capa
); i
++)
345 int __cfg80211_mlme_assoc(struct cfg80211_registered_device
*rdev
,
346 struct net_device
*dev
,
347 struct ieee80211_channel
*chan
,
348 const u8
*bssid
, const u8
*prev_bssid
,
349 const u8
*ssid
, int ssid_len
,
350 const u8
*ie
, int ie_len
, bool use_mfp
,
351 struct cfg80211_crypto_settings
*crypt
,
352 u32 assoc_flags
, struct ieee80211_ht_cap
*ht_capa
,
353 struct ieee80211_ht_cap
*ht_capa_mask
)
355 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
356 struct cfg80211_assoc_request req
;
358 bool was_connected
= false;
360 ASSERT_WDEV_LOCK(wdev
);
362 memset(&req
, 0, sizeof(req
));
364 if (wdev
->current_bss
&& prev_bssid
&&
365 memcmp(wdev
->current_bss
->pub
.bssid
, prev_bssid
, ETH_ALEN
) == 0) {
367 * Trying to reassociate: Allow this to proceed and let the old
368 * association to be dropped when the new one is completed.
370 if (wdev
->sme_state
== CFG80211_SME_CONNECTED
) {
371 was_connected
= true;
372 wdev
->sme_state
= CFG80211_SME_CONNECTING
;
374 } else if (wdev
->current_bss
)
379 memcpy(&req
.crypto
, crypt
, sizeof(req
.crypto
));
380 req
.use_mfp
= use_mfp
;
381 req
.prev_bssid
= prev_bssid
;
382 req
.flags
= assoc_flags
;
384 memcpy(&req
.ht_capa
, ht_capa
, sizeof(req
.ht_capa
));
386 memcpy(&req
.ht_capa_mask
, ht_capa_mask
,
387 sizeof(req
.ht_capa_mask
));
388 cfg80211_oper_and_ht_capa(&req
.ht_capa_mask
,
389 rdev
->wiphy
.ht_capa_mod_mask
);
391 req
.bss
= cfg80211_get_bss(&rdev
->wiphy
, chan
, bssid
, ssid
, ssid_len
,
392 WLAN_CAPABILITY_ESS
, WLAN_CAPABILITY_ESS
);
395 wdev
->sme_state
= CFG80211_SME_CONNECTED
;
399 err
= rdev
->ops
->assoc(&rdev
->wiphy
, dev
, &req
);
403 wdev
->sme_state
= CFG80211_SME_CONNECTED
;
404 cfg80211_put_bss(req
.bss
);
410 int cfg80211_mlme_assoc(struct cfg80211_registered_device
*rdev
,
411 struct net_device
*dev
,
412 struct ieee80211_channel
*chan
,
413 const u8
*bssid
, const u8
*prev_bssid
,
414 const u8
*ssid
, int ssid_len
,
415 const u8
*ie
, int ie_len
, bool use_mfp
,
416 struct cfg80211_crypto_settings
*crypt
,
417 u32 assoc_flags
, struct ieee80211_ht_cap
*ht_capa
,
418 struct ieee80211_ht_cap
*ht_capa_mask
)
420 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
424 err
= __cfg80211_mlme_assoc(rdev
, dev
, chan
, bssid
, prev_bssid
,
425 ssid
, ssid_len
, ie
, ie_len
, use_mfp
, crypt
,
426 assoc_flags
, ht_capa
, ht_capa_mask
);
432 int __cfg80211_mlme_deauth(struct cfg80211_registered_device
*rdev
,
433 struct net_device
*dev
, const u8
*bssid
,
434 const u8
*ie
, int ie_len
, u16 reason
,
435 bool local_state_change
)
437 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
438 struct cfg80211_deauth_request req
= {
440 .reason_code
= reason
,
445 ASSERT_WDEV_LOCK(wdev
);
447 if (local_state_change
) {
448 if (wdev
->current_bss
&&
449 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
450 cfg80211_unhold_bss(wdev
->current_bss
);
451 cfg80211_put_bss(&wdev
->current_bss
->pub
);
452 wdev
->current_bss
= NULL
;
458 return rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
);
461 int cfg80211_mlme_deauth(struct cfg80211_registered_device
*rdev
,
462 struct net_device
*dev
, const u8
*bssid
,
463 const u8
*ie
, int ie_len
, u16 reason
,
464 bool local_state_change
)
466 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
470 err
= __cfg80211_mlme_deauth(rdev
, dev
, bssid
, ie
, ie_len
, reason
,
477 static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device
*rdev
,
478 struct net_device
*dev
, const u8
*bssid
,
479 const u8
*ie
, int ie_len
, u16 reason
,
480 bool local_state_change
)
482 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
483 struct cfg80211_disassoc_request req
;
485 ASSERT_WDEV_LOCK(wdev
);
487 if (wdev
->sme_state
!= CFG80211_SME_CONNECTED
)
490 if (WARN_ON(!wdev
->current_bss
))
493 memset(&req
, 0, sizeof(req
));
494 req
.reason_code
= reason
;
495 req
.local_state_change
= local_state_change
;
498 if (memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0)
499 req
.bss
= &wdev
->current_bss
->pub
;
503 return rdev
->ops
->disassoc(&rdev
->wiphy
, dev
, &req
);
506 int cfg80211_mlme_disassoc(struct cfg80211_registered_device
*rdev
,
507 struct net_device
*dev
, const u8
*bssid
,
508 const u8
*ie
, int ie_len
, u16 reason
,
509 bool local_state_change
)
511 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
515 err
= __cfg80211_mlme_disassoc(rdev
, dev
, bssid
, ie
, ie_len
, reason
,
522 void cfg80211_mlme_down(struct cfg80211_registered_device
*rdev
,
523 struct net_device
*dev
)
525 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
526 struct cfg80211_deauth_request req
;
529 ASSERT_WDEV_LOCK(wdev
);
531 if (!rdev
->ops
->deauth
)
534 memset(&req
, 0, sizeof(req
));
535 req
.reason_code
= WLAN_REASON_DEAUTH_LEAVING
;
539 if (!wdev
->current_bss
)
542 memcpy(bssid
, wdev
->current_bss
->pub
.bssid
, ETH_ALEN
);
544 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
);
546 if (wdev
->current_bss
) {
547 cfg80211_unhold_bss(wdev
->current_bss
);
548 cfg80211_put_bss(&wdev
->current_bss
->pub
);
549 wdev
->current_bss
= NULL
;
553 void cfg80211_ready_on_channel(struct net_device
*dev
, u64 cookie
,
554 struct ieee80211_channel
*chan
,
555 enum nl80211_channel_type channel_type
,
556 unsigned int duration
, gfp_t gfp
)
558 struct wiphy
*wiphy
= dev
->ieee80211_ptr
->wiphy
;
559 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
561 nl80211_send_remain_on_channel(rdev
, dev
, cookie
, chan
, channel_type
,
564 EXPORT_SYMBOL(cfg80211_ready_on_channel
);
566 void cfg80211_remain_on_channel_expired(struct net_device
*dev
,
568 struct ieee80211_channel
*chan
,
569 enum nl80211_channel_type channel_type
,
572 struct wiphy
*wiphy
= dev
->ieee80211_ptr
->wiphy
;
573 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
575 nl80211_send_remain_on_channel_cancel(rdev
, dev
, cookie
, chan
,
578 EXPORT_SYMBOL(cfg80211_remain_on_channel_expired
);
580 void cfg80211_new_sta(struct net_device
*dev
, const u8
*mac_addr
,
581 struct station_info
*sinfo
, gfp_t gfp
)
583 struct wiphy
*wiphy
= dev
->ieee80211_ptr
->wiphy
;
584 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
586 nl80211_send_sta_event(rdev
, dev
, mac_addr
, sinfo
, gfp
);
588 EXPORT_SYMBOL(cfg80211_new_sta
);
590 void cfg80211_del_sta(struct net_device
*dev
, const u8
*mac_addr
, gfp_t gfp
)
592 struct wiphy
*wiphy
= dev
->ieee80211_ptr
->wiphy
;
593 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
595 nl80211_send_sta_del_event(rdev
, dev
, mac_addr
, gfp
);
597 EXPORT_SYMBOL(cfg80211_del_sta
);
599 struct cfg80211_mgmt_registration
{
600 struct list_head list
;
611 int cfg80211_mlme_register_mgmt(struct wireless_dev
*wdev
, u32 snd_pid
,
612 u16 frame_type
, const u8
*match_data
,
615 struct wiphy
*wiphy
= wdev
->wiphy
;
616 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
617 struct cfg80211_mgmt_registration
*reg
, *nreg
;
621 if (!wdev
->wiphy
->mgmt_stypes
)
624 if ((frame_type
& IEEE80211_FCTL_FTYPE
) != IEEE80211_FTYPE_MGMT
)
627 if (frame_type
& ~(IEEE80211_FCTL_FTYPE
| IEEE80211_FCTL_STYPE
))
630 mgmt_type
= (frame_type
& IEEE80211_FCTL_STYPE
) >> 4;
631 if (!(wdev
->wiphy
->mgmt_stypes
[wdev
->iftype
].rx
& BIT(mgmt_type
)))
634 nreg
= kzalloc(sizeof(*reg
) + match_len
, GFP_KERNEL
);
638 spin_lock_bh(&wdev
->mgmt_registrations_lock
);
640 list_for_each_entry(reg
, &wdev
->mgmt_registrations
, list
) {
641 int mlen
= min(match_len
, reg
->match_len
);
643 if (frame_type
!= le16_to_cpu(reg
->frame_type
))
646 if (memcmp(reg
->match
, match_data
, mlen
) == 0) {
657 memcpy(nreg
->match
, match_data
, match_len
);
658 nreg
->match_len
= match_len
;
659 nreg
->nlpid
= snd_pid
;
660 nreg
->frame_type
= cpu_to_le16(frame_type
);
661 list_add(&nreg
->list
, &wdev
->mgmt_registrations
);
663 if (rdev
->ops
->mgmt_frame_register
)
664 rdev
->ops
->mgmt_frame_register(wiphy
, wdev
->netdev
,
668 spin_unlock_bh(&wdev
->mgmt_registrations_lock
);
673 void cfg80211_mlme_unregister_socket(struct wireless_dev
*wdev
, u32 nlpid
)
675 struct wiphy
*wiphy
= wdev
->wiphy
;
676 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
677 struct cfg80211_mgmt_registration
*reg
, *tmp
;
679 spin_lock_bh(&wdev
->mgmt_registrations_lock
);
681 list_for_each_entry_safe(reg
, tmp
, &wdev
->mgmt_registrations
, list
) {
682 if (reg
->nlpid
!= nlpid
)
685 if (rdev
->ops
->mgmt_frame_register
) {
686 u16 frame_type
= le16_to_cpu(reg
->frame_type
);
688 rdev
->ops
->mgmt_frame_register(wiphy
, wdev
->netdev
,
692 list_del(®
->list
);
696 spin_unlock_bh(&wdev
->mgmt_registrations_lock
);
698 if (nlpid
== wdev
->ap_unexpected_nlpid
)
699 wdev
->ap_unexpected_nlpid
= 0;
702 void cfg80211_mlme_purge_registrations(struct wireless_dev
*wdev
)
704 struct cfg80211_mgmt_registration
*reg
, *tmp
;
706 spin_lock_bh(&wdev
->mgmt_registrations_lock
);
708 list_for_each_entry_safe(reg
, tmp
, &wdev
->mgmt_registrations
, list
) {
709 list_del(®
->list
);
713 spin_unlock_bh(&wdev
->mgmt_registrations_lock
);
716 int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device
*rdev
,
717 struct net_device
*dev
,
718 struct ieee80211_channel
*chan
, bool offchan
,
719 enum nl80211_channel_type channel_type
,
720 bool channel_type_valid
, unsigned int wait
,
721 const u8
*buf
, size_t len
, bool no_cck
,
722 bool dont_wait_for_ack
, u64
*cookie
)
724 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
725 const struct ieee80211_mgmt
*mgmt
;
728 if (!wdev
->wiphy
->mgmt_stypes
)
731 if (!rdev
->ops
->mgmt_tx
)
737 mgmt
= (const struct ieee80211_mgmt
*) buf
;
739 if (!ieee80211_is_mgmt(mgmt
->frame_control
))
742 stype
= le16_to_cpu(mgmt
->frame_control
) & IEEE80211_FCTL_STYPE
;
743 if (!(wdev
->wiphy
->mgmt_stypes
[wdev
->iftype
].tx
& BIT(stype
>> 4)))
746 if (ieee80211_is_action(mgmt
->frame_control
) &&
747 mgmt
->u
.action
.category
!= WLAN_CATEGORY_PUBLIC
) {
752 switch (wdev
->iftype
) {
753 case NL80211_IFTYPE_ADHOC
:
754 case NL80211_IFTYPE_STATION
:
755 case NL80211_IFTYPE_P2P_CLIENT
:
756 if (!wdev
->current_bss
) {
761 if (memcmp(wdev
->current_bss
->pub
.bssid
,
762 mgmt
->bssid
, ETH_ALEN
)) {
768 * check for IBSS DA must be done by driver as
769 * cfg80211 doesn't track the stations
771 if (wdev
->iftype
== NL80211_IFTYPE_ADHOC
)
774 /* for station, check that DA is the AP */
775 if (memcmp(wdev
->current_bss
->pub
.bssid
,
776 mgmt
->da
, ETH_ALEN
)) {
781 case NL80211_IFTYPE_AP
:
782 case NL80211_IFTYPE_P2P_GO
:
783 case NL80211_IFTYPE_AP_VLAN
:
784 if (memcmp(mgmt
->bssid
, dev
->dev_addr
, ETH_ALEN
))
787 case NL80211_IFTYPE_MESH_POINT
:
788 if (memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
)) {
793 * check for mesh DA must be done by driver as
794 * cfg80211 doesn't track the stations
807 if (memcmp(mgmt
->sa
, dev
->dev_addr
, ETH_ALEN
) != 0)
810 /* Transmit the Action frame as requested by user space */
811 return rdev
->ops
->mgmt_tx(&rdev
->wiphy
, dev
, chan
, offchan
,
812 channel_type
, channel_type_valid
,
813 wait
, buf
, len
, no_cck
, dont_wait_for_ack
,
817 bool cfg80211_rx_mgmt(struct net_device
*dev
, int freq
, int sig_mbm
,
818 const u8
*buf
, size_t len
, gfp_t gfp
)
820 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
821 struct wiphy
*wiphy
= wdev
->wiphy
;
822 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
823 struct cfg80211_mgmt_registration
*reg
;
824 const struct ieee80211_txrx_stypes
*stypes
=
825 &wiphy
->mgmt_stypes
[wdev
->iftype
];
826 struct ieee80211_mgmt
*mgmt
= (void *)buf
;
830 __le16 ftype
= mgmt
->frame_control
&
831 cpu_to_le16(IEEE80211_FCTL_FTYPE
| IEEE80211_FCTL_STYPE
);
834 stype
= (le16_to_cpu(mgmt
->frame_control
) & IEEE80211_FCTL_STYPE
) >> 4;
836 if (!(stypes
->rx
& BIT(stype
)))
839 data
= buf
+ ieee80211_hdrlen(mgmt
->frame_control
);
840 data_len
= len
- ieee80211_hdrlen(mgmt
->frame_control
);
842 spin_lock_bh(&wdev
->mgmt_registrations_lock
);
844 list_for_each_entry(reg
, &wdev
->mgmt_registrations
, list
) {
845 if (reg
->frame_type
!= ftype
)
848 if (reg
->match_len
> data_len
)
851 if (memcmp(reg
->match
, data
, reg
->match_len
))
856 /* Indicate the received Action frame to user space */
857 if (nl80211_send_mgmt(rdev
, dev
, reg
->nlpid
,
866 spin_unlock_bh(&wdev
->mgmt_registrations_lock
);
870 EXPORT_SYMBOL(cfg80211_rx_mgmt
);
872 void cfg80211_mgmt_tx_status(struct net_device
*dev
, u64 cookie
,
873 const u8
*buf
, size_t len
, bool ack
, gfp_t gfp
)
875 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
876 struct wiphy
*wiphy
= wdev
->wiphy
;
877 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
879 /* Indicate TX status of the Action frame to user space */
880 nl80211_send_mgmt_tx_status(rdev
, dev
, cookie
, buf
, len
, ack
, gfp
);
882 EXPORT_SYMBOL(cfg80211_mgmt_tx_status
);
884 void cfg80211_cqm_rssi_notify(struct net_device
*dev
,
885 enum nl80211_cqm_rssi_threshold_event rssi_event
,
888 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
889 struct wiphy
*wiphy
= wdev
->wiphy
;
890 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
892 /* Indicate roaming trigger event to user space */
893 nl80211_send_cqm_rssi_notify(rdev
, dev
, rssi_event
, gfp
);
895 EXPORT_SYMBOL(cfg80211_cqm_rssi_notify
);
897 void cfg80211_cqm_pktloss_notify(struct net_device
*dev
,
898 const u8
*peer
, u32 num_packets
, gfp_t gfp
)
900 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
901 struct wiphy
*wiphy
= wdev
->wiphy
;
902 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
904 /* Indicate roaming trigger event to user space */
905 nl80211_send_cqm_pktloss_notify(rdev
, dev
, peer
, num_packets
, gfp
);
907 EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify
);
909 void cfg80211_gtk_rekey_notify(struct net_device
*dev
, const u8
*bssid
,
910 const u8
*replay_ctr
, gfp_t gfp
)
912 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
913 struct wiphy
*wiphy
= wdev
->wiphy
;
914 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
916 nl80211_gtk_rekey_notify(rdev
, dev
, bssid
, replay_ctr
, gfp
);
918 EXPORT_SYMBOL(cfg80211_gtk_rekey_notify
);
920 void cfg80211_pmksa_candidate_notify(struct net_device
*dev
, int index
,
921 const u8
*bssid
, bool preauth
, gfp_t gfp
)
923 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
924 struct wiphy
*wiphy
= wdev
->wiphy
;
925 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
927 nl80211_pmksa_candidate_notify(rdev
, dev
, index
, bssid
, preauth
, gfp
);
929 EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify
);
931 bool cfg80211_rx_spurious_frame(struct net_device
*dev
,
932 const u8
*addr
, gfp_t gfp
)
934 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
936 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_AP
&&
937 wdev
->iftype
!= NL80211_IFTYPE_P2P_GO
))
940 return nl80211_unexpected_frame(dev
, addr
, gfp
);
942 EXPORT_SYMBOL(cfg80211_rx_spurious_frame
);
944 bool cfg80211_rx_unexpected_4addr_frame(struct net_device
*dev
,
945 const u8
*addr
, gfp_t gfp
)
947 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
949 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_AP
&&
950 wdev
->iftype
!= NL80211_IFTYPE_P2P_GO
&&
951 wdev
->iftype
!= NL80211_IFTYPE_AP_VLAN
))
954 return nl80211_unexpected_4addr_frame(dev
, addr
, gfp
);
956 EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame
);