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 <net/cfg80211.h>
15 void cfg80211_send_rx_auth(struct net_device
*dev
, const u8
*buf
, size_t len
)
17 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
18 struct wiphy
*wiphy
= wdev
->wiphy
;
19 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
20 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
21 u8
*bssid
= mgmt
->bssid
;
23 u16 status
= le16_to_cpu(mgmt
->u
.auth
.status_code
);
28 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
29 if (wdev
->authtry_bsses
[i
] &&
30 memcmp(wdev
->authtry_bsses
[i
]->pub
.bssid
, bssid
,
32 if (status
== WLAN_STATUS_SUCCESS
) {
33 wdev
->auth_bsses
[i
] = wdev
->authtry_bsses
[i
];
35 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
36 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
38 wdev
->authtry_bsses
[i
] = NULL
;
46 nl80211_send_rx_auth(rdev
, dev
, buf
, len
, GFP_KERNEL
);
47 cfg80211_sme_rx_auth(dev
, buf
, len
);
51 EXPORT_SYMBOL(cfg80211_send_rx_auth
);
53 void cfg80211_send_rx_assoc(struct net_device
*dev
, const u8
*buf
, size_t len
)
56 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
57 struct wiphy
*wiphy
= wdev
->wiphy
;
58 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
59 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
60 u8
*ie
= mgmt
->u
.assoc_resp
.variable
;
61 int i
, ieoffs
= offsetof(struct ieee80211_mgmt
, u
.assoc_resp
.variable
);
66 status_code
= le16_to_cpu(mgmt
->u
.assoc_resp
.status_code
);
68 nl80211_send_rx_assoc(rdev
, dev
, buf
, len
, GFP_KERNEL
);
70 __cfg80211_connect_result(dev
, mgmt
->bssid
, NULL
, 0, ie
, len
- ieoffs
,
72 status_code
== WLAN_STATUS_SUCCESS
);
74 if (status_code
== WLAN_STATUS_SUCCESS
) {
75 for (i
= 0; wdev
->current_bss
&& i
< MAX_AUTH_BSSES
; i
++) {
76 if (wdev
->auth_bsses
[i
] == wdev
->current_bss
) {
77 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
78 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
79 wdev
->auth_bsses
[i
] = NULL
;
90 EXPORT_SYMBOL(cfg80211_send_rx_assoc
);
92 static void __cfg80211_send_deauth(struct net_device
*dev
,
93 const u8
*buf
, size_t len
)
95 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
96 struct wiphy
*wiphy
= wdev
->wiphy
;
97 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
98 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
99 const u8
*bssid
= mgmt
->bssid
;
103 ASSERT_WDEV_LOCK(wdev
);
105 nl80211_send_deauth(rdev
, dev
, buf
, len
, GFP_KERNEL
);
107 if (wdev
->current_bss
&&
108 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
110 cfg80211_unhold_bss(wdev
->current_bss
);
111 cfg80211_put_bss(&wdev
->current_bss
->pub
);
112 wdev
->current_bss
= NULL
;
113 } else for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
114 if (wdev
->auth_bsses
[i
] &&
115 memcmp(wdev
->auth_bsses
[i
]->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
116 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
117 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
118 wdev
->auth_bsses
[i
] = NULL
;
122 if (wdev
->authtry_bsses
[i
] &&
123 memcmp(wdev
->authtry_bsses
[i
]->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
124 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
125 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
126 wdev
->authtry_bsses
[i
] = NULL
;
134 if (wdev
->sme_state
== CFG80211_SME_CONNECTED
) {
138 reason_code
= le16_to_cpu(mgmt
->u
.deauth
.reason_code
);
140 from_ap
= memcmp(mgmt
->da
, dev
->dev_addr
, ETH_ALEN
) == 0;
141 __cfg80211_disconnected(dev
, NULL
, 0, reason_code
, from_ap
);
142 } else if (wdev
->sme_state
== CFG80211_SME_CONNECTING
) {
143 __cfg80211_connect_result(dev
, mgmt
->bssid
, NULL
, 0, NULL
, 0,
144 WLAN_STATUS_UNSPECIFIED_FAILURE
,
150 void cfg80211_send_deauth(struct net_device
*dev
, const u8
*buf
, size_t len
,
153 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
155 BUG_ON(cookie
&& wdev
!= cookie
);
158 /* called within callback */
159 __cfg80211_send_deauth(dev
, buf
, len
);
162 __cfg80211_send_deauth(dev
, buf
, len
);
166 EXPORT_SYMBOL(cfg80211_send_deauth
);
168 static void __cfg80211_send_disassoc(struct net_device
*dev
,
169 const u8
*buf
, size_t len
)
171 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
172 struct wiphy
*wiphy
= wdev
->wiphy
;
173 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
174 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
175 const u8
*bssid
= mgmt
->bssid
;
181 ASSERT_WDEV_LOCK(wdev
);
183 nl80211_send_disassoc(rdev
, dev
, buf
, len
, GFP_KERNEL
);
185 if (wdev
->sme_state
!= CFG80211_SME_CONNECTED
)
188 if (wdev
->current_bss
&&
189 memcmp(wdev
->current_bss
, bssid
, ETH_ALEN
) == 0) {
190 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
191 if (wdev
->authtry_bsses
[i
] || wdev
->auth_bsses
[i
])
193 wdev
->auth_bsses
[i
] = wdev
->current_bss
;
194 wdev
->current_bss
= NULL
;
196 cfg80211_sme_disassoc(dev
, i
);
204 reason_code
= le16_to_cpu(mgmt
->u
.disassoc
.reason_code
);
206 from_ap
= memcmp(mgmt
->da
, dev
->dev_addr
, ETH_ALEN
) == 0;
207 __cfg80211_disconnected(dev
, NULL
, 0, reason_code
, from_ap
);
210 void cfg80211_send_disassoc(struct net_device
*dev
, const u8
*buf
, size_t len
,
213 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
215 BUG_ON(cookie
&& wdev
!= cookie
);
218 /* called within callback */
219 __cfg80211_send_disassoc(dev
, buf
, len
);
222 __cfg80211_send_disassoc(dev
, buf
, len
);
226 EXPORT_SYMBOL(cfg80211_send_disassoc
);
228 void cfg80211_send_auth_timeout(struct net_device
*dev
, const u8
*addr
)
230 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
231 struct wiphy
*wiphy
= wdev
->wiphy
;
232 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
238 nl80211_send_auth_timeout(rdev
, dev
, addr
, GFP_KERNEL
);
239 if (wdev
->sme_state
== CFG80211_SME_CONNECTING
)
240 __cfg80211_connect_result(dev
, addr
, NULL
, 0, NULL
, 0,
241 WLAN_STATUS_UNSPECIFIED_FAILURE
,
244 for (i
= 0; addr
&& i
< MAX_AUTH_BSSES
; i
++) {
245 if (wdev
->authtry_bsses
[i
] &&
246 memcmp(wdev
->authtry_bsses
[i
]->pub
.bssid
,
247 addr
, ETH_ALEN
) == 0) {
248 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
249 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
250 wdev
->authtry_bsses
[i
] = NULL
;
260 EXPORT_SYMBOL(cfg80211_send_auth_timeout
);
262 void cfg80211_send_assoc_timeout(struct net_device
*dev
, const u8
*addr
)
264 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
265 struct wiphy
*wiphy
= wdev
->wiphy
;
266 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
272 nl80211_send_assoc_timeout(rdev
, dev
, addr
, GFP_KERNEL
);
273 if (wdev
->sme_state
== CFG80211_SME_CONNECTING
)
274 __cfg80211_connect_result(dev
, addr
, NULL
, 0, NULL
, 0,
275 WLAN_STATUS_UNSPECIFIED_FAILURE
,
278 for (i
= 0; addr
&& i
< MAX_AUTH_BSSES
; i
++) {
279 if (wdev
->auth_bsses
[i
] &&
280 memcmp(wdev
->auth_bsses
[i
]->pub
.bssid
,
281 addr
, ETH_ALEN
) == 0) {
282 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
283 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
284 wdev
->auth_bsses
[i
] = NULL
;
294 EXPORT_SYMBOL(cfg80211_send_assoc_timeout
);
296 void cfg80211_michael_mic_failure(struct net_device
*dev
, const u8
*addr
,
297 enum nl80211_key_type key_type
, int key_id
,
298 const u8
*tsc
, gfp_t gfp
)
300 struct wiphy
*wiphy
= dev
->ieee80211_ptr
->wiphy
;
301 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
302 #ifdef CONFIG_WIRELESS_EXT
303 union iwreq_data wrqu
;
304 char *buf
= kmalloc(128, gfp
);
307 sprintf(buf
, "MLME-MICHAELMICFAILURE.indication("
308 "keyid=%d %scast addr=%pM)", key_id
,
309 key_type
== NL80211_KEYTYPE_GROUP
? "broad" : "uni",
311 memset(&wrqu
, 0, sizeof(wrqu
));
312 wrqu
.data
.length
= strlen(buf
);
313 wireless_send_event(dev
, IWEVCUSTOM
, &wrqu
, buf
);
318 nl80211_michael_mic_failure(rdev
, dev
, addr
, key_type
, key_id
, tsc
, gfp
);
320 EXPORT_SYMBOL(cfg80211_michael_mic_failure
);
322 /* some MLME handling for userspace SME */
323 int __cfg80211_mlme_auth(struct cfg80211_registered_device
*rdev
,
324 struct net_device
*dev
,
325 struct ieee80211_channel
*chan
,
326 enum nl80211_auth_type auth_type
,
328 const u8
*ssid
, int ssid_len
,
329 const u8
*ie
, int ie_len
,
330 const u8
*key
, int key_len
, int key_idx
)
332 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
333 struct cfg80211_auth_request req
;
334 struct cfg80211_internal_bss
*bss
;
335 int i
, err
, slot
= -1, nfree
= 0;
337 ASSERT_WDEV_LOCK(wdev
);
339 if (auth_type
== NL80211_AUTHTYPE_SHARED_KEY
)
340 if (!key
|| !key_len
|| key_idx
< 0 || key_idx
> 4)
343 if (wdev
->current_bss
&&
344 memcmp(bssid
, wdev
->current_bss
->pub
.bssid
, ETH_ALEN
) == 0)
347 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
348 if (wdev
->authtry_bsses
[i
] &&
349 memcmp(bssid
, wdev
->authtry_bsses
[i
]->pub
.bssid
,
352 if (wdev
->auth_bsses
[i
] &&
353 memcmp(bssid
, wdev
->auth_bsses
[i
]->pub
.bssid
,
358 memset(&req
, 0, sizeof(req
));
362 req
.auth_type
= auth_type
;
363 req
.bss
= cfg80211_get_bss(&rdev
->wiphy
, chan
, bssid
, ssid
, ssid_len
,
364 WLAN_CAPABILITY_ESS
, WLAN_CAPABILITY_ESS
);
366 req
.key_len
= key_len
;
367 req
.key_idx
= key_idx
;
371 bss
= bss_from_pub(req
.bss
);
373 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
374 if (!wdev
->auth_bsses
[i
] && !wdev
->authtry_bsses
[i
]) {
380 /* we need one free slot for disassoc and one for this auth */
386 wdev
->authtry_bsses
[slot
] = bss
;
387 cfg80211_hold_bss(bss
);
389 err
= rdev
->ops
->auth(&rdev
->wiphy
, dev
, &req
);
391 wdev
->authtry_bsses
[slot
] = NULL
;
392 cfg80211_unhold_bss(bss
);
397 cfg80211_put_bss(req
.bss
);
401 int cfg80211_mlme_auth(struct cfg80211_registered_device
*rdev
,
402 struct net_device
*dev
, struct ieee80211_channel
*chan
,
403 enum nl80211_auth_type auth_type
, const u8
*bssid
,
404 const u8
*ssid
, int ssid_len
,
405 const u8
*ie
, int ie_len
,
406 const u8
*key
, int key_len
, int key_idx
)
410 wdev_lock(dev
->ieee80211_ptr
);
411 err
= __cfg80211_mlme_auth(rdev
, dev
, chan
, auth_type
, bssid
,
412 ssid
, ssid_len
, ie
, ie_len
,
413 key
, key_len
, key_idx
);
414 wdev_unlock(dev
->ieee80211_ptr
);
419 int __cfg80211_mlme_assoc(struct cfg80211_registered_device
*rdev
,
420 struct net_device
*dev
,
421 struct ieee80211_channel
*chan
,
422 const u8
*bssid
, const u8
*prev_bssid
,
423 const u8
*ssid
, int ssid_len
,
424 const u8
*ie
, int ie_len
, bool use_mfp
,
425 struct cfg80211_crypto_settings
*crypt
)
427 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
428 struct cfg80211_assoc_request req
;
429 struct cfg80211_internal_bss
*bss
;
430 int i
, err
, slot
= -1;
432 ASSERT_WDEV_LOCK(wdev
);
434 memset(&req
, 0, sizeof(req
));
436 if (wdev
->current_bss
)
441 memcpy(&req
.crypto
, crypt
, sizeof(req
.crypto
));
442 req
.use_mfp
= use_mfp
;
443 req
.prev_bssid
= prev_bssid
;
444 req
.bss
= cfg80211_get_bss(&rdev
->wiphy
, chan
, bssid
, ssid
, ssid_len
,
445 WLAN_CAPABILITY_ESS
, WLAN_CAPABILITY_ESS
);
449 bss
= bss_from_pub(req
.bss
);
451 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
452 if (bss
== wdev
->auth_bsses
[i
]) {
463 err
= rdev
->ops
->assoc(&rdev
->wiphy
, dev
, &req
);
465 /* still a reference in wdev->auth_bsses[slot] */
466 cfg80211_put_bss(req
.bss
);
470 int cfg80211_mlme_assoc(struct cfg80211_registered_device
*rdev
,
471 struct net_device
*dev
,
472 struct ieee80211_channel
*chan
,
473 const u8
*bssid
, const u8
*prev_bssid
,
474 const u8
*ssid
, int ssid_len
,
475 const u8
*ie
, int ie_len
, bool use_mfp
,
476 struct cfg80211_crypto_settings
*crypt
)
478 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
482 err
= __cfg80211_mlme_assoc(rdev
, dev
, chan
, bssid
, prev_bssid
,
483 ssid
, ssid_len
, ie
, ie_len
, use_mfp
, crypt
);
489 int __cfg80211_mlme_deauth(struct cfg80211_registered_device
*rdev
,
490 struct net_device
*dev
, const u8
*bssid
,
491 const u8
*ie
, int ie_len
, u16 reason
)
493 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
494 struct cfg80211_deauth_request req
;
497 ASSERT_WDEV_LOCK(wdev
);
499 memset(&req
, 0, sizeof(req
));
500 req
.reason_code
= reason
;
503 if (wdev
->current_bss
&&
504 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
505 req
.bss
= &wdev
->current_bss
->pub
;
506 } else for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
507 if (wdev
->auth_bsses
[i
] &&
508 memcmp(bssid
, wdev
->auth_bsses
[i
]->pub
.bssid
, ETH_ALEN
) == 0) {
509 req
.bss
= &wdev
->auth_bsses
[i
]->pub
;
512 if (wdev
->authtry_bsses
[i
] &&
513 memcmp(bssid
, wdev
->authtry_bsses
[i
]->pub
.bssid
, ETH_ALEN
) == 0) {
514 req
.bss
= &wdev
->authtry_bsses
[i
]->pub
;
522 return rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
525 int cfg80211_mlme_deauth(struct cfg80211_registered_device
*rdev
,
526 struct net_device
*dev
, const u8
*bssid
,
527 const u8
*ie
, int ie_len
, u16 reason
)
529 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
533 err
= __cfg80211_mlme_deauth(rdev
, dev
, bssid
, ie
, ie_len
, reason
);
539 static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device
*rdev
,
540 struct net_device
*dev
, const u8
*bssid
,
541 const u8
*ie
, int ie_len
, u16 reason
)
543 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
544 struct cfg80211_disassoc_request req
;
546 ASSERT_WDEV_LOCK(wdev
);
548 memset(&req
, 0, sizeof(req
));
549 req
.reason_code
= reason
;
552 if (memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0)
553 req
.bss
= &wdev
->current_bss
->pub
;
557 return rdev
->ops
->disassoc(&rdev
->wiphy
, dev
, &req
, wdev
);
560 int cfg80211_mlme_disassoc(struct cfg80211_registered_device
*rdev
,
561 struct net_device
*dev
, const u8
*bssid
,
562 const u8
*ie
, int ie_len
, u16 reason
)
564 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
568 err
= __cfg80211_mlme_disassoc(rdev
, dev
, bssid
, ie
, ie_len
, reason
);
574 void cfg80211_mlme_down(struct cfg80211_registered_device
*rdev
,
575 struct net_device
*dev
)
577 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
578 struct cfg80211_deauth_request req
;
581 ASSERT_WDEV_LOCK(wdev
);
583 if (!rdev
->ops
->deauth
)
586 memset(&req
, 0, sizeof(req
));
587 req
.reason_code
= WLAN_REASON_DEAUTH_LEAVING
;
591 if (wdev
->current_bss
) {
592 req
.bss
= &wdev
->current_bss
->pub
;
593 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
594 if (wdev
->current_bss
) {
595 cfg80211_unhold_bss(wdev
->current_bss
);
596 cfg80211_put_bss(&wdev
->current_bss
->pub
);
597 wdev
->current_bss
= NULL
;
601 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
602 if (wdev
->auth_bsses
[i
]) {
603 req
.bss
= &wdev
->auth_bsses
[i
]->pub
;
604 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
605 if (wdev
->auth_bsses
[i
]) {
606 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
607 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
608 wdev
->auth_bsses
[i
] = NULL
;
611 if (wdev
->authtry_bsses
[i
]) {
612 req
.bss
= &wdev
->authtry_bsses
[i
]->pub
;
613 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
, wdev
);
614 if (wdev
->authtry_bsses
[i
]) {
615 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
616 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
617 wdev
->authtry_bsses
[i
] = NULL
;