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
;
47 nl80211_send_rx_auth(rdev
, dev
, buf
, len
, GFP_KERNEL
);
48 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 * 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
);
111 need_connect_result
= false;
113 * do not call connect_result() now because the
114 * sme will schedule work that does it later.
119 if (!wdev
->conn
&& wdev
->sme_state
== CFG80211_SME_IDLE
) {
121 * This is for the userspace SME, the CONNECTING
122 * state will be changed to CONNECTED by
123 * __cfg80211_connect_result() below.
125 wdev
->sme_state
= CFG80211_SME_CONNECTING
;
128 /* this consumes one bss reference (unless bss is NULL) */
129 __cfg80211_connect_result(dev
, mgmt
->bssid
, NULL
, 0, ie
, len
- ieoffs
,
131 status_code
== WLAN_STATUS_SUCCESS
,
132 bss
? &bss
->pub
: NULL
);
133 /* drop hold now, and also reference acquired above */
135 cfg80211_unhold_bss(bss
);
136 cfg80211_put_bss(&bss
->pub
);
142 EXPORT_SYMBOL(cfg80211_send_rx_assoc
);
144 static void __cfg80211_send_deauth(struct net_device
*dev
,
145 const u8
*buf
, size_t len
)
147 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
148 struct wiphy
*wiphy
= wdev
->wiphy
;
149 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
150 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
151 const u8
*bssid
= mgmt
->bssid
;
155 ASSERT_WDEV_LOCK(wdev
);
157 nl80211_send_deauth(rdev
, dev
, buf
, len
, GFP_KERNEL
);
159 if (wdev
->current_bss
&&
160 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
162 cfg80211_unhold_bss(wdev
->current_bss
);
163 cfg80211_put_bss(&wdev
->current_bss
->pub
);
164 wdev
->current_bss
= NULL
;
165 } else for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
166 if (wdev
->auth_bsses
[i
] &&
167 memcmp(wdev
->auth_bsses
[i
]->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
168 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
169 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
170 wdev
->auth_bsses
[i
] = NULL
;
174 if (wdev
->authtry_bsses
[i
] &&
175 memcmp(wdev
->authtry_bsses
[i
]->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
176 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
177 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
178 wdev
->authtry_bsses
[i
] = NULL
;
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
,
202 void cfg80211_send_deauth(struct net_device
*dev
, const u8
*buf
, size_t len
,
205 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
207 BUG_ON(cookie
&& wdev
!= cookie
);
210 /* called within callback */
211 __cfg80211_send_deauth(dev
, buf
, len
);
214 __cfg80211_send_deauth(dev
, buf
, len
);
218 EXPORT_SYMBOL(cfg80211_send_deauth
);
220 static void __cfg80211_send_disassoc(struct net_device
*dev
,
221 const u8
*buf
, size_t len
)
223 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
224 struct wiphy
*wiphy
= wdev
->wiphy
;
225 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
226 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
227 const u8
*bssid
= mgmt
->bssid
;
233 ASSERT_WDEV_LOCK(wdev
);
235 nl80211_send_disassoc(rdev
, dev
, buf
, len
, GFP_KERNEL
);
237 if (wdev
->sme_state
!= CFG80211_SME_CONNECTED
)
240 if (wdev
->current_bss
&&
241 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
242 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
243 if (wdev
->authtry_bsses
[i
] || wdev
->auth_bsses
[i
])
245 wdev
->auth_bsses
[i
] = wdev
->current_bss
;
246 wdev
->current_bss
= NULL
;
248 cfg80211_sme_disassoc(dev
, i
);
256 reason_code
= le16_to_cpu(mgmt
->u
.disassoc
.reason_code
);
258 from_ap
= memcmp(mgmt
->sa
, dev
->dev_addr
, ETH_ALEN
) != 0;
259 __cfg80211_disconnected(dev
, NULL
, 0, reason_code
, from_ap
);
262 void cfg80211_send_disassoc(struct net_device
*dev
, const u8
*buf
, size_t len
,
265 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
267 BUG_ON(cookie
&& wdev
!= cookie
);
270 /* called within callback */
271 __cfg80211_send_disassoc(dev
, buf
, len
);
274 __cfg80211_send_disassoc(dev
, buf
, len
);
278 EXPORT_SYMBOL(cfg80211_send_disassoc
);
280 void cfg80211_send_auth_timeout(struct net_device
*dev
, const u8
*addr
)
282 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
283 struct wiphy
*wiphy
= wdev
->wiphy
;
284 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
290 nl80211_send_auth_timeout(rdev
, dev
, addr
, GFP_KERNEL
);
291 if (wdev
->sme_state
== CFG80211_SME_CONNECTING
)
292 __cfg80211_connect_result(dev
, addr
, NULL
, 0, NULL
, 0,
293 WLAN_STATUS_UNSPECIFIED_FAILURE
,
296 for (i
= 0; addr
&& i
< MAX_AUTH_BSSES
; i
++) {
297 if (wdev
->authtry_bsses
[i
] &&
298 memcmp(wdev
->authtry_bsses
[i
]->pub
.bssid
,
299 addr
, ETH_ALEN
) == 0) {
300 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
301 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
302 wdev
->authtry_bsses
[i
] = NULL
;
312 EXPORT_SYMBOL(cfg80211_send_auth_timeout
);
314 void cfg80211_send_assoc_timeout(struct net_device
*dev
, const u8
*addr
)
316 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
317 struct wiphy
*wiphy
= wdev
->wiphy
;
318 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
324 nl80211_send_assoc_timeout(rdev
, dev
, addr
, GFP_KERNEL
);
325 if (wdev
->sme_state
== CFG80211_SME_CONNECTING
)
326 __cfg80211_connect_result(dev
, addr
, NULL
, 0, NULL
, 0,
327 WLAN_STATUS_UNSPECIFIED_FAILURE
,
330 for (i
= 0; addr
&& i
< MAX_AUTH_BSSES
; i
++) {
331 if (wdev
->auth_bsses
[i
] &&
332 memcmp(wdev
->auth_bsses
[i
]->pub
.bssid
,
333 addr
, ETH_ALEN
) == 0) {
334 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
335 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
336 wdev
->auth_bsses
[i
] = NULL
;
346 EXPORT_SYMBOL(cfg80211_send_assoc_timeout
);
348 void cfg80211_michael_mic_failure(struct net_device
*dev
, const u8
*addr
,
349 enum nl80211_key_type key_type
, int key_id
,
350 const u8
*tsc
, gfp_t gfp
)
352 struct wiphy
*wiphy
= dev
->ieee80211_ptr
->wiphy
;
353 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
354 #ifdef CONFIG_WIRELESS_EXT
355 union iwreq_data wrqu
;
356 char *buf
= kmalloc(128, gfp
);
359 sprintf(buf
, "MLME-MICHAELMICFAILURE.indication("
360 "keyid=%d %scast addr=%pM)", key_id
,
361 key_type
== NL80211_KEYTYPE_GROUP
? "broad" : "uni",
363 memset(&wrqu
, 0, sizeof(wrqu
));
364 wrqu
.data
.length
= strlen(buf
);
365 wireless_send_event(dev
, IWEVCUSTOM
, &wrqu
, buf
);
370 nl80211_michael_mic_failure(rdev
, dev
, addr
, key_type
, key_id
, tsc
, gfp
);
372 EXPORT_SYMBOL(cfg80211_michael_mic_failure
);
374 /* some MLME handling for userspace SME */
375 int __cfg80211_mlme_auth(struct cfg80211_registered_device
*rdev
,
376 struct net_device
*dev
,
377 struct ieee80211_channel
*chan
,
378 enum nl80211_auth_type auth_type
,
380 const u8
*ssid
, int ssid_len
,
381 const u8
*ie
, int ie_len
,
382 const u8
*key
, int key_len
, int key_idx
)
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
));
414 req
.auth_type
= auth_type
;
415 req
.bss
= cfg80211_get_bss(&rdev
->wiphy
, chan
, bssid
, ssid
, ssid_len
,
416 WLAN_CAPABILITY_ESS
, WLAN_CAPABILITY_ESS
);
418 req
.key_len
= key_len
;
419 req
.key_idx
= key_idx
;
423 bss
= bss_from_pub(req
.bss
);
425 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
426 if (!wdev
->auth_bsses
[i
] && !wdev
->authtry_bsses
[i
]) {
432 /* we need one free slot for disassoc and one for this auth */
438 wdev
->authtry_bsses
[slot
] = bss
;
439 cfg80211_hold_bss(bss
);
441 err
= rdev
->ops
->auth(&rdev
->wiphy
, dev
, &req
);
443 wdev
->authtry_bsses
[slot
] = NULL
;
444 cfg80211_unhold_bss(bss
);
449 cfg80211_put_bss(req
.bss
);
453 int cfg80211_mlme_auth(struct cfg80211_registered_device
*rdev
,
454 struct net_device
*dev
, struct ieee80211_channel
*chan
,
455 enum nl80211_auth_type auth_type
, const u8
*bssid
,
456 const u8
*ssid
, int ssid_len
,
457 const u8
*ie
, int ie_len
,
458 const u8
*key
, int key_len
, int key_idx
)
462 wdev_lock(dev
->ieee80211_ptr
);
463 err
= __cfg80211_mlme_auth(rdev
, dev
, chan
, auth_type
, bssid
,
464 ssid
, ssid_len
, ie
, ie_len
,
465 key
, key_len
, key_idx
);
466 wdev_unlock(dev
->ieee80211_ptr
);
471 int __cfg80211_mlme_assoc(struct cfg80211_registered_device
*rdev
,
472 struct net_device
*dev
,
473 struct ieee80211_channel
*chan
,
474 const u8
*bssid
, const u8
*prev_bssid
,
475 const u8
*ssid
, int ssid_len
,
476 const u8
*ie
, int ie_len
, bool use_mfp
,
477 struct cfg80211_crypto_settings
*crypt
)
479 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
480 struct cfg80211_assoc_request req
;
481 struct cfg80211_internal_bss
*bss
;
482 int i
, err
, slot
= -1;
484 ASSERT_WDEV_LOCK(wdev
);
486 memset(&req
, 0, sizeof(req
));
488 if (wdev
->current_bss
)
493 memcpy(&req
.crypto
, crypt
, sizeof(req
.crypto
));
494 req
.use_mfp
= use_mfp
;
495 req
.prev_bssid
= prev_bssid
;
496 req
.bss
= cfg80211_get_bss(&rdev
->wiphy
, chan
, bssid
, ssid
, ssid_len
,
497 WLAN_CAPABILITY_ESS
, WLAN_CAPABILITY_ESS
);
501 bss
= bss_from_pub(req
.bss
);
503 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
504 if (bss
== wdev
->auth_bsses
[i
]) {
515 err
= rdev
->ops
->assoc(&rdev
->wiphy
, dev
, &req
);
517 /* still a reference in wdev->auth_bsses[slot] */
518 cfg80211_put_bss(req
.bss
);
522 int cfg80211_mlme_assoc(struct cfg80211_registered_device
*rdev
,
523 struct net_device
*dev
,
524 struct ieee80211_channel
*chan
,
525 const u8
*bssid
, const u8
*prev_bssid
,
526 const u8
*ssid
, int ssid_len
,
527 const u8
*ie
, int ie_len
, bool use_mfp
,
528 struct cfg80211_crypto_settings
*crypt
)
530 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
534 err
= __cfg80211_mlme_assoc(rdev
, dev
, chan
, bssid
, prev_bssid
,
535 ssid
, ssid_len
, ie
, ie_len
, use_mfp
, crypt
);
541 int __cfg80211_mlme_deauth(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_deauth_request req
;
549 ASSERT_WDEV_LOCK(wdev
);
551 memset(&req
, 0, sizeof(req
));
552 req
.reason_code
= reason
;
555 if (wdev
->current_bss
&&
556 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
557 req
.bss
= &wdev
->current_bss
->pub
;
558 } else for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
559 if (wdev
->auth_bsses
[i
] &&
560 memcmp(bssid
, wdev
->auth_bsses
[i
]->pub
.bssid
, ETH_ALEN
) == 0) {
561 req
.bss
= &wdev
->auth_bsses
[i
]->pub
;
564 if (wdev
->authtry_bsses
[i
] &&
565 memcmp(bssid
, wdev
->authtry_bsses
[i
]->pub
.bssid
, ETH_ALEN
) == 0) {
566 req
.bss
= &wdev
->authtry_bsses
[i
]->pub
;
574 return rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
577 int cfg80211_mlme_deauth(struct cfg80211_registered_device
*rdev
,
578 struct net_device
*dev
, const u8
*bssid
,
579 const u8
*ie
, int ie_len
, u16 reason
)
581 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
585 err
= __cfg80211_mlme_deauth(rdev
, dev
, bssid
, ie
, ie_len
, reason
);
591 static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device
*rdev
,
592 struct net_device
*dev
, const u8
*bssid
,
593 const u8
*ie
, int ie_len
, u16 reason
)
595 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
596 struct cfg80211_disassoc_request req
;
598 ASSERT_WDEV_LOCK(wdev
);
600 if (wdev
->sme_state
!= CFG80211_SME_CONNECTED
)
603 if (WARN_ON(!wdev
->current_bss
))
606 memset(&req
, 0, sizeof(req
));
607 req
.reason_code
= reason
;
610 if (memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0)
611 req
.bss
= &wdev
->current_bss
->pub
;
615 return rdev
->ops
->disassoc(&rdev
->wiphy
, dev
, &req
, wdev
);
618 int cfg80211_mlme_disassoc(struct cfg80211_registered_device
*rdev
,
619 struct net_device
*dev
, const u8
*bssid
,
620 const u8
*ie
, int ie_len
, u16 reason
)
622 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
626 err
= __cfg80211_mlme_disassoc(rdev
, dev
, bssid
, ie
, ie_len
, reason
);
632 void cfg80211_mlme_down(struct cfg80211_registered_device
*rdev
,
633 struct net_device
*dev
)
635 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
636 struct cfg80211_deauth_request req
;
639 ASSERT_WDEV_LOCK(wdev
);
641 if (!rdev
->ops
->deauth
)
644 memset(&req
, 0, sizeof(req
));
645 req
.reason_code
= WLAN_REASON_DEAUTH_LEAVING
;
649 if (wdev
->current_bss
) {
650 req
.bss
= &wdev
->current_bss
->pub
;
651 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
652 if (wdev
->current_bss
) {
653 cfg80211_unhold_bss(wdev
->current_bss
);
654 cfg80211_put_bss(&wdev
->current_bss
->pub
);
655 wdev
->current_bss
= NULL
;
659 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
660 if (wdev
->auth_bsses
[i
]) {
661 req
.bss
= &wdev
->auth_bsses
[i
]->pub
;
662 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
663 if (wdev
->auth_bsses
[i
]) {
664 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
665 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
666 wdev
->auth_bsses
[i
] = NULL
;
669 if (wdev
->authtry_bsses
[i
]) {
670 req
.bss
= &wdev
->authtry_bsses
[i
]->pub
;
671 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
672 if (wdev
->authtry_bsses
[i
]) {
673 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
674 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
675 wdev
->authtry_bsses
[i
] = NULL
;