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
);
68 status_code
= le16_to_cpu(mgmt
->u
.assoc_resp
.status_code
);
70 nl80211_send_rx_assoc(rdev
, dev
, buf
, len
, GFP_KERNEL
);
72 __cfg80211_connect_result(dev
, mgmt
->bssid
, NULL
, 0, ie
, len
- ieoffs
,
74 status_code
== WLAN_STATUS_SUCCESS
);
76 if (status_code
== WLAN_STATUS_SUCCESS
) {
77 for (i
= 0; wdev
->current_bss
&& i
< MAX_AUTH_BSSES
; i
++) {
78 if (wdev
->auth_bsses
[i
] == wdev
->current_bss
) {
79 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
80 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
81 wdev
->auth_bsses
[i
] = NULL
;
92 EXPORT_SYMBOL(cfg80211_send_rx_assoc
);
94 static void __cfg80211_send_deauth(struct net_device
*dev
,
95 const u8
*buf
, size_t len
)
97 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
98 struct wiphy
*wiphy
= wdev
->wiphy
;
99 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
100 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
101 const u8
*bssid
= mgmt
->bssid
;
105 ASSERT_WDEV_LOCK(wdev
);
107 nl80211_send_deauth(rdev
, dev
, buf
, len
, GFP_KERNEL
);
109 if (wdev
->current_bss
&&
110 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
112 cfg80211_unhold_bss(wdev
->current_bss
);
113 cfg80211_put_bss(&wdev
->current_bss
->pub
);
114 wdev
->current_bss
= NULL
;
115 } else for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
116 if (wdev
->auth_bsses
[i
] &&
117 memcmp(wdev
->auth_bsses
[i
]->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
118 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
119 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
120 wdev
->auth_bsses
[i
] = NULL
;
124 if (wdev
->authtry_bsses
[i
] &&
125 memcmp(wdev
->authtry_bsses
[i
]->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
126 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
127 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
128 wdev
->authtry_bsses
[i
] = NULL
;
136 if (wdev
->sme_state
== CFG80211_SME_CONNECTED
) {
140 reason_code
= le16_to_cpu(mgmt
->u
.deauth
.reason_code
);
142 from_ap
= memcmp(mgmt
->da
, dev
->dev_addr
, ETH_ALEN
) == 0;
143 __cfg80211_disconnected(dev
, NULL
, 0, reason_code
, from_ap
);
144 } else if (wdev
->sme_state
== CFG80211_SME_CONNECTING
) {
145 __cfg80211_connect_result(dev
, mgmt
->bssid
, NULL
, 0, NULL
, 0,
146 WLAN_STATUS_UNSPECIFIED_FAILURE
,
152 void cfg80211_send_deauth(struct net_device
*dev
, const u8
*buf
, size_t len
,
155 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
157 BUG_ON(cookie
&& wdev
!= cookie
);
160 /* called within callback */
161 __cfg80211_send_deauth(dev
, buf
, len
);
164 __cfg80211_send_deauth(dev
, buf
, len
);
168 EXPORT_SYMBOL(cfg80211_send_deauth
);
170 static void __cfg80211_send_disassoc(struct net_device
*dev
,
171 const u8
*buf
, size_t len
)
173 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
174 struct wiphy
*wiphy
= wdev
->wiphy
;
175 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
176 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
177 const u8
*bssid
= mgmt
->bssid
;
183 ASSERT_WDEV_LOCK(wdev
);
185 nl80211_send_disassoc(rdev
, dev
, buf
, len
, GFP_KERNEL
);
187 if (wdev
->sme_state
!= CFG80211_SME_CONNECTED
)
190 if (wdev
->current_bss
&&
191 memcmp(wdev
->current_bss
, bssid
, ETH_ALEN
) == 0) {
192 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
193 if (wdev
->authtry_bsses
[i
] || wdev
->auth_bsses
[i
])
195 wdev
->auth_bsses
[i
] = wdev
->current_bss
;
196 wdev
->current_bss
= NULL
;
198 cfg80211_sme_disassoc(dev
, i
);
206 reason_code
= le16_to_cpu(mgmt
->u
.disassoc
.reason_code
);
208 from_ap
= memcmp(mgmt
->da
, dev
->dev_addr
, ETH_ALEN
) == 0;
209 __cfg80211_disconnected(dev
, NULL
, 0, reason_code
, from_ap
);
212 void cfg80211_send_disassoc(struct net_device
*dev
, const u8
*buf
, size_t len
,
215 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
217 BUG_ON(cookie
&& wdev
!= cookie
);
220 /* called within callback */
221 __cfg80211_send_disassoc(dev
, buf
, len
);
224 __cfg80211_send_disassoc(dev
, buf
, len
);
228 EXPORT_SYMBOL(cfg80211_send_disassoc
);
230 void cfg80211_send_auth_timeout(struct net_device
*dev
, const u8
*addr
)
232 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
233 struct wiphy
*wiphy
= wdev
->wiphy
;
234 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
240 nl80211_send_auth_timeout(rdev
, dev
, addr
, GFP_KERNEL
);
241 if (wdev
->sme_state
== CFG80211_SME_CONNECTING
)
242 __cfg80211_connect_result(dev
, addr
, NULL
, 0, NULL
, 0,
243 WLAN_STATUS_UNSPECIFIED_FAILURE
,
246 for (i
= 0; addr
&& i
< MAX_AUTH_BSSES
; i
++) {
247 if (wdev
->authtry_bsses
[i
] &&
248 memcmp(wdev
->authtry_bsses
[i
]->pub
.bssid
,
249 addr
, ETH_ALEN
) == 0) {
250 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
251 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
252 wdev
->authtry_bsses
[i
] = NULL
;
262 EXPORT_SYMBOL(cfg80211_send_auth_timeout
);
264 void cfg80211_send_assoc_timeout(struct net_device
*dev
, const u8
*addr
)
266 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
267 struct wiphy
*wiphy
= wdev
->wiphy
;
268 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
274 nl80211_send_assoc_timeout(rdev
, dev
, addr
, GFP_KERNEL
);
275 if (wdev
->sme_state
== CFG80211_SME_CONNECTING
)
276 __cfg80211_connect_result(dev
, addr
, NULL
, 0, NULL
, 0,
277 WLAN_STATUS_UNSPECIFIED_FAILURE
,
280 for (i
= 0; addr
&& i
< MAX_AUTH_BSSES
; i
++) {
281 if (wdev
->auth_bsses
[i
] &&
282 memcmp(wdev
->auth_bsses
[i
]->pub
.bssid
,
283 addr
, ETH_ALEN
) == 0) {
284 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
285 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
286 wdev
->auth_bsses
[i
] = NULL
;
296 EXPORT_SYMBOL(cfg80211_send_assoc_timeout
);
298 void cfg80211_michael_mic_failure(struct net_device
*dev
, const u8
*addr
,
299 enum nl80211_key_type key_type
, int key_id
,
300 const u8
*tsc
, gfp_t gfp
)
302 struct wiphy
*wiphy
= dev
->ieee80211_ptr
->wiphy
;
303 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
304 #ifdef CONFIG_WIRELESS_EXT
305 union iwreq_data wrqu
;
306 char *buf
= kmalloc(128, gfp
);
309 sprintf(buf
, "MLME-MICHAELMICFAILURE.indication("
310 "keyid=%d %scast addr=%pM)", key_id
,
311 key_type
== NL80211_KEYTYPE_GROUP
? "broad" : "uni",
313 memset(&wrqu
, 0, sizeof(wrqu
));
314 wrqu
.data
.length
= strlen(buf
);
315 wireless_send_event(dev
, IWEVCUSTOM
, &wrqu
, buf
);
320 nl80211_michael_mic_failure(rdev
, dev
, addr
, key_type
, key_id
, tsc
, gfp
);
322 EXPORT_SYMBOL(cfg80211_michael_mic_failure
);
324 /* some MLME handling for userspace SME */
325 int __cfg80211_mlme_auth(struct cfg80211_registered_device
*rdev
,
326 struct net_device
*dev
,
327 struct ieee80211_channel
*chan
,
328 enum nl80211_auth_type auth_type
,
330 const u8
*ssid
, int ssid_len
,
331 const u8
*ie
, int ie_len
,
332 const u8
*key
, int key_len
, int key_idx
)
334 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
335 struct cfg80211_auth_request req
;
336 struct cfg80211_internal_bss
*bss
;
337 int i
, err
, slot
= -1, nfree
= 0;
339 ASSERT_WDEV_LOCK(wdev
);
341 if (auth_type
== NL80211_AUTHTYPE_SHARED_KEY
)
342 if (!key
|| !key_len
|| key_idx
< 0 || key_idx
> 4)
345 if (wdev
->current_bss
&&
346 memcmp(bssid
, wdev
->current_bss
->pub
.bssid
, ETH_ALEN
) == 0)
349 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
350 if (wdev
->authtry_bsses
[i
] &&
351 memcmp(bssid
, wdev
->authtry_bsses
[i
]->pub
.bssid
,
354 if (wdev
->auth_bsses
[i
] &&
355 memcmp(bssid
, wdev
->auth_bsses
[i
]->pub
.bssid
,
360 memset(&req
, 0, sizeof(req
));
364 req
.auth_type
= auth_type
;
365 req
.bss
= cfg80211_get_bss(&rdev
->wiphy
, chan
, bssid
, ssid
, ssid_len
,
366 WLAN_CAPABILITY_ESS
, WLAN_CAPABILITY_ESS
);
368 req
.key_len
= key_len
;
369 req
.key_idx
= key_idx
;
373 bss
= bss_from_pub(req
.bss
);
375 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
376 if (!wdev
->auth_bsses
[i
] && !wdev
->authtry_bsses
[i
]) {
382 /* we need one free slot for disassoc and one for this auth */
388 wdev
->authtry_bsses
[slot
] = bss
;
389 cfg80211_hold_bss(bss
);
391 err
= rdev
->ops
->auth(&rdev
->wiphy
, dev
, &req
);
393 wdev
->authtry_bsses
[slot
] = NULL
;
394 cfg80211_unhold_bss(bss
);
399 cfg80211_put_bss(req
.bss
);
403 int cfg80211_mlme_auth(struct cfg80211_registered_device
*rdev
,
404 struct net_device
*dev
, struct ieee80211_channel
*chan
,
405 enum nl80211_auth_type auth_type
, const u8
*bssid
,
406 const u8
*ssid
, int ssid_len
,
407 const u8
*ie
, int ie_len
,
408 const u8
*key
, int key_len
, int key_idx
)
412 wdev_lock(dev
->ieee80211_ptr
);
413 err
= __cfg80211_mlme_auth(rdev
, dev
, chan
, auth_type
, bssid
,
414 ssid
, ssid_len
, ie
, ie_len
,
415 key
, key_len
, key_idx
);
416 wdev_unlock(dev
->ieee80211_ptr
);
421 int __cfg80211_mlme_assoc(struct cfg80211_registered_device
*rdev
,
422 struct net_device
*dev
,
423 struct ieee80211_channel
*chan
,
424 const u8
*bssid
, const u8
*prev_bssid
,
425 const u8
*ssid
, int ssid_len
,
426 const u8
*ie
, int ie_len
, bool use_mfp
,
427 struct cfg80211_crypto_settings
*crypt
)
429 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
430 struct cfg80211_assoc_request req
;
431 struct cfg80211_internal_bss
*bss
;
432 int i
, err
, slot
= -1;
434 ASSERT_WDEV_LOCK(wdev
);
436 memset(&req
, 0, sizeof(req
));
438 if (wdev
->current_bss
)
443 memcpy(&req
.crypto
, crypt
, sizeof(req
.crypto
));
444 req
.use_mfp
= use_mfp
;
445 req
.prev_bssid
= prev_bssid
;
446 req
.bss
= cfg80211_get_bss(&rdev
->wiphy
, chan
, bssid
, ssid
, ssid_len
,
447 WLAN_CAPABILITY_ESS
, WLAN_CAPABILITY_ESS
);
451 bss
= bss_from_pub(req
.bss
);
453 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
454 if (bss
== wdev
->auth_bsses
[i
]) {
465 err
= rdev
->ops
->assoc(&rdev
->wiphy
, dev
, &req
);
467 /* still a reference in wdev->auth_bsses[slot] */
468 cfg80211_put_bss(req
.bss
);
472 int cfg80211_mlme_assoc(struct cfg80211_registered_device
*rdev
,
473 struct net_device
*dev
,
474 struct ieee80211_channel
*chan
,
475 const u8
*bssid
, const u8
*prev_bssid
,
476 const u8
*ssid
, int ssid_len
,
477 const u8
*ie
, int ie_len
, bool use_mfp
,
478 struct cfg80211_crypto_settings
*crypt
)
480 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
484 err
= __cfg80211_mlme_assoc(rdev
, dev
, chan
, bssid
, prev_bssid
,
485 ssid
, ssid_len
, ie
, ie_len
, use_mfp
, crypt
);
491 int __cfg80211_mlme_deauth(struct cfg80211_registered_device
*rdev
,
492 struct net_device
*dev
, const u8
*bssid
,
493 const u8
*ie
, int ie_len
, u16 reason
)
495 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
496 struct cfg80211_deauth_request req
;
499 ASSERT_WDEV_LOCK(wdev
);
501 memset(&req
, 0, sizeof(req
));
502 req
.reason_code
= reason
;
505 if (wdev
->current_bss
&&
506 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
507 req
.bss
= &wdev
->current_bss
->pub
;
508 } else for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
509 if (wdev
->auth_bsses
[i
] &&
510 memcmp(bssid
, wdev
->auth_bsses
[i
]->pub
.bssid
, ETH_ALEN
) == 0) {
511 req
.bss
= &wdev
->auth_bsses
[i
]->pub
;
514 if (wdev
->authtry_bsses
[i
] &&
515 memcmp(bssid
, wdev
->authtry_bsses
[i
]->pub
.bssid
, ETH_ALEN
) == 0) {
516 req
.bss
= &wdev
->authtry_bsses
[i
]->pub
;
524 return rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
527 int cfg80211_mlme_deauth(struct cfg80211_registered_device
*rdev
,
528 struct net_device
*dev
, const u8
*bssid
,
529 const u8
*ie
, int ie_len
, u16 reason
)
531 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
535 err
= __cfg80211_mlme_deauth(rdev
, dev
, bssid
, ie
, ie_len
, reason
);
541 static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device
*rdev
,
542 struct net_device
*dev
, const u8
*bssid
,
543 const u8
*ie
, int ie_len
, u16 reason
)
545 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
546 struct cfg80211_disassoc_request req
;
548 ASSERT_WDEV_LOCK(wdev
);
550 if (wdev
->sme_state
!= CFG80211_SME_CONNECTED
)
553 if (WARN_ON(!wdev
->current_bss
))
556 memset(&req
, 0, sizeof(req
));
557 req
.reason_code
= reason
;
560 if (memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0)
561 req
.bss
= &wdev
->current_bss
->pub
;
565 return rdev
->ops
->disassoc(&rdev
->wiphy
, dev
, &req
, wdev
);
568 int cfg80211_mlme_disassoc(struct cfg80211_registered_device
*rdev
,
569 struct net_device
*dev
, const u8
*bssid
,
570 const u8
*ie
, int ie_len
, u16 reason
)
572 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
576 err
= __cfg80211_mlme_disassoc(rdev
, dev
, bssid
, ie
, ie_len
, reason
);
582 void cfg80211_mlme_down(struct cfg80211_registered_device
*rdev
,
583 struct net_device
*dev
)
585 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
586 struct cfg80211_deauth_request req
;
589 ASSERT_WDEV_LOCK(wdev
);
591 if (!rdev
->ops
->deauth
)
594 memset(&req
, 0, sizeof(req
));
595 req
.reason_code
= WLAN_REASON_DEAUTH_LEAVING
;
599 if (wdev
->current_bss
) {
600 req
.bss
= &wdev
->current_bss
->pub
;
601 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
602 if (wdev
->current_bss
) {
603 cfg80211_unhold_bss(wdev
->current_bss
);
604 cfg80211_put_bss(&wdev
->current_bss
->pub
);
605 wdev
->current_bss
= NULL
;
609 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
610 if (wdev
->auth_bsses
[i
]) {
611 req
.bss
= &wdev
->auth_bsses
[i
]->pub
;
612 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
613 if (wdev
->auth_bsses
[i
]) {
614 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
615 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
616 wdev
->auth_bsses
[i
] = NULL
;
619 if (wdev
->authtry_bsses
[i
]) {
620 req
.bss
= &wdev
->authtry_bsses
[i
]->pub
;
621 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
622 if (wdev
->authtry_bsses
[i
]) {
623 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
624 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
625 wdev
->authtry_bsses
[i
] = NULL
;