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
);
23 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
24 u8
*bssid
= mgmt
->bssid
;
26 u16 status
= le16_to_cpu(mgmt
->u
.auth
.status_code
);
31 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
32 if (wdev
->authtry_bsses
[i
] &&
33 memcmp(wdev
->authtry_bsses
[i
]->pub
.bssid
, bssid
,
35 if (status
== WLAN_STATUS_SUCCESS
) {
36 wdev
->auth_bsses
[i
] = wdev
->authtry_bsses
[i
];
38 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
39 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
41 wdev
->authtry_bsses
[i
] = NULL
;
48 nl80211_send_rx_auth(rdev
, dev
, buf
, len
, GFP_KERNEL
);
49 cfg80211_sme_rx_auth(dev
, buf
, len
);
54 EXPORT_SYMBOL(cfg80211_send_rx_auth
);
56 void cfg80211_send_rx_assoc(struct net_device
*dev
, const u8
*buf
, size_t len
)
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
;
69 status_code
= le16_to_cpu(mgmt
->u
.assoc_resp
.status_code
);
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.
77 if (status_code
!= WLAN_STATUS_SUCCESS
&& wdev
->conn
&&
78 cfg80211_sme_failed_reassoc(wdev
))
81 nl80211_send_rx_assoc(rdev
, dev
, buf
, len
, GFP_KERNEL
);
83 if (status_code
== WLAN_STATUS_SUCCESS
) {
84 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
85 if (!wdev
->auth_bsses
[i
])
87 if (memcmp(wdev
->auth_bsses
[i
]->pub
.bssid
, mgmt
->bssid
,
89 bss
= wdev
->auth_bsses
[i
];
90 wdev
->auth_bsses
[i
] = NULL
;
91 /* additional reference to drop hold */
92 cfg80211_ref_bss(bss
);
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.
109 } else if (wdev
->conn
) {
110 cfg80211_sme_failed_assoc(wdev
);
112 * do not call connect_result() now because the
113 * sme will schedule work that does it later.
118 if (!wdev
->conn
&& wdev
->sme_state
== CFG80211_SME_IDLE
) {
120 * This is for the userspace SME, the CONNECTING
121 * state will be changed to CONNECTED by
122 * __cfg80211_connect_result() below.
124 wdev
->sme_state
= CFG80211_SME_CONNECTING
;
127 /* this consumes one bss reference (unless bss is NULL) */
128 __cfg80211_connect_result(dev
, mgmt
->bssid
, NULL
, 0, ie
, len
- ieoffs
,
130 status_code
== WLAN_STATUS_SUCCESS
,
131 bss
? &bss
->pub
: NULL
);
132 /* drop hold now, and also reference acquired above */
134 cfg80211_unhold_bss(bss
);
135 cfg80211_put_bss(&bss
->pub
);
141 EXPORT_SYMBOL(cfg80211_send_rx_assoc
);
143 void __cfg80211_send_deauth(struct net_device
*dev
,
144 const u8
*buf
, size_t len
)
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
;
154 ASSERT_WDEV_LOCK(wdev
);
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
;
162 } else for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
163 if (wdev
->auth_bsses
[i
] &&
164 memcmp(wdev
->auth_bsses
[i
]->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
165 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
166 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
167 wdev
->auth_bsses
[i
] = NULL
;
171 if (wdev
->authtry_bsses
[i
] &&
172 memcmp(wdev
->authtry_bsses
[i
]->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
173 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
174 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
175 wdev
->authtry_bsses
[i
] = NULL
;
184 nl80211_send_deauth(rdev
, dev
, buf
, len
, GFP_KERNEL
);
186 if (wdev
->sme_state
== CFG80211_SME_CONNECTED
) {
190 reason_code
= le16_to_cpu(mgmt
->u
.deauth
.reason_code
);
192 from_ap
= memcmp(mgmt
->sa
, dev
->dev_addr
, ETH_ALEN
) != 0;
193 __cfg80211_disconnected(dev
, NULL
, 0, reason_code
, from_ap
);
194 } else if (wdev
->sme_state
== CFG80211_SME_CONNECTING
) {
195 __cfg80211_connect_result(dev
, mgmt
->bssid
, NULL
, 0, NULL
, 0,
196 WLAN_STATUS_UNSPECIFIED_FAILURE
,
200 EXPORT_SYMBOL(__cfg80211_send_deauth
);
202 void cfg80211_send_deauth(struct net_device
*dev
, const u8
*buf
, size_t len
)
204 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
207 __cfg80211_send_deauth(dev
, buf
, len
);
210 EXPORT_SYMBOL(cfg80211_send_deauth
);
212 void __cfg80211_send_disassoc(struct net_device
*dev
,
213 const u8
*buf
, size_t len
)
215 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
216 struct wiphy
*wiphy
= wdev
->wiphy
;
217 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
218 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
219 const u8
*bssid
= mgmt
->bssid
;
225 ASSERT_WDEV_LOCK(wdev
);
227 nl80211_send_disassoc(rdev
, dev
, buf
, len
, GFP_KERNEL
);
229 if (wdev
->sme_state
!= CFG80211_SME_CONNECTED
)
232 if (wdev
->current_bss
&&
233 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
234 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
235 if (wdev
->authtry_bsses
[i
] || wdev
->auth_bsses
[i
])
237 wdev
->auth_bsses
[i
] = wdev
->current_bss
;
238 wdev
->current_bss
= NULL
;
240 cfg80211_sme_disassoc(dev
, i
);
248 reason_code
= le16_to_cpu(mgmt
->u
.disassoc
.reason_code
);
250 from_ap
= memcmp(mgmt
->sa
, dev
->dev_addr
, ETH_ALEN
) != 0;
251 __cfg80211_disconnected(dev
, NULL
, 0, reason_code
, from_ap
);
253 EXPORT_SYMBOL(__cfg80211_send_disassoc
);
255 void cfg80211_send_disassoc(struct net_device
*dev
, const u8
*buf
, size_t len
)
257 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
260 __cfg80211_send_disassoc(dev
, buf
, len
);
263 EXPORT_SYMBOL(cfg80211_send_disassoc
);
265 static void __cfg80211_auth_remove(struct wireless_dev
*wdev
, const u8
*addr
)
270 ASSERT_WDEV_LOCK(wdev
);
272 for (i
= 0; addr
&& i
< MAX_AUTH_BSSES
; i
++) {
273 if (wdev
->authtry_bsses
[i
] &&
274 memcmp(wdev
->authtry_bsses
[i
]->pub
.bssid
,
275 addr
, ETH_ALEN
) == 0) {
276 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
277 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
278 wdev
->authtry_bsses
[i
] = NULL
;
287 void __cfg80211_auth_canceled(struct net_device
*dev
, const u8
*addr
)
289 __cfg80211_auth_remove(dev
->ieee80211_ptr
, addr
);
291 EXPORT_SYMBOL(__cfg80211_auth_canceled
);
293 void cfg80211_send_auth_timeout(struct net_device
*dev
, const u8
*addr
)
295 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
296 struct wiphy
*wiphy
= wdev
->wiphy
;
297 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
301 nl80211_send_auth_timeout(rdev
, dev
, addr
, GFP_KERNEL
);
302 if (wdev
->sme_state
== CFG80211_SME_CONNECTING
)
303 __cfg80211_connect_result(dev
, addr
, NULL
, 0, NULL
, 0,
304 WLAN_STATUS_UNSPECIFIED_FAILURE
,
307 __cfg80211_auth_remove(wdev
, addr
);
311 EXPORT_SYMBOL(cfg80211_send_auth_timeout
);
313 void cfg80211_send_assoc_timeout(struct net_device
*dev
, const u8
*addr
)
315 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
316 struct wiphy
*wiphy
= wdev
->wiphy
;
317 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
323 nl80211_send_assoc_timeout(rdev
, dev
, addr
, GFP_KERNEL
);
324 if (wdev
->sme_state
== CFG80211_SME_CONNECTING
)
325 __cfg80211_connect_result(dev
, addr
, NULL
, 0, NULL
, 0,
326 WLAN_STATUS_UNSPECIFIED_FAILURE
,
329 for (i
= 0; addr
&& i
< MAX_AUTH_BSSES
; i
++) {
330 if (wdev
->auth_bsses
[i
] &&
331 memcmp(wdev
->auth_bsses
[i
]->pub
.bssid
,
332 addr
, ETH_ALEN
) == 0) {
333 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
334 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
335 wdev
->auth_bsses
[i
] = NULL
;
345 EXPORT_SYMBOL(cfg80211_send_assoc_timeout
);
347 void cfg80211_michael_mic_failure(struct net_device
*dev
, const u8
*addr
,
348 enum nl80211_key_type key_type
, int key_id
,
349 const u8
*tsc
, gfp_t gfp
)
351 struct wiphy
*wiphy
= dev
->ieee80211_ptr
->wiphy
;
352 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
353 #ifdef CONFIG_CFG80211_WEXT
354 union iwreq_data wrqu
;
355 char *buf
= kmalloc(128, gfp
);
358 sprintf(buf
, "MLME-MICHAELMICFAILURE.indication("
359 "keyid=%d %scast addr=%pM)", key_id
,
360 key_type
== NL80211_KEYTYPE_GROUP
? "broad" : "uni",
362 memset(&wrqu
, 0, sizeof(wrqu
));
363 wrqu
.data
.length
= strlen(buf
);
364 wireless_send_event(dev
, IWEVCUSTOM
, &wrqu
, buf
);
369 nl80211_michael_mic_failure(rdev
, dev
, addr
, key_type
, key_id
, tsc
, gfp
);
371 EXPORT_SYMBOL(cfg80211_michael_mic_failure
);
373 /* some MLME handling for userspace SME */
374 int __cfg80211_mlme_auth(struct cfg80211_registered_device
*rdev
,
375 struct net_device
*dev
,
376 struct ieee80211_channel
*chan
,
377 enum nl80211_auth_type auth_type
,
379 const u8
*ssid
, int ssid_len
,
380 const u8
*ie
, int ie_len
,
381 const u8
*key
, int key_len
, int key_idx
,
382 bool local_state_change
)
384 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
385 struct cfg80211_auth_request req
;
386 struct cfg80211_internal_bss
*bss
;
387 int i
, err
, slot
= -1, nfree
= 0;
389 ASSERT_WDEV_LOCK(wdev
);
391 if (auth_type
== NL80211_AUTHTYPE_SHARED_KEY
)
392 if (!key
|| !key_len
|| key_idx
< 0 || key_idx
> 4)
395 if (wdev
->current_bss
&&
396 memcmp(bssid
, wdev
->current_bss
->pub
.bssid
, ETH_ALEN
) == 0)
399 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
400 if (wdev
->authtry_bsses
[i
] &&
401 memcmp(bssid
, wdev
->authtry_bsses
[i
]->pub
.bssid
,
404 if (wdev
->auth_bsses
[i
] &&
405 memcmp(bssid
, wdev
->auth_bsses
[i
]->pub
.bssid
,
410 memset(&req
, 0, sizeof(req
));
412 req
.local_state_change
= local_state_change
;
415 req
.auth_type
= auth_type
;
416 req
.bss
= cfg80211_get_bss(&rdev
->wiphy
, chan
, bssid
, ssid
, ssid_len
,
417 WLAN_CAPABILITY_ESS
, WLAN_CAPABILITY_ESS
);
419 req
.key_len
= key_len
;
420 req
.key_idx
= key_idx
;
424 bss
= bss_from_pub(req
.bss
);
426 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
427 if (!wdev
->auth_bsses
[i
] && !wdev
->authtry_bsses
[i
]) {
433 /* we need one free slot for disassoc and one for this auth */
439 if (local_state_change
)
440 wdev
->auth_bsses
[slot
] = bss
;
442 wdev
->authtry_bsses
[slot
] = bss
;
443 cfg80211_hold_bss(bss
);
445 err
= rdev
->ops
->auth(&rdev
->wiphy
, dev
, &req
);
447 if (local_state_change
)
448 wdev
->auth_bsses
[slot
] = NULL
;
450 wdev
->authtry_bsses
[slot
] = NULL
;
451 cfg80211_unhold_bss(bss
);
456 cfg80211_put_bss(req
.bss
);
460 int cfg80211_mlme_auth(struct cfg80211_registered_device
*rdev
,
461 struct net_device
*dev
, struct ieee80211_channel
*chan
,
462 enum nl80211_auth_type auth_type
, const u8
*bssid
,
463 const u8
*ssid
, int ssid_len
,
464 const u8
*ie
, int ie_len
,
465 const u8
*key
, int key_len
, int key_idx
,
466 bool local_state_change
)
470 wdev_lock(dev
->ieee80211_ptr
);
471 err
= __cfg80211_mlme_auth(rdev
, dev
, chan
, auth_type
, bssid
,
472 ssid
, ssid_len
, ie
, ie_len
,
473 key
, key_len
, key_idx
, local_state_change
);
474 wdev_unlock(dev
->ieee80211_ptr
);
479 int __cfg80211_mlme_assoc(struct cfg80211_registered_device
*rdev
,
480 struct net_device
*dev
,
481 struct ieee80211_channel
*chan
,
482 const u8
*bssid
, const u8
*prev_bssid
,
483 const u8
*ssid
, int ssid_len
,
484 const u8
*ie
, int ie_len
, bool use_mfp
,
485 struct cfg80211_crypto_settings
*crypt
)
487 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
488 struct cfg80211_assoc_request req
;
489 struct cfg80211_internal_bss
*bss
;
490 int i
, err
, slot
= -1;
491 bool was_connected
= false;
493 ASSERT_WDEV_LOCK(wdev
);
495 memset(&req
, 0, sizeof(req
));
497 if (wdev
->current_bss
&& prev_bssid
&&
498 memcmp(wdev
->current_bss
->pub
.bssid
, prev_bssid
, ETH_ALEN
) == 0) {
500 * Trying to reassociate: Allow this to proceed and let the old
501 * association to be dropped when the new one is completed.
503 if (wdev
->sme_state
== CFG80211_SME_CONNECTED
) {
504 was_connected
= true;
505 wdev
->sme_state
= CFG80211_SME_CONNECTING
;
507 } else if (wdev
->current_bss
)
512 memcpy(&req
.crypto
, crypt
, sizeof(req
.crypto
));
513 req
.use_mfp
= use_mfp
;
514 req
.prev_bssid
= prev_bssid
;
515 req
.bss
= cfg80211_get_bss(&rdev
->wiphy
, chan
, bssid
, ssid
, ssid_len
,
516 WLAN_CAPABILITY_ESS
, WLAN_CAPABILITY_ESS
);
519 wdev
->sme_state
= CFG80211_SME_CONNECTED
;
523 bss
= bss_from_pub(req
.bss
);
525 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
526 if (bss
== wdev
->auth_bsses
[i
]) {
537 err
= rdev
->ops
->assoc(&rdev
->wiphy
, dev
, &req
);
539 if (err
&& was_connected
)
540 wdev
->sme_state
= CFG80211_SME_CONNECTED
;
541 /* still a reference in wdev->auth_bsses[slot] */
542 cfg80211_put_bss(req
.bss
);
546 int cfg80211_mlme_assoc(struct cfg80211_registered_device
*rdev
,
547 struct net_device
*dev
,
548 struct ieee80211_channel
*chan
,
549 const u8
*bssid
, const u8
*prev_bssid
,
550 const u8
*ssid
, int ssid_len
,
551 const u8
*ie
, int ie_len
, bool use_mfp
,
552 struct cfg80211_crypto_settings
*crypt
)
554 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
558 err
= __cfg80211_mlme_assoc(rdev
, dev
, chan
, bssid
, prev_bssid
,
559 ssid
, ssid_len
, ie
, ie_len
, use_mfp
, crypt
);
565 int __cfg80211_mlme_deauth(struct cfg80211_registered_device
*rdev
,
566 struct net_device
*dev
, const u8
*bssid
,
567 const u8
*ie
, int ie_len
, u16 reason
,
568 bool local_state_change
)
570 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
571 struct cfg80211_deauth_request req
;
574 ASSERT_WDEV_LOCK(wdev
);
576 memset(&req
, 0, sizeof(req
));
577 req
.reason_code
= reason
;
578 req
.local_state_change
= local_state_change
;
581 if (wdev
->current_bss
&&
582 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
583 req
.bss
= &wdev
->current_bss
->pub
;
584 } else for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
585 if (wdev
->auth_bsses
[i
] &&
586 memcmp(bssid
, wdev
->auth_bsses
[i
]->pub
.bssid
, ETH_ALEN
) == 0) {
587 req
.bss
= &wdev
->auth_bsses
[i
]->pub
;
590 if (wdev
->authtry_bsses
[i
] &&
591 memcmp(bssid
, wdev
->authtry_bsses
[i
]->pub
.bssid
, ETH_ALEN
) == 0) {
592 req
.bss
= &wdev
->authtry_bsses
[i
]->pub
;
600 return rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
603 int cfg80211_mlme_deauth(struct cfg80211_registered_device
*rdev
,
604 struct net_device
*dev
, const u8
*bssid
,
605 const u8
*ie
, int ie_len
, u16 reason
,
606 bool local_state_change
)
608 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
612 err
= __cfg80211_mlme_deauth(rdev
, dev
, bssid
, ie
, ie_len
, reason
,
619 static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device
*rdev
,
620 struct net_device
*dev
, const u8
*bssid
,
621 const u8
*ie
, int ie_len
, u16 reason
,
622 bool local_state_change
)
624 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
625 struct cfg80211_disassoc_request req
;
627 ASSERT_WDEV_LOCK(wdev
);
629 if (wdev
->sme_state
!= CFG80211_SME_CONNECTED
)
632 if (WARN_ON(!wdev
->current_bss
))
635 memset(&req
, 0, sizeof(req
));
636 req
.reason_code
= reason
;
637 req
.local_state_change
= local_state_change
;
640 if (memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0)
641 req
.bss
= &wdev
->current_bss
->pub
;
645 return rdev
->ops
->disassoc(&rdev
->wiphy
, dev
, &req
, wdev
);
648 int cfg80211_mlme_disassoc(struct cfg80211_registered_device
*rdev
,
649 struct net_device
*dev
, const u8
*bssid
,
650 const u8
*ie
, int ie_len
, u16 reason
,
651 bool local_state_change
)
653 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
657 err
= __cfg80211_mlme_disassoc(rdev
, dev
, bssid
, ie
, ie_len
, reason
,
664 void cfg80211_mlme_down(struct cfg80211_registered_device
*rdev
,
665 struct net_device
*dev
)
667 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
668 struct cfg80211_deauth_request req
;
671 ASSERT_WDEV_LOCK(wdev
);
673 if (!rdev
->ops
->deauth
)
676 memset(&req
, 0, sizeof(req
));
677 req
.reason_code
= WLAN_REASON_DEAUTH_LEAVING
;
681 if (wdev
->current_bss
) {
682 req
.bss
= &wdev
->current_bss
->pub
;
683 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
684 if (wdev
->current_bss
) {
685 cfg80211_unhold_bss(wdev
->current_bss
);
686 cfg80211_put_bss(&wdev
->current_bss
->pub
);
687 wdev
->current_bss
= NULL
;
691 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
692 if (wdev
->auth_bsses
[i
]) {
693 req
.bss
= &wdev
->auth_bsses
[i
]->pub
;
694 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
695 if (wdev
->auth_bsses
[i
]) {
696 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
697 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
698 wdev
->auth_bsses
[i
] = NULL
;
701 if (wdev
->authtry_bsses
[i
]) {
702 req
.bss
= &wdev
->authtry_bsses
[i
]->pub
;
703 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
704 if (wdev
->authtry_bsses
[i
]) {
705 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
706 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
707 wdev
->authtry_bsses
[i
] = NULL
;
713 void cfg80211_ready_on_channel(struct net_device
*dev
, u64 cookie
,
714 struct ieee80211_channel
*chan
,
715 enum nl80211_channel_type channel_type
,
716 unsigned int duration
, gfp_t gfp
)
718 struct wiphy
*wiphy
= dev
->ieee80211_ptr
->wiphy
;
719 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
721 nl80211_send_remain_on_channel(rdev
, dev
, cookie
, chan
, channel_type
,
724 EXPORT_SYMBOL(cfg80211_ready_on_channel
);
726 void cfg80211_remain_on_channel_expired(struct net_device
*dev
,
728 struct ieee80211_channel
*chan
,
729 enum nl80211_channel_type channel_type
,
732 struct wiphy
*wiphy
= dev
->ieee80211_ptr
->wiphy
;
733 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
735 nl80211_send_remain_on_channel_cancel(rdev
, dev
, cookie
, chan
,
738 EXPORT_SYMBOL(cfg80211_remain_on_channel_expired
);
740 void cfg80211_new_sta(struct net_device
*dev
, const u8
*mac_addr
,
741 struct station_info
*sinfo
, gfp_t gfp
)
743 struct wiphy
*wiphy
= dev
->ieee80211_ptr
->wiphy
;
744 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
746 nl80211_send_sta_event(rdev
, dev
, mac_addr
, sinfo
, gfp
);
748 EXPORT_SYMBOL(cfg80211_new_sta
);
750 struct cfg80211_action_registration
{
751 struct list_head list
;
760 int cfg80211_mlme_register_action(struct wireless_dev
*wdev
, u32 snd_pid
,
761 const u8
*match_data
, int match_len
)
763 struct cfg80211_action_registration
*reg
, *nreg
;
766 nreg
= kzalloc(sizeof(*reg
) + match_len
, GFP_KERNEL
);
770 spin_lock_bh(&wdev
->action_registrations_lock
);
772 list_for_each_entry(reg
, &wdev
->action_registrations
, list
) {
773 int mlen
= min(match_len
, reg
->match_len
);
775 if (memcmp(reg
->match
, match_data
, mlen
) == 0) {
786 memcpy(nreg
->match
, match_data
, match_len
);
787 nreg
->match_len
= match_len
;
788 nreg
->nlpid
= snd_pid
;
789 list_add(&nreg
->list
, &wdev
->action_registrations
);
792 spin_unlock_bh(&wdev
->action_registrations_lock
);
796 void cfg80211_mlme_unregister_actions(struct wireless_dev
*wdev
, u32 nlpid
)
798 struct cfg80211_action_registration
*reg
, *tmp
;
800 spin_lock_bh(&wdev
->action_registrations_lock
);
802 list_for_each_entry_safe(reg
, tmp
, &wdev
->action_registrations
, list
) {
803 if (reg
->nlpid
== nlpid
) {
804 list_del(®
->list
);
809 spin_unlock_bh(&wdev
->action_registrations_lock
);
812 void cfg80211_mlme_purge_actions(struct wireless_dev
*wdev
)
814 struct cfg80211_action_registration
*reg
, *tmp
;
816 spin_lock_bh(&wdev
->action_registrations_lock
);
818 list_for_each_entry_safe(reg
, tmp
, &wdev
->action_registrations
, list
) {
819 list_del(®
->list
);
823 spin_unlock_bh(&wdev
->action_registrations_lock
);
826 int cfg80211_mlme_action(struct cfg80211_registered_device
*rdev
,
827 struct net_device
*dev
,
828 struct ieee80211_channel
*chan
,
829 enum nl80211_channel_type channel_type
,
830 bool channel_type_valid
,
831 const u8
*buf
, size_t len
, u64
*cookie
)
833 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
834 const struct ieee80211_mgmt
*mgmt
;
836 if (rdev
->ops
->action
== NULL
)
841 mgmt
= (const struct ieee80211_mgmt
*) buf
;
842 if (!ieee80211_is_action(mgmt
->frame_control
))
844 if (mgmt
->u
.action
.category
!= WLAN_CATEGORY_PUBLIC
) {
845 /* Verify that we are associated with the destination AP */
848 if (!wdev
->current_bss
||
849 memcmp(wdev
->current_bss
->pub
.bssid
, mgmt
->bssid
,
851 (wdev
->iftype
== NL80211_IFTYPE_STATION
&&
852 memcmp(wdev
->current_bss
->pub
.bssid
, mgmt
->da
,
861 if (memcmp(mgmt
->sa
, dev
->dev_addr
, ETH_ALEN
) != 0)
864 /* Transmit the Action frame as requested by user space */
865 return rdev
->ops
->action(&rdev
->wiphy
, dev
, chan
, channel_type
,
866 channel_type_valid
, buf
, len
, cookie
);
869 bool cfg80211_rx_action(struct net_device
*dev
, int freq
, const u8
*buf
,
870 size_t len
, gfp_t gfp
)
872 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
873 struct wiphy
*wiphy
= wdev
->wiphy
;
874 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
875 struct cfg80211_action_registration
*reg
;
876 const u8
*action_data
;
880 /* frame length - min size excluding category */
881 action_data_len
= len
- (IEEE80211_MIN_ACTION_SIZE
- 1);
883 /* action data starts with category */
884 action_data
= buf
+ IEEE80211_MIN_ACTION_SIZE
- 1;
886 spin_lock_bh(&wdev
->action_registrations_lock
);
888 list_for_each_entry(reg
, &wdev
->action_registrations
, list
) {
889 if (reg
->match_len
> action_data_len
)
892 if (memcmp(reg
->match
, action_data
, reg
->match_len
))
897 /* Indicate the received Action frame to user space */
898 if (nl80211_send_action(rdev
, dev
, reg
->nlpid
, freq
,
906 spin_unlock_bh(&wdev
->action_registrations_lock
);
910 EXPORT_SYMBOL(cfg80211_rx_action
);
912 void cfg80211_action_tx_status(struct net_device
*dev
, u64 cookie
,
913 const u8
*buf
, size_t len
, bool ack
, gfp_t gfp
)
915 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
916 struct wiphy
*wiphy
= wdev
->wiphy
;
917 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
919 /* Indicate TX status of the Action frame to user space */
920 nl80211_send_action_tx_status(rdev
, dev
, cookie
, buf
, len
, ack
, gfp
);
922 EXPORT_SYMBOL(cfg80211_action_tx_status
);
924 void cfg80211_cqm_rssi_notify(struct net_device
*dev
,
925 enum nl80211_cqm_rssi_threshold_event rssi_event
,
928 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
929 struct wiphy
*wiphy
= wdev
->wiphy
;
930 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
932 /* Indicate roaming trigger event to user space */
933 nl80211_send_cqm_rssi_notify(rdev
, dev
, rssi_event
, gfp
);
935 EXPORT_SYMBOL(cfg80211_cqm_rssi_notify
);