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
);
70 nl80211_send_rx_assoc(rdev
, dev
, buf
, len
, GFP_KERNEL
);
72 if (status_code
== WLAN_STATUS_SUCCESS
) {
73 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
74 if (!wdev
->auth_bsses
[i
])
76 if (memcmp(wdev
->auth_bsses
[i
]->pub
.bssid
, mgmt
->bssid
,
78 bss
= wdev
->auth_bsses
[i
];
79 wdev
->auth_bsses
[i
] = NULL
;
80 /* additional reference to drop hold */
81 cfg80211_ref_bss(bss
);
89 /* this consumes one bss reference (unless bss is NULL) */
90 __cfg80211_connect_result(dev
, mgmt
->bssid
, NULL
, 0, ie
, len
- ieoffs
,
92 status_code
== WLAN_STATUS_SUCCESS
,
93 bss
? &bss
->pub
: NULL
);
94 /* drop hold now, and also reference acquired above */
96 cfg80211_unhold_bss(bss
);
97 cfg80211_put_bss(&bss
->pub
);
102 EXPORT_SYMBOL(cfg80211_send_rx_assoc
);
104 static void __cfg80211_send_deauth(struct net_device
*dev
,
105 const u8
*buf
, size_t len
)
107 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
108 struct wiphy
*wiphy
= wdev
->wiphy
;
109 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
110 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
111 const u8
*bssid
= mgmt
->bssid
;
115 ASSERT_WDEV_LOCK(wdev
);
117 nl80211_send_deauth(rdev
, dev
, buf
, len
, GFP_KERNEL
);
119 if (wdev
->current_bss
&&
120 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
122 cfg80211_unhold_bss(wdev
->current_bss
);
123 cfg80211_put_bss(&wdev
->current_bss
->pub
);
124 wdev
->current_bss
= NULL
;
125 } else for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
126 if (wdev
->auth_bsses
[i
] &&
127 memcmp(wdev
->auth_bsses
[i
]->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
128 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
129 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
130 wdev
->auth_bsses
[i
] = NULL
;
134 if (wdev
->authtry_bsses
[i
] &&
135 memcmp(wdev
->authtry_bsses
[i
]->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
136 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
137 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
138 wdev
->authtry_bsses
[i
] = NULL
;
146 if (wdev
->sme_state
== CFG80211_SME_CONNECTED
) {
150 reason_code
= le16_to_cpu(mgmt
->u
.deauth
.reason_code
);
152 from_ap
= memcmp(mgmt
->da
, dev
->dev_addr
, ETH_ALEN
) == 0;
153 __cfg80211_disconnected(dev
, NULL
, 0, reason_code
, from_ap
);
154 } else if (wdev
->sme_state
== CFG80211_SME_CONNECTING
) {
155 __cfg80211_connect_result(dev
, mgmt
->bssid
, NULL
, 0, NULL
, 0,
156 WLAN_STATUS_UNSPECIFIED_FAILURE
,
162 void cfg80211_send_deauth(struct net_device
*dev
, const u8
*buf
, size_t len
,
165 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
167 BUG_ON(cookie
&& wdev
!= cookie
);
170 /* called within callback */
171 __cfg80211_send_deauth(dev
, buf
, len
);
174 __cfg80211_send_deauth(dev
, buf
, len
);
178 EXPORT_SYMBOL(cfg80211_send_deauth
);
180 static void __cfg80211_send_disassoc(struct net_device
*dev
,
181 const u8
*buf
, size_t len
)
183 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
184 struct wiphy
*wiphy
= wdev
->wiphy
;
185 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
186 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
187 const u8
*bssid
= mgmt
->bssid
;
193 ASSERT_WDEV_LOCK(wdev
);
195 nl80211_send_disassoc(rdev
, dev
, buf
, len
, GFP_KERNEL
);
197 if (wdev
->sme_state
!= CFG80211_SME_CONNECTED
)
200 if (wdev
->current_bss
&&
201 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
202 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
203 if (wdev
->authtry_bsses
[i
] || wdev
->auth_bsses
[i
])
205 wdev
->auth_bsses
[i
] = wdev
->current_bss
;
206 wdev
->current_bss
= NULL
;
208 cfg80211_sme_disassoc(dev
, i
);
216 reason_code
= le16_to_cpu(mgmt
->u
.disassoc
.reason_code
);
218 from_ap
= memcmp(mgmt
->da
, dev
->dev_addr
, ETH_ALEN
) == 0;
219 __cfg80211_disconnected(dev
, NULL
, 0, reason_code
, from_ap
);
222 void cfg80211_send_disassoc(struct net_device
*dev
, const u8
*buf
, size_t len
,
225 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
227 BUG_ON(cookie
&& wdev
!= cookie
);
230 /* called within callback */
231 __cfg80211_send_disassoc(dev
, buf
, len
);
234 __cfg80211_send_disassoc(dev
, buf
, len
);
238 EXPORT_SYMBOL(cfg80211_send_disassoc
);
240 void cfg80211_send_auth_timeout(struct net_device
*dev
, const u8
*addr
)
242 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
243 struct wiphy
*wiphy
= wdev
->wiphy
;
244 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
250 nl80211_send_auth_timeout(rdev
, dev
, addr
, GFP_KERNEL
);
251 if (wdev
->sme_state
== CFG80211_SME_CONNECTING
)
252 __cfg80211_connect_result(dev
, addr
, NULL
, 0, NULL
, 0,
253 WLAN_STATUS_UNSPECIFIED_FAILURE
,
256 for (i
= 0; addr
&& i
< MAX_AUTH_BSSES
; i
++) {
257 if (wdev
->authtry_bsses
[i
] &&
258 memcmp(wdev
->authtry_bsses
[i
]->pub
.bssid
,
259 addr
, ETH_ALEN
) == 0) {
260 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
261 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
262 wdev
->authtry_bsses
[i
] = NULL
;
272 EXPORT_SYMBOL(cfg80211_send_auth_timeout
);
274 void cfg80211_send_assoc_timeout(struct net_device
*dev
, const u8
*addr
)
276 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
277 struct wiphy
*wiphy
= wdev
->wiphy
;
278 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
284 nl80211_send_assoc_timeout(rdev
, dev
, addr
, GFP_KERNEL
);
285 if (wdev
->sme_state
== CFG80211_SME_CONNECTING
)
286 __cfg80211_connect_result(dev
, addr
, NULL
, 0, NULL
, 0,
287 WLAN_STATUS_UNSPECIFIED_FAILURE
,
290 for (i
= 0; addr
&& i
< MAX_AUTH_BSSES
; i
++) {
291 if (wdev
->auth_bsses
[i
] &&
292 memcmp(wdev
->auth_bsses
[i
]->pub
.bssid
,
293 addr
, ETH_ALEN
) == 0) {
294 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
295 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
296 wdev
->auth_bsses
[i
] = NULL
;
306 EXPORT_SYMBOL(cfg80211_send_assoc_timeout
);
308 void cfg80211_michael_mic_failure(struct net_device
*dev
, const u8
*addr
,
309 enum nl80211_key_type key_type
, int key_id
,
310 const u8
*tsc
, gfp_t gfp
)
312 struct wiphy
*wiphy
= dev
->ieee80211_ptr
->wiphy
;
313 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
314 #ifdef CONFIG_WIRELESS_EXT
315 union iwreq_data wrqu
;
316 char *buf
= kmalloc(128, gfp
);
319 sprintf(buf
, "MLME-MICHAELMICFAILURE.indication("
320 "keyid=%d %scast addr=%pM)", key_id
,
321 key_type
== NL80211_KEYTYPE_GROUP
? "broad" : "uni",
323 memset(&wrqu
, 0, sizeof(wrqu
));
324 wrqu
.data
.length
= strlen(buf
);
325 wireless_send_event(dev
, IWEVCUSTOM
, &wrqu
, buf
);
330 nl80211_michael_mic_failure(rdev
, dev
, addr
, key_type
, key_id
, tsc
, gfp
);
332 EXPORT_SYMBOL(cfg80211_michael_mic_failure
);
334 /* some MLME handling for userspace SME */
335 int __cfg80211_mlme_auth(struct cfg80211_registered_device
*rdev
,
336 struct net_device
*dev
,
337 struct ieee80211_channel
*chan
,
338 enum nl80211_auth_type auth_type
,
340 const u8
*ssid
, int ssid_len
,
341 const u8
*ie
, int ie_len
,
342 const u8
*key
, int key_len
, int key_idx
)
344 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
345 struct cfg80211_auth_request req
;
346 struct cfg80211_internal_bss
*bss
;
347 int i
, err
, slot
= -1, nfree
= 0;
349 ASSERT_WDEV_LOCK(wdev
);
351 if (auth_type
== NL80211_AUTHTYPE_SHARED_KEY
)
352 if (!key
|| !key_len
|| key_idx
< 0 || key_idx
> 4)
355 if (wdev
->current_bss
&&
356 memcmp(bssid
, wdev
->current_bss
->pub
.bssid
, ETH_ALEN
) == 0)
359 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
360 if (wdev
->authtry_bsses
[i
] &&
361 memcmp(bssid
, wdev
->authtry_bsses
[i
]->pub
.bssid
,
364 if (wdev
->auth_bsses
[i
] &&
365 memcmp(bssid
, wdev
->auth_bsses
[i
]->pub
.bssid
,
370 memset(&req
, 0, sizeof(req
));
374 req
.auth_type
= auth_type
;
375 req
.bss
= cfg80211_get_bss(&rdev
->wiphy
, chan
, bssid
, ssid
, ssid_len
,
376 WLAN_CAPABILITY_ESS
, WLAN_CAPABILITY_ESS
);
378 req
.key_len
= key_len
;
379 req
.key_idx
= key_idx
;
383 bss
= bss_from_pub(req
.bss
);
385 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
386 if (!wdev
->auth_bsses
[i
] && !wdev
->authtry_bsses
[i
]) {
392 /* we need one free slot for disassoc and one for this auth */
398 wdev
->authtry_bsses
[slot
] = bss
;
399 cfg80211_hold_bss(bss
);
401 err
= rdev
->ops
->auth(&rdev
->wiphy
, dev
, &req
);
403 wdev
->authtry_bsses
[slot
] = NULL
;
404 cfg80211_unhold_bss(bss
);
409 cfg80211_put_bss(req
.bss
);
413 int cfg80211_mlme_auth(struct cfg80211_registered_device
*rdev
,
414 struct net_device
*dev
, struct ieee80211_channel
*chan
,
415 enum nl80211_auth_type auth_type
, const u8
*bssid
,
416 const u8
*ssid
, int ssid_len
,
417 const u8
*ie
, int ie_len
,
418 const u8
*key
, int key_len
, int key_idx
)
422 wdev_lock(dev
->ieee80211_ptr
);
423 err
= __cfg80211_mlme_auth(rdev
, dev
, chan
, auth_type
, bssid
,
424 ssid
, ssid_len
, ie
, ie_len
,
425 key
, key_len
, key_idx
);
426 wdev_unlock(dev
->ieee80211_ptr
);
431 int __cfg80211_mlme_assoc(struct cfg80211_registered_device
*rdev
,
432 struct net_device
*dev
,
433 struct ieee80211_channel
*chan
,
434 const u8
*bssid
, const u8
*prev_bssid
,
435 const u8
*ssid
, int ssid_len
,
436 const u8
*ie
, int ie_len
, bool use_mfp
,
437 struct cfg80211_crypto_settings
*crypt
)
439 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
440 struct cfg80211_assoc_request req
;
441 struct cfg80211_internal_bss
*bss
;
442 int i
, err
, slot
= -1;
444 ASSERT_WDEV_LOCK(wdev
);
446 memset(&req
, 0, sizeof(req
));
448 if (wdev
->current_bss
)
453 memcpy(&req
.crypto
, crypt
, sizeof(req
.crypto
));
454 req
.use_mfp
= use_mfp
;
455 req
.prev_bssid
= prev_bssid
;
456 req
.bss
= cfg80211_get_bss(&rdev
->wiphy
, chan
, bssid
, ssid
, ssid_len
,
457 WLAN_CAPABILITY_ESS
, WLAN_CAPABILITY_ESS
);
461 bss
= bss_from_pub(req
.bss
);
463 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
464 if (bss
== wdev
->auth_bsses
[i
]) {
475 err
= rdev
->ops
->assoc(&rdev
->wiphy
, dev
, &req
);
477 /* still a reference in wdev->auth_bsses[slot] */
478 cfg80211_put_bss(req
.bss
);
482 int cfg80211_mlme_assoc(struct cfg80211_registered_device
*rdev
,
483 struct net_device
*dev
,
484 struct ieee80211_channel
*chan
,
485 const u8
*bssid
, const u8
*prev_bssid
,
486 const u8
*ssid
, int ssid_len
,
487 const u8
*ie
, int ie_len
, bool use_mfp
,
488 struct cfg80211_crypto_settings
*crypt
)
490 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
494 err
= __cfg80211_mlme_assoc(rdev
, dev
, chan
, bssid
, prev_bssid
,
495 ssid
, ssid_len
, ie
, ie_len
, use_mfp
, crypt
);
501 int __cfg80211_mlme_deauth(struct cfg80211_registered_device
*rdev
,
502 struct net_device
*dev
, const u8
*bssid
,
503 const u8
*ie
, int ie_len
, u16 reason
)
505 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
506 struct cfg80211_deauth_request req
;
509 ASSERT_WDEV_LOCK(wdev
);
511 memset(&req
, 0, sizeof(req
));
512 req
.reason_code
= reason
;
515 if (wdev
->current_bss
&&
516 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
517 req
.bss
= &wdev
->current_bss
->pub
;
518 } else for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
519 if (wdev
->auth_bsses
[i
] &&
520 memcmp(bssid
, wdev
->auth_bsses
[i
]->pub
.bssid
, ETH_ALEN
) == 0) {
521 req
.bss
= &wdev
->auth_bsses
[i
]->pub
;
524 if (wdev
->authtry_bsses
[i
] &&
525 memcmp(bssid
, wdev
->authtry_bsses
[i
]->pub
.bssid
, ETH_ALEN
) == 0) {
526 req
.bss
= &wdev
->authtry_bsses
[i
]->pub
;
534 return rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
537 int cfg80211_mlme_deauth(struct cfg80211_registered_device
*rdev
,
538 struct net_device
*dev
, const u8
*bssid
,
539 const u8
*ie
, int ie_len
, u16 reason
)
541 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
545 err
= __cfg80211_mlme_deauth(rdev
, dev
, bssid
, ie
, ie_len
, reason
);
551 static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device
*rdev
,
552 struct net_device
*dev
, const u8
*bssid
,
553 const u8
*ie
, int ie_len
, u16 reason
)
555 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
556 struct cfg80211_disassoc_request req
;
558 ASSERT_WDEV_LOCK(wdev
);
560 if (wdev
->sme_state
!= CFG80211_SME_CONNECTED
)
563 if (WARN_ON(!wdev
->current_bss
))
566 memset(&req
, 0, sizeof(req
));
567 req
.reason_code
= reason
;
570 if (memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0)
571 req
.bss
= &wdev
->current_bss
->pub
;
575 return rdev
->ops
->disassoc(&rdev
->wiphy
, dev
, &req
, wdev
);
578 int cfg80211_mlme_disassoc(struct cfg80211_registered_device
*rdev
,
579 struct net_device
*dev
, const u8
*bssid
,
580 const u8
*ie
, int ie_len
, u16 reason
)
582 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
586 err
= __cfg80211_mlme_disassoc(rdev
, dev
, bssid
, ie
, ie_len
, reason
);
592 void cfg80211_mlme_down(struct cfg80211_registered_device
*rdev
,
593 struct net_device
*dev
)
595 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
596 struct cfg80211_deauth_request req
;
599 ASSERT_WDEV_LOCK(wdev
);
601 if (!rdev
->ops
->deauth
)
604 memset(&req
, 0, sizeof(req
));
605 req
.reason_code
= WLAN_REASON_DEAUTH_LEAVING
;
609 if (wdev
->current_bss
) {
610 req
.bss
= &wdev
->current_bss
->pub
;
611 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
612 if (wdev
->current_bss
) {
613 cfg80211_unhold_bss(wdev
->current_bss
);
614 cfg80211_put_bss(&wdev
->current_bss
->pub
);
615 wdev
->current_bss
= NULL
;
619 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
620 if (wdev
->auth_bsses
[i
]) {
621 req
.bss
= &wdev
->auth_bsses
[i
]->pub
;
622 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
623 if (wdev
->auth_bsses
[i
]) {
624 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
625 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
626 wdev
->auth_bsses
[i
] = NULL
;
629 if (wdev
->authtry_bsses
[i
]) {
630 req
.bss
= &wdev
->authtry_bsses
[i
]->pub
;
631 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
632 if (wdev
->authtry_bsses
[i
]) {
633 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
634 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
635 wdev
->authtry_bsses
[i
] = NULL
;