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
);
49 EXPORT_SYMBOL(cfg80211_send_rx_auth
);
51 void cfg80211_send_rx_assoc(struct net_device
*dev
, const u8
*buf
, size_t len
)
54 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
55 struct wiphy
*wiphy
= wdev
->wiphy
;
56 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
57 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
58 u8
*ie
= mgmt
->u
.assoc_resp
.variable
;
59 int i
, ieoffs
= offsetof(struct ieee80211_mgmt
, u
.assoc_resp
.variable
);
64 status_code
= le16_to_cpu(mgmt
->u
.assoc_resp
.status_code
);
66 nl80211_send_rx_assoc(rdev
, dev
, buf
, len
, GFP_KERNEL
);
68 cfg80211_connect_result(dev
, mgmt
->bssid
, NULL
, 0, ie
, len
- ieoffs
,
69 status_code
, GFP_KERNEL
);
71 if (status_code
== WLAN_STATUS_SUCCESS
) {
72 for (i
= 0; wdev
->current_bss
&& i
< MAX_AUTH_BSSES
; i
++) {
73 if (wdev
->auth_bsses
[i
] == wdev
->current_bss
) {
74 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
75 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
76 wdev
->auth_bsses
[i
] = NULL
;
85 EXPORT_SYMBOL(cfg80211_send_rx_assoc
);
87 void cfg80211_send_deauth(struct net_device
*dev
, const u8
*buf
, size_t len
)
89 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
90 struct wiphy
*wiphy
= wdev
->wiphy
;
91 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
92 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
93 const u8
*bssid
= mgmt
->bssid
;
99 nl80211_send_deauth(rdev
, dev
, buf
, len
, GFP_KERNEL
);
101 if (wdev
->current_bss
&&
102 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
104 cfg80211_unhold_bss(wdev
->current_bss
);
105 cfg80211_put_bss(&wdev
->current_bss
->pub
);
106 wdev
->current_bss
= NULL
;
107 } else for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
108 if (wdev
->auth_bsses
[i
] &&
109 memcmp(wdev
->auth_bsses
[i
]->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
110 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
111 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
112 wdev
->auth_bsses
[i
] = NULL
;
116 if (wdev
->authtry_bsses
[i
] &&
117 memcmp(wdev
->authtry_bsses
[i
]->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
118 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
119 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
120 wdev
->authtry_bsses
[i
] = NULL
;
128 if (wdev
->sme_state
== CFG80211_SME_CONNECTED
) {
132 reason_code
= le16_to_cpu(mgmt
->u
.deauth
.reason_code
);
134 from_ap
= memcmp(mgmt
->da
, dev
->dev_addr
, ETH_ALEN
) == 0;
135 __cfg80211_disconnected(dev
, GFP_KERNEL
, NULL
, 0,
136 reason_code
, from_ap
);
137 } else if (wdev
->sme_state
== CFG80211_SME_CONNECTING
) {
138 cfg80211_connect_result(dev
, mgmt
->bssid
, NULL
, 0, NULL
, 0,
139 WLAN_STATUS_UNSPECIFIED_FAILURE
,
143 EXPORT_SYMBOL(cfg80211_send_deauth
);
145 void cfg80211_send_disassoc(struct net_device
*dev
, 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
;
159 nl80211_send_disassoc(rdev
, dev
, buf
, len
, GFP_KERNEL
);
161 if (!wdev
->sme_state
== CFG80211_SME_CONNECTED
)
164 if (wdev
->current_bss
&&
165 memcmp(wdev
->current_bss
, bssid
, ETH_ALEN
) == 0) {
166 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
167 if (wdev
->authtry_bsses
[i
] || wdev
->auth_bsses
[i
])
169 wdev
->auth_bsses
[i
] = wdev
->current_bss
;
170 wdev
->current_bss
= NULL
;
172 cfg80211_sme_disassoc(dev
, i
);
180 reason_code
= le16_to_cpu(mgmt
->u
.disassoc
.reason_code
);
182 from_ap
= memcmp(mgmt
->da
, dev
->dev_addr
, ETH_ALEN
) == 0;
183 __cfg80211_disconnected(dev
, GFP_KERNEL
, NULL
, 0,
184 reason_code
, from_ap
);
186 EXPORT_SYMBOL(cfg80211_send_disassoc
);
188 void cfg80211_send_auth_timeout(struct net_device
*dev
, const u8
*addr
)
190 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
191 struct wiphy
*wiphy
= wdev
->wiphy
;
192 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
198 nl80211_send_auth_timeout(rdev
, dev
, addr
, GFP_KERNEL
);
199 if (wdev
->sme_state
== CFG80211_SME_CONNECTING
)
200 cfg80211_connect_result(dev
, addr
, NULL
, 0, NULL
, 0,
201 WLAN_STATUS_UNSPECIFIED_FAILURE
,
204 for (i
= 0; addr
&& i
< MAX_AUTH_BSSES
; i
++) {
205 if (wdev
->authtry_bsses
[i
] &&
206 memcmp(wdev
->authtry_bsses
[i
]->pub
.bssid
,
207 addr
, ETH_ALEN
) == 0) {
208 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
209 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
210 wdev
->authtry_bsses
[i
] = NULL
;
218 EXPORT_SYMBOL(cfg80211_send_auth_timeout
);
220 void cfg80211_send_assoc_timeout(struct net_device
*dev
, const u8
*addr
)
222 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
223 struct wiphy
*wiphy
= wdev
->wiphy
;
224 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
230 nl80211_send_assoc_timeout(rdev
, dev
, addr
, GFP_KERNEL
);
231 if (wdev
->sme_state
== CFG80211_SME_CONNECTING
)
232 cfg80211_connect_result(dev
, addr
, NULL
, 0, NULL
, 0,
233 WLAN_STATUS_UNSPECIFIED_FAILURE
,
236 for (i
= 0; addr
&& i
< MAX_AUTH_BSSES
; i
++) {
237 if (wdev
->auth_bsses
[i
] &&
238 memcmp(wdev
->auth_bsses
[i
]->pub
.bssid
,
239 addr
, ETH_ALEN
) == 0) {
240 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
241 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
242 wdev
->auth_bsses
[i
] = NULL
;
250 EXPORT_SYMBOL(cfg80211_send_assoc_timeout
);
252 void cfg80211_michael_mic_failure(struct net_device
*dev
, const u8
*addr
,
253 enum nl80211_key_type key_type
, int key_id
,
254 const u8
*tsc
, gfp_t gfp
)
256 struct wiphy
*wiphy
= dev
->ieee80211_ptr
->wiphy
;
257 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
258 #ifdef CONFIG_WIRELESS_EXT
259 union iwreq_data wrqu
;
260 char *buf
= kmalloc(128, gfp
);
263 sprintf(buf
, "MLME-MICHAELMICFAILURE.indication("
264 "keyid=%d %scast addr=%pM)", key_id
,
265 key_type
== NL80211_KEYTYPE_GROUP
? "broad" : "uni",
267 memset(&wrqu
, 0, sizeof(wrqu
));
268 wrqu
.data
.length
= strlen(buf
);
269 wireless_send_event(dev
, IWEVCUSTOM
, &wrqu
, buf
);
274 nl80211_michael_mic_failure(rdev
, dev
, addr
, key_type
, key_id
, tsc
, gfp
);
276 EXPORT_SYMBOL(cfg80211_michael_mic_failure
);
278 /* some MLME handling for userspace SME */
279 int cfg80211_mlme_auth(struct cfg80211_registered_device
*rdev
,
280 struct net_device
*dev
, struct ieee80211_channel
*chan
,
281 enum nl80211_auth_type auth_type
, const u8
*bssid
,
282 const u8
*ssid
, int ssid_len
,
283 const u8
*ie
, int ie_len
)
285 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
286 struct cfg80211_auth_request req
;
287 struct cfg80211_internal_bss
*bss
;
288 int i
, err
, slot
= -1, nfree
= 0;
290 if (wdev
->current_bss
&&
291 memcmp(bssid
, wdev
->current_bss
->pub
.bssid
, ETH_ALEN
) == 0)
294 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
295 if (wdev
->authtry_bsses
[i
] &&
296 memcmp(bssid
, wdev
->authtry_bsses
[i
]->pub
.bssid
,
299 if (wdev
->auth_bsses
[i
] &&
300 memcmp(bssid
, wdev
->auth_bsses
[i
]->pub
.bssid
,
305 memset(&req
, 0, sizeof(req
));
309 req
.auth_type
= auth_type
;
310 req
.bss
= cfg80211_get_bss(&rdev
->wiphy
, chan
, bssid
, ssid
, ssid_len
,
311 WLAN_CAPABILITY_ESS
, WLAN_CAPABILITY_ESS
);
315 bss
= bss_from_pub(req
.bss
);
317 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
318 if (!wdev
->auth_bsses
[i
] && !wdev
->authtry_bsses
[i
]) {
324 /* we need one free slot for disassoc and one for this auth */
330 wdev
->authtry_bsses
[slot
] = bss
;
331 cfg80211_hold_bss(bss
);
333 err
= rdev
->ops
->auth(&rdev
->wiphy
, dev
, &req
);
335 wdev
->authtry_bsses
[slot
] = NULL
;
336 cfg80211_unhold_bss(bss
);
341 cfg80211_put_bss(req
.bss
);
345 int cfg80211_mlme_assoc(struct cfg80211_registered_device
*rdev
,
346 struct net_device
*dev
, struct ieee80211_channel
*chan
,
347 const u8
*bssid
, const u8
*prev_bssid
,
348 const u8
*ssid
, int ssid_len
,
349 const u8
*ie
, int ie_len
, bool use_mfp
,
350 struct cfg80211_crypto_settings
*crypt
)
352 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
353 struct cfg80211_assoc_request req
;
354 struct cfg80211_internal_bss
*bss
;
355 int i
, err
, slot
= -1;
357 memset(&req
, 0, sizeof(req
));
359 if (wdev
->current_bss
)
364 memcpy(&req
.crypto
, crypt
, sizeof(req
.crypto
));
365 req
.use_mfp
= use_mfp
;
366 req
.prev_bssid
= prev_bssid
;
367 req
.bss
= cfg80211_get_bss(&rdev
->wiphy
, chan
, bssid
, ssid
, ssid_len
,
368 WLAN_CAPABILITY_ESS
, WLAN_CAPABILITY_ESS
);
372 bss
= bss_from_pub(req
.bss
);
374 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
375 if (bss
== wdev
->auth_bsses
[i
]) {
386 err
= rdev
->ops
->assoc(&rdev
->wiphy
, dev
, &req
);
388 /* still a reference in wdev->auth_bsses[slot] */
389 cfg80211_put_bss(req
.bss
);
393 int cfg80211_mlme_deauth(struct cfg80211_registered_device
*rdev
,
394 struct net_device
*dev
, const u8
*bssid
,
395 const u8
*ie
, int ie_len
, u16 reason
)
397 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
398 struct cfg80211_deauth_request req
;
401 memset(&req
, 0, sizeof(req
));
402 req
.reason_code
= reason
;
405 if (wdev
->current_bss
&&
406 memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0) {
407 req
.bss
= &wdev
->current_bss
->pub
;
408 } else for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
409 if (wdev
->auth_bsses
[i
] &&
410 memcmp(bssid
, wdev
->auth_bsses
[i
]->pub
.bssid
, ETH_ALEN
) == 0) {
411 req
.bss
= &wdev
->auth_bsses
[i
]->pub
;
414 if (wdev
->authtry_bsses
[i
] &&
415 memcmp(bssid
, wdev
->authtry_bsses
[i
]->pub
.bssid
, ETH_ALEN
) == 0) {
416 req
.bss
= &wdev
->authtry_bsses
[i
]->pub
;
424 return rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
);
427 int cfg80211_mlme_disassoc(struct cfg80211_registered_device
*rdev
,
428 struct net_device
*dev
, const u8
*bssid
,
429 const u8
*ie
, int ie_len
, u16 reason
)
431 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
432 struct cfg80211_disassoc_request req
;
434 memset(&req
, 0, sizeof(req
));
435 req
.reason_code
= reason
;
438 if (memcmp(wdev
->current_bss
->pub
.bssid
, bssid
, ETH_ALEN
) == 0)
439 req
.bss
= &wdev
->current_bss
->pub
;
443 return rdev
->ops
->disassoc(&rdev
->wiphy
, dev
, &req
);
446 void cfg80211_mlme_down(struct cfg80211_registered_device
*rdev
,
447 struct net_device
*dev
)
449 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
450 struct cfg80211_deauth_request req
;
453 if (!rdev
->ops
->deauth
)
456 memset(&req
, 0, sizeof(req
));
457 req
.reason_code
= WLAN_REASON_DEAUTH_LEAVING
;
461 if (wdev
->current_bss
) {
462 req
.bss
= &wdev
->current_bss
->pub
;
463 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
);
464 if (wdev
->current_bss
) {
465 cfg80211_unhold_bss(wdev
->current_bss
);
466 cfg80211_put_bss(&wdev
->current_bss
->pub
);
467 wdev
->current_bss
= NULL
;
471 for (i
= 0; i
< MAX_AUTH_BSSES
; i
++) {
472 if (wdev
->auth_bsses
[i
]) {
473 req
.bss
= &wdev
->auth_bsses
[i
]->pub
;
474 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
);
475 if (wdev
->auth_bsses
[i
]) {
476 cfg80211_unhold_bss(wdev
->auth_bsses
[i
]);
477 cfg80211_put_bss(&wdev
->auth_bsses
[i
]->pub
);
478 wdev
->auth_bsses
[i
] = NULL
;
481 if (wdev
->authtry_bsses
[i
]) {
482 req
.bss
= &wdev
->authtry_bsses
[i
]->pub
;
483 rdev
->ops
->deauth(&rdev
->wiphy
, dev
, &req
);
484 if (wdev
->authtry_bsses
[i
]) {
485 cfg80211_unhold_bss(wdev
->authtry_bsses
[i
]);
486 cfg80211_put_bss(&wdev
->authtry_bsses
[i
]->pub
);
487 wdev
->authtry_bsses
[i
] = NULL
;