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
);
99 if (!wdev
->conn
&& wdev
->sme_state
== CFG80211_SME_IDLE
) {
101 * This is for the userspace SME, the CONNECTING
102 * state will be changed to CONNECTED by
103 * __cfg80211_connect_result() below.
105 wdev
->sme_state
= CFG80211_SME_CONNECTING
;
108 /* this consumes one bss reference (unless bss is NULL) */
109 __cfg80211_connect_result(dev
, mgmt
->bssid
, NULL
, 0, ie
, len
- ieoffs
,
111 status_code
== WLAN_STATUS_SUCCESS
,
112 bss
? &bss
->pub
: NULL
);
113 /* drop hold now, and also reference acquired above */
115 cfg80211_unhold_bss(bss
);
116 cfg80211_put_bss(&bss
->pub
);
122 EXPORT_SYMBOL(cfg80211_send_rx_assoc
);
124 static void __cfg80211_send_deauth(struct net_device
*dev
,
125 const u8
*buf
, size_t len
)
127 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
128 struct wiphy
*wiphy
= wdev
->wiphy
;
129 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
130 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
131 const u8
*bssid
= mgmt
->bssid
;
135 ASSERT_WDEV_LOCK(wdev
);
137 nl80211_send_deauth(rdev
, dev
, buf
, len
, GFP_KERNEL
);
139 if (wdev
->current_bss
&&
140 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
142 cfg80211_unhold_bss(wdev
->current_bss
);
143 cfg80211_put_bss(&wdev
->current_bss
->pub
);
144 wdev
->current_bss
= NULL
;
145 } else for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
146 if (wdev
->auth_bsses
[i
] &&
147 memcmp(wdev
->auth_bsses
[i
]->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
148 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
149 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
150 wdev
->auth_bsses
[i
] = NULL
;
154 if (wdev
->authtry_bsses
[i
] &&
155 memcmp(wdev
->authtry_bsses
[i
]->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
156 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
157 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
158 wdev
->authtry_bsses
[i
] = NULL
;
166 if (wdev
->sme_state
== CFG80211_SME_CONNECTED
) {
170 reason_code
= le16_to_cpu(mgmt
->u
.deauth
.reason_code
);
172 from_ap
= memcmp(mgmt
->sa
, dev
->dev_addr
, ETH_ALEN
) != 0;
173 __cfg80211_disconnected(dev
, NULL
, 0, reason_code
, from_ap
);
174 } else if (wdev
->sme_state
== CFG80211_SME_CONNECTING
) {
175 __cfg80211_connect_result(dev
, mgmt
->bssid
, NULL
, 0, NULL
, 0,
176 WLAN_STATUS_UNSPECIFIED_FAILURE
,
182 void cfg80211_send_deauth(struct net_device
*dev
, const u8
*buf
, size_t len
,
185 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
187 BUG_ON(cookie
&& wdev
!= cookie
);
190 /* called within callback */
191 __cfg80211_send_deauth(dev
, buf
, len
);
194 __cfg80211_send_deauth(dev
, buf
, len
);
198 EXPORT_SYMBOL(cfg80211_send_deauth
);
200 static void __cfg80211_send_disassoc(struct net_device
*dev
,
201 const u8
*buf
, size_t len
)
203 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
204 struct wiphy
*wiphy
= wdev
->wiphy
;
205 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
206 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
207 const u8
*bssid
= mgmt
->bssid
;
213 ASSERT_WDEV_LOCK(wdev
);
215 nl80211_send_disassoc(rdev
, dev
, buf
, len
, GFP_KERNEL
);
217 if (wdev
->sme_state
!= CFG80211_SME_CONNECTED
)
220 if (wdev
->current_bss
&&
221 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
222 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
223 if (wdev
->authtry_bsses
[i
] || wdev
->auth_bsses
[i
])
225 wdev
->auth_bsses
[i
] = wdev
->current_bss
;
226 wdev
->current_bss
= NULL
;
228 cfg80211_sme_disassoc(dev
, i
);
236 reason_code
= le16_to_cpu(mgmt
->u
.disassoc
.reason_code
);
238 from_ap
= memcmp(mgmt
->sa
, dev
->dev_addr
, ETH_ALEN
) != 0;
239 __cfg80211_disconnected(dev
, NULL
, 0, reason_code
, from_ap
);
242 void cfg80211_send_disassoc(struct net_device
*dev
, const u8
*buf
, size_t len
,
245 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
247 BUG_ON(cookie
&& wdev
!= cookie
);
250 /* called within callback */
251 __cfg80211_send_disassoc(dev
, buf
, len
);
254 __cfg80211_send_disassoc(dev
, buf
, len
);
258 EXPORT_SYMBOL(cfg80211_send_disassoc
);
260 void cfg80211_send_auth_timeout(struct net_device
*dev
, const u8
*addr
)
262 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
263 struct wiphy
*wiphy
= wdev
->wiphy
;
264 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
270 nl80211_send_auth_timeout(rdev
, dev
, addr
, GFP_KERNEL
);
271 if (wdev
->sme_state
== CFG80211_SME_CONNECTING
)
272 __cfg80211_connect_result(dev
, addr
, NULL
, 0, NULL
, 0,
273 WLAN_STATUS_UNSPECIFIED_FAILURE
,
276 for (i
= 0; addr
&& i
< MAX_AUTH_BSSES
; i
++) {
277 if (wdev
->authtry_bsses
[i
] &&
278 memcmp(wdev
->authtry_bsses
[i
]->pub
.bssid
,
279 addr
, ETH_ALEN
) == 0) {
280 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
281 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
282 wdev
->authtry_bsses
[i
] = NULL
;
292 EXPORT_SYMBOL(cfg80211_send_auth_timeout
);
294 void cfg80211_send_assoc_timeout(struct net_device
*dev
, const u8
*addr
)
296 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
297 struct wiphy
*wiphy
= wdev
->wiphy
;
298 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
304 nl80211_send_assoc_timeout(rdev
, dev
, addr
, GFP_KERNEL
);
305 if (wdev
->sme_state
== CFG80211_SME_CONNECTING
)
306 __cfg80211_connect_result(dev
, addr
, NULL
, 0, NULL
, 0,
307 WLAN_STATUS_UNSPECIFIED_FAILURE
,
310 for (i
= 0; addr
&& i
< MAX_AUTH_BSSES
; i
++) {
311 if (wdev
->auth_bsses
[i
] &&
312 memcmp(wdev
->auth_bsses
[i
]->pub
.bssid
,
313 addr
, ETH_ALEN
) == 0) {
314 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
315 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
316 wdev
->auth_bsses
[i
] = NULL
;
326 EXPORT_SYMBOL(cfg80211_send_assoc_timeout
);
328 void cfg80211_michael_mic_failure(struct net_device
*dev
, const u8
*addr
,
329 enum nl80211_key_type key_type
, int key_id
,
330 const u8
*tsc
, gfp_t gfp
)
332 struct wiphy
*wiphy
= dev
->ieee80211_ptr
->wiphy
;
333 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
334 #ifdef CONFIG_WIRELESS_EXT
335 union iwreq_data wrqu
;
336 char *buf
= kmalloc(128, gfp
);
339 sprintf(buf
, "MLME-MICHAELMICFAILURE.indication("
340 "keyid=%d %scast addr=%pM)", key_id
,
341 key_type
== NL80211_KEYTYPE_GROUP
? "broad" : "uni",
343 memset(&wrqu
, 0, sizeof(wrqu
));
344 wrqu
.data
.length
= strlen(buf
);
345 wireless_send_event(dev
, IWEVCUSTOM
, &wrqu
, buf
);
350 nl80211_michael_mic_failure(rdev
, dev
, addr
, key_type
, key_id
, tsc
, gfp
);
352 EXPORT_SYMBOL(cfg80211_michael_mic_failure
);
354 /* some MLME handling for userspace SME */
355 int __cfg80211_mlme_auth(struct cfg80211_registered_device
*rdev
,
356 struct net_device
*dev
,
357 struct ieee80211_channel
*chan
,
358 enum nl80211_auth_type auth_type
,
360 const u8
*ssid
, int ssid_len
,
361 const u8
*ie
, int ie_len
,
362 const u8
*key
, int key_len
, int key_idx
)
364 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
365 struct cfg80211_auth_request req
;
366 struct cfg80211_internal_bss
*bss
;
367 int i
, err
, slot
= -1, nfree
= 0;
369 ASSERT_WDEV_LOCK(wdev
);
371 if (auth_type
== NL80211_AUTHTYPE_SHARED_KEY
)
372 if (!key
|| !key_len
|| key_idx
< 0 || key_idx
> 4)
375 if (wdev
->current_bss
&&
376 memcmp(bssid
, wdev
->current_bss
->pub
.bssid
, ETH_ALEN
) == 0)
379 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
380 if (wdev
->authtry_bsses
[i
] &&
381 memcmp(bssid
, wdev
->authtry_bsses
[i
]->pub
.bssid
,
384 if (wdev
->auth_bsses
[i
] &&
385 memcmp(bssid
, wdev
->auth_bsses
[i
]->pub
.bssid
,
390 memset(&req
, 0, sizeof(req
));
394 req
.auth_type
= auth_type
;
395 req
.bss
= cfg80211_get_bss(&rdev
->wiphy
, chan
, bssid
, ssid
, ssid_len
,
396 WLAN_CAPABILITY_ESS
, WLAN_CAPABILITY_ESS
);
398 req
.key_len
= key_len
;
399 req
.key_idx
= key_idx
;
403 bss
= bss_from_pub(req
.bss
);
405 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
406 if (!wdev
->auth_bsses
[i
] && !wdev
->authtry_bsses
[i
]) {
412 /* we need one free slot for disassoc and one for this auth */
418 wdev
->authtry_bsses
[slot
] = bss
;
419 cfg80211_hold_bss(bss
);
421 err
= rdev
->ops
->auth(&rdev
->wiphy
, dev
, &req
);
423 wdev
->authtry_bsses
[slot
] = NULL
;
424 cfg80211_unhold_bss(bss
);
429 cfg80211_put_bss(req
.bss
);
433 int cfg80211_mlme_auth(struct cfg80211_registered_device
*rdev
,
434 struct net_device
*dev
, struct ieee80211_channel
*chan
,
435 enum nl80211_auth_type auth_type
, const u8
*bssid
,
436 const u8
*ssid
, int ssid_len
,
437 const u8
*ie
, int ie_len
,
438 const u8
*key
, int key_len
, int key_idx
)
442 wdev_lock(dev
->ieee80211_ptr
);
443 err
= __cfg80211_mlme_auth(rdev
, dev
, chan
, auth_type
, bssid
,
444 ssid
, ssid_len
, ie
, ie_len
,
445 key
, key_len
, key_idx
);
446 wdev_unlock(dev
->ieee80211_ptr
);
451 int __cfg80211_mlme_assoc(struct cfg80211_registered_device
*rdev
,
452 struct net_device
*dev
,
453 struct ieee80211_channel
*chan
,
454 const u8
*bssid
, const u8
*prev_bssid
,
455 const u8
*ssid
, int ssid_len
,
456 const u8
*ie
, int ie_len
, bool use_mfp
,
457 struct cfg80211_crypto_settings
*crypt
)
459 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
460 struct cfg80211_assoc_request req
;
461 struct cfg80211_internal_bss
*bss
;
462 int i
, err
, slot
= -1;
464 ASSERT_WDEV_LOCK(wdev
);
466 memset(&req
, 0, sizeof(req
));
468 if (wdev
->current_bss
)
473 memcpy(&req
.crypto
, crypt
, sizeof(req
.crypto
));
474 req
.use_mfp
= use_mfp
;
475 req
.prev_bssid
= prev_bssid
;
476 req
.bss
= cfg80211_get_bss(&rdev
->wiphy
, chan
, bssid
, ssid
, ssid_len
,
477 WLAN_CAPABILITY_ESS
, WLAN_CAPABILITY_ESS
);
481 bss
= bss_from_pub(req
.bss
);
483 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
484 if (bss
== wdev
->auth_bsses
[i
]) {
495 err
= rdev
->ops
->assoc(&rdev
->wiphy
, dev
, &req
);
497 /* still a reference in wdev->auth_bsses[slot] */
498 cfg80211_put_bss(req
.bss
);
502 int cfg80211_mlme_assoc(struct cfg80211_registered_device
*rdev
,
503 struct net_device
*dev
,
504 struct ieee80211_channel
*chan
,
505 const u8
*bssid
, const u8
*prev_bssid
,
506 const u8
*ssid
, int ssid_len
,
507 const u8
*ie
, int ie_len
, bool use_mfp
,
508 struct cfg80211_crypto_settings
*crypt
)
510 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
514 err
= __cfg80211_mlme_assoc(rdev
, dev
, chan
, bssid
, prev_bssid
,
515 ssid
, ssid_len
, ie
, ie_len
, use_mfp
, crypt
);
521 int __cfg80211_mlme_deauth(struct cfg80211_registered_device
*rdev
,
522 struct net_device
*dev
, const u8
*bssid
,
523 const u8
*ie
, int ie_len
, u16 reason
)
525 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
526 struct cfg80211_deauth_request req
;
529 ASSERT_WDEV_LOCK(wdev
);
531 memset(&req
, 0, sizeof(req
));
532 req
.reason_code
= reason
;
535 if (wdev
->current_bss
&&
536 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
537 req
.bss
= &wdev
->current_bss
->pub
;
538 } else for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
539 if (wdev
->auth_bsses
[i
] &&
540 memcmp(bssid
, wdev
->auth_bsses
[i
]->pub
.bssid
, ETH_ALEN
) == 0) {
541 req
.bss
= &wdev
->auth_bsses
[i
]->pub
;
544 if (wdev
->authtry_bsses
[i
] &&
545 memcmp(bssid
, wdev
->authtry_bsses
[i
]->pub
.bssid
, ETH_ALEN
) == 0) {
546 req
.bss
= &wdev
->authtry_bsses
[i
]->pub
;
554 return rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
557 int cfg80211_mlme_deauth(struct cfg80211_registered_device
*rdev
,
558 struct net_device
*dev
, const u8
*bssid
,
559 const u8
*ie
, int ie_len
, u16 reason
)
561 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
565 err
= __cfg80211_mlme_deauth(rdev
, dev
, bssid
, ie
, ie_len
, reason
);
571 static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device
*rdev
,
572 struct net_device
*dev
, const u8
*bssid
,
573 const u8
*ie
, int ie_len
, u16 reason
)
575 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
576 struct cfg80211_disassoc_request req
;
578 ASSERT_WDEV_LOCK(wdev
);
580 if (wdev
->sme_state
!= CFG80211_SME_CONNECTED
)
583 if (WARN_ON(!wdev
->current_bss
))
586 memset(&req
, 0, sizeof(req
));
587 req
.reason_code
= reason
;
590 if (memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0)
591 req
.bss
= &wdev
->current_bss
->pub
;
595 return rdev
->ops
->disassoc(&rdev
->wiphy
, dev
, &req
, wdev
);
598 int cfg80211_mlme_disassoc(struct cfg80211_registered_device
*rdev
,
599 struct net_device
*dev
, const u8
*bssid
,
600 const u8
*ie
, int ie_len
, u16 reason
)
602 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
606 err
= __cfg80211_mlme_disassoc(rdev
, dev
, bssid
, ie
, ie_len
, reason
);
612 void cfg80211_mlme_down(struct cfg80211_registered_device
*rdev
,
613 struct net_device
*dev
)
615 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
616 struct cfg80211_deauth_request req
;
619 ASSERT_WDEV_LOCK(wdev
);
621 if (!rdev
->ops
->deauth
)
624 memset(&req
, 0, sizeof(req
));
625 req
.reason_code
= WLAN_REASON_DEAUTH_LEAVING
;
629 if (wdev
->current_bss
) {
630 req
.bss
= &wdev
->current_bss
->pub
;
631 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
632 if (wdev
->current_bss
) {
633 cfg80211_unhold_bss(wdev
->current_bss
);
634 cfg80211_put_bss(&wdev
->current_bss
->pub
);
635 wdev
->current_bss
= NULL
;
639 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
640 if (wdev
->auth_bsses
[i
]) {
641 req
.bss
= &wdev
->auth_bsses
[i
]->pub
;
642 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
643 if (wdev
->auth_bsses
[i
]) {
644 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
645 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
646 wdev
->auth_bsses
[i
] = NULL
;
649 if (wdev
->authtry_bsses
[i
]) {
650 req
.bss
= &wdev
->authtry_bsses
[i
]->pub
;
651 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
652 if (wdev
->authtry_bsses
[i
]) {
653 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
654 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
655 wdev
->authtry_bsses
[i
] = NULL
;