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
;
65 bool need_connect_result
= true;
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 } else if (wdev
->conn
) {
99 cfg80211_sme_failed_assoc(wdev
);
100 need_connect_result
= false;
102 * do not call connect_result() now because the
103 * sme will schedule work that does it later.
108 if (!wdev
->conn
&& wdev
->sme_state
== CFG80211_SME_IDLE
) {
110 * This is for the userspace SME, the CONNECTING
111 * state will be changed to CONNECTED by
112 * __cfg80211_connect_result() below.
114 wdev
->sme_state
= CFG80211_SME_CONNECTING
;
117 /* this consumes one bss reference (unless bss is NULL) */
118 __cfg80211_connect_result(dev
, mgmt
->bssid
, NULL
, 0, ie
, len
- ieoffs
,
120 status_code
== WLAN_STATUS_SUCCESS
,
121 bss
? &bss
->pub
: NULL
);
122 /* drop hold now, and also reference acquired above */
124 cfg80211_unhold_bss(bss
);
125 cfg80211_put_bss(&bss
->pub
);
131 EXPORT_SYMBOL(cfg80211_send_rx_assoc
);
133 static void __cfg80211_send_deauth(struct net_device
*dev
,
134 const u8
*buf
, size_t len
)
136 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
137 struct wiphy
*wiphy
= wdev
->wiphy
;
138 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
139 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
140 const u8
*bssid
= mgmt
->bssid
;
144 ASSERT_WDEV_LOCK(wdev
);
146 nl80211_send_deauth(rdev
, dev
, buf
, len
, GFP_KERNEL
);
148 if (wdev
->current_bss
&&
149 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
151 cfg80211_unhold_bss(wdev
->current_bss
);
152 cfg80211_put_bss(&wdev
->current_bss
->pub
);
153 wdev
->current_bss
= NULL
;
154 } else for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
155 if (wdev
->auth_bsses
[i
] &&
156 memcmp(wdev
->auth_bsses
[i
]->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
157 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
158 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
159 wdev
->auth_bsses
[i
] = NULL
;
163 if (wdev
->authtry_bsses
[i
] &&
164 memcmp(wdev
->authtry_bsses
[i
]->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
165 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
166 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
167 wdev
->authtry_bsses
[i
] = NULL
;
175 if (wdev
->sme_state
== CFG80211_SME_CONNECTED
) {
179 reason_code
= le16_to_cpu(mgmt
->u
.deauth
.reason_code
);
181 from_ap
= memcmp(mgmt
->sa
, dev
->dev_addr
, ETH_ALEN
) != 0;
182 __cfg80211_disconnected(dev
, NULL
, 0, reason_code
, from_ap
);
183 } else if (wdev
->sme_state
== CFG80211_SME_CONNECTING
) {
184 __cfg80211_connect_result(dev
, mgmt
->bssid
, NULL
, 0, NULL
, 0,
185 WLAN_STATUS_UNSPECIFIED_FAILURE
,
191 void cfg80211_send_deauth(struct net_device
*dev
, const u8
*buf
, size_t len
,
194 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
196 BUG_ON(cookie
&& wdev
!= cookie
);
199 /* called within callback */
200 __cfg80211_send_deauth(dev
, buf
, len
);
203 __cfg80211_send_deauth(dev
, buf
, len
);
207 EXPORT_SYMBOL(cfg80211_send_deauth
);
209 static void __cfg80211_send_disassoc(struct net_device
*dev
,
210 const u8
*buf
, size_t len
)
212 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
213 struct wiphy
*wiphy
= wdev
->wiphy
;
214 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
215 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
216 const u8
*bssid
= mgmt
->bssid
;
222 ASSERT_WDEV_LOCK(wdev
);
224 nl80211_send_disassoc(rdev
, dev
, buf
, len
, GFP_KERNEL
);
226 if (wdev
->sme_state
!= CFG80211_SME_CONNECTED
)
229 if (wdev
->current_bss
&&
230 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
231 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
232 if (wdev
->authtry_bsses
[i
] || wdev
->auth_bsses
[i
])
234 wdev
->auth_bsses
[i
] = wdev
->current_bss
;
235 wdev
->current_bss
= NULL
;
237 cfg80211_sme_disassoc(dev
, i
);
245 reason_code
= le16_to_cpu(mgmt
->u
.disassoc
.reason_code
);
247 from_ap
= memcmp(mgmt
->sa
, dev
->dev_addr
, ETH_ALEN
) != 0;
248 __cfg80211_disconnected(dev
, NULL
, 0, reason_code
, from_ap
);
251 void cfg80211_send_disassoc(struct net_device
*dev
, const u8
*buf
, size_t len
,
254 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
256 BUG_ON(cookie
&& wdev
!= cookie
);
259 /* called within callback */
260 __cfg80211_send_disassoc(dev
, buf
, len
);
263 __cfg80211_send_disassoc(dev
, buf
, len
);
267 EXPORT_SYMBOL(cfg80211_send_disassoc
);
269 void cfg80211_send_auth_timeout(struct net_device
*dev
, const u8
*addr
)
271 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
272 struct wiphy
*wiphy
= wdev
->wiphy
;
273 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
279 nl80211_send_auth_timeout(rdev
, dev
, addr
, GFP_KERNEL
);
280 if (wdev
->sme_state
== CFG80211_SME_CONNECTING
)
281 __cfg80211_connect_result(dev
, addr
, NULL
, 0, NULL
, 0,
282 WLAN_STATUS_UNSPECIFIED_FAILURE
,
285 for (i
= 0; addr
&& i
< MAX_AUTH_BSSES
; i
++) {
286 if (wdev
->authtry_bsses
[i
] &&
287 memcmp(wdev
->authtry_bsses
[i
]->pub
.bssid
,
288 addr
, ETH_ALEN
) == 0) {
289 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
290 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
291 wdev
->authtry_bsses
[i
] = NULL
;
301 EXPORT_SYMBOL(cfg80211_send_auth_timeout
);
303 void cfg80211_send_assoc_timeout(struct net_device
*dev
, const u8
*addr
)
305 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
306 struct wiphy
*wiphy
= wdev
->wiphy
;
307 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
313 nl80211_send_assoc_timeout(rdev
, dev
, addr
, GFP_KERNEL
);
314 if (wdev
->sme_state
== CFG80211_SME_CONNECTING
)
315 __cfg80211_connect_result(dev
, addr
, NULL
, 0, NULL
, 0,
316 WLAN_STATUS_UNSPECIFIED_FAILURE
,
319 for (i
= 0; addr
&& i
< MAX_AUTH_BSSES
; i
++) {
320 if (wdev
->auth_bsses
[i
] &&
321 memcmp(wdev
->auth_bsses
[i
]->pub
.bssid
,
322 addr
, ETH_ALEN
) == 0) {
323 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
324 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
325 wdev
->auth_bsses
[i
] = NULL
;
335 EXPORT_SYMBOL(cfg80211_send_assoc_timeout
);
337 void cfg80211_michael_mic_failure(struct net_device
*dev
, const u8
*addr
,
338 enum nl80211_key_type key_type
, int key_id
,
339 const u8
*tsc
, gfp_t gfp
)
341 struct wiphy
*wiphy
= dev
->ieee80211_ptr
->wiphy
;
342 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
343 #ifdef CONFIG_WIRELESS_EXT
344 union iwreq_data wrqu
;
345 char *buf
= kmalloc(128, gfp
);
348 sprintf(buf
, "MLME-MICHAELMICFAILURE.indication("
349 "keyid=%d %scast addr=%pM)", key_id
,
350 key_type
== NL80211_KEYTYPE_GROUP
? "broad" : "uni",
352 memset(&wrqu
, 0, sizeof(wrqu
));
353 wrqu
.data
.length
= strlen(buf
);
354 wireless_send_event(dev
, IWEVCUSTOM
, &wrqu
, buf
);
359 nl80211_michael_mic_failure(rdev
, dev
, addr
, key_type
, key_id
, tsc
, gfp
);
361 EXPORT_SYMBOL(cfg80211_michael_mic_failure
);
363 /* some MLME handling for userspace SME */
364 int __cfg80211_mlme_auth(struct cfg80211_registered_device
*rdev
,
365 struct net_device
*dev
,
366 struct ieee80211_channel
*chan
,
367 enum nl80211_auth_type auth_type
,
369 const u8
*ssid
, int ssid_len
,
370 const u8
*ie
, int ie_len
,
371 const u8
*key
, int key_len
, int key_idx
)
373 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
374 struct cfg80211_auth_request req
;
375 struct cfg80211_internal_bss
*bss
;
376 int i
, err
, slot
= -1, nfree
= 0;
378 ASSERT_WDEV_LOCK(wdev
);
380 if (auth_type
== NL80211_AUTHTYPE_SHARED_KEY
)
381 if (!key
|| !key_len
|| key_idx
< 0 || key_idx
> 4)
384 if (wdev
->current_bss
&&
385 memcmp(bssid
, wdev
->current_bss
->pub
.bssid
, ETH_ALEN
) == 0)
388 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
389 if (wdev
->authtry_bsses
[i
] &&
390 memcmp(bssid
, wdev
->authtry_bsses
[i
]->pub
.bssid
,
393 if (wdev
->auth_bsses
[i
] &&
394 memcmp(bssid
, wdev
->auth_bsses
[i
]->pub
.bssid
,
399 memset(&req
, 0, sizeof(req
));
403 req
.auth_type
= auth_type
;
404 req
.bss
= cfg80211_get_bss(&rdev
->wiphy
, chan
, bssid
, ssid
, ssid_len
,
405 WLAN_CAPABILITY_ESS
, WLAN_CAPABILITY_ESS
);
407 req
.key_len
= key_len
;
408 req
.key_idx
= key_idx
;
412 bss
= bss_from_pub(req
.bss
);
414 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
415 if (!wdev
->auth_bsses
[i
] && !wdev
->authtry_bsses
[i
]) {
421 /* we need one free slot for disassoc and one for this auth */
427 wdev
->authtry_bsses
[slot
] = bss
;
428 cfg80211_hold_bss(bss
);
430 err
= rdev
->ops
->auth(&rdev
->wiphy
, dev
, &req
);
432 wdev
->authtry_bsses
[slot
] = NULL
;
433 cfg80211_unhold_bss(bss
);
438 cfg80211_put_bss(req
.bss
);
442 int cfg80211_mlme_auth(struct cfg80211_registered_device
*rdev
,
443 struct net_device
*dev
, struct ieee80211_channel
*chan
,
444 enum nl80211_auth_type auth_type
, const u8
*bssid
,
445 const u8
*ssid
, int ssid_len
,
446 const u8
*ie
, int ie_len
,
447 const u8
*key
, int key_len
, int key_idx
)
451 wdev_lock(dev
->ieee80211_ptr
);
452 err
= __cfg80211_mlme_auth(rdev
, dev
, chan
, auth_type
, bssid
,
453 ssid
, ssid_len
, ie
, ie_len
,
454 key
, key_len
, key_idx
);
455 wdev_unlock(dev
->ieee80211_ptr
);
460 int __cfg80211_mlme_assoc(struct cfg80211_registered_device
*rdev
,
461 struct net_device
*dev
,
462 struct ieee80211_channel
*chan
,
463 const u8
*bssid
, const u8
*prev_bssid
,
464 const u8
*ssid
, int ssid_len
,
465 const u8
*ie
, int ie_len
, bool use_mfp
,
466 struct cfg80211_crypto_settings
*crypt
)
468 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
469 struct cfg80211_assoc_request req
;
470 struct cfg80211_internal_bss
*bss
;
471 int i
, err
, slot
= -1;
473 ASSERT_WDEV_LOCK(wdev
);
475 memset(&req
, 0, sizeof(req
));
477 if (wdev
->current_bss
)
482 memcpy(&req
.crypto
, crypt
, sizeof(req
.crypto
));
483 req
.use_mfp
= use_mfp
;
484 req
.prev_bssid
= prev_bssid
;
485 req
.bss
= cfg80211_get_bss(&rdev
->wiphy
, chan
, bssid
, ssid
, ssid_len
,
486 WLAN_CAPABILITY_ESS
, WLAN_CAPABILITY_ESS
);
490 bss
= bss_from_pub(req
.bss
);
492 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
493 if (bss
== wdev
->auth_bsses
[i
]) {
504 err
= rdev
->ops
->assoc(&rdev
->wiphy
, dev
, &req
);
506 /* still a reference in wdev->auth_bsses[slot] */
507 cfg80211_put_bss(req
.bss
);
511 int cfg80211_mlme_assoc(struct cfg80211_registered_device
*rdev
,
512 struct net_device
*dev
,
513 struct ieee80211_channel
*chan
,
514 const u8
*bssid
, const u8
*prev_bssid
,
515 const u8
*ssid
, int ssid_len
,
516 const u8
*ie
, int ie_len
, bool use_mfp
,
517 struct cfg80211_crypto_settings
*crypt
)
519 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
523 err
= __cfg80211_mlme_assoc(rdev
, dev
, chan
, bssid
, prev_bssid
,
524 ssid
, ssid_len
, ie
, ie_len
, use_mfp
, crypt
);
530 int __cfg80211_mlme_deauth(struct cfg80211_registered_device
*rdev
,
531 struct net_device
*dev
, const u8
*bssid
,
532 const u8
*ie
, int ie_len
, u16 reason
)
534 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
535 struct cfg80211_deauth_request req
;
538 ASSERT_WDEV_LOCK(wdev
);
540 memset(&req
, 0, sizeof(req
));
541 req
.reason_code
= reason
;
544 if (wdev
->current_bss
&&
545 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
546 req
.bss
= &wdev
->current_bss
->pub
;
547 } else for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
548 if (wdev
->auth_bsses
[i
] &&
549 memcmp(bssid
, wdev
->auth_bsses
[i
]->pub
.bssid
, ETH_ALEN
) == 0) {
550 req
.bss
= &wdev
->auth_bsses
[i
]->pub
;
553 if (wdev
->authtry_bsses
[i
] &&
554 memcmp(bssid
, wdev
->authtry_bsses
[i
]->pub
.bssid
, ETH_ALEN
) == 0) {
555 req
.bss
= &wdev
->authtry_bsses
[i
]->pub
;
563 return rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
566 int cfg80211_mlme_deauth(struct cfg80211_registered_device
*rdev
,
567 struct net_device
*dev
, const u8
*bssid
,
568 const u8
*ie
, int ie_len
, u16 reason
)
570 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
574 err
= __cfg80211_mlme_deauth(rdev
, dev
, bssid
, ie
, ie_len
, reason
);
580 static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device
*rdev
,
581 struct net_device
*dev
, const u8
*bssid
,
582 const u8
*ie
, int ie_len
, u16 reason
)
584 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
585 struct cfg80211_disassoc_request req
;
587 ASSERT_WDEV_LOCK(wdev
);
589 if (wdev
->sme_state
!= CFG80211_SME_CONNECTED
)
592 if (WARN_ON(!wdev
->current_bss
))
595 memset(&req
, 0, sizeof(req
));
596 req
.reason_code
= reason
;
599 if (memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0)
600 req
.bss
= &wdev
->current_bss
->pub
;
604 return rdev
->ops
->disassoc(&rdev
->wiphy
, dev
, &req
, wdev
);
607 int cfg80211_mlme_disassoc(struct cfg80211_registered_device
*rdev
,
608 struct net_device
*dev
, const u8
*bssid
,
609 const u8
*ie
, int ie_len
, u16 reason
)
611 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
615 err
= __cfg80211_mlme_disassoc(rdev
, dev
, bssid
, ie
, ie_len
, reason
);
621 void cfg80211_mlme_down(struct cfg80211_registered_device
*rdev
,
622 struct net_device
*dev
)
624 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
625 struct cfg80211_deauth_request req
;
628 ASSERT_WDEV_LOCK(wdev
);
630 if (!rdev
->ops
->deauth
)
633 memset(&req
, 0, sizeof(req
));
634 req
.reason_code
= WLAN_REASON_DEAUTH_LEAVING
;
638 if (wdev
->current_bss
) {
639 req
.bss
= &wdev
->current_bss
->pub
;
640 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
641 if (wdev
->current_bss
) {
642 cfg80211_unhold_bss(wdev
->current_bss
);
643 cfg80211_put_bss(&wdev
->current_bss
->pub
);
644 wdev
->current_bss
= NULL
;
648 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
649 if (wdev
->auth_bsses
[i
]) {
650 req
.bss
= &wdev
->auth_bsses
[i
]->pub
;
651 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
652 if (wdev
->auth_bsses
[i
]) {
653 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
654 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
655 wdev
->auth_bsses
[i
] = NULL
;
658 if (wdev
->authtry_bsses
[i
]) {
659 req
.bss
= &wdev
->authtry_bsses
[i
]->pub
;
660 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
661 if (wdev
->authtry_bsses
[i
]) {
662 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
663 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
664 wdev
->authtry_bsses
[i
] = NULL
;