2 * SME code for cfg80211's connect emulation.
4 * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
5 * Copyright (C) 2009 Intel Corporation. All rights reserved.
8 #include <linux/etherdevice.h>
9 #include <linux/if_arp.h>
10 #include <linux/workqueue.h>
11 #include <net/cfg80211.h>
12 #include <net/rtnetlink.h>
15 struct cfg80211_conn
{
16 struct cfg80211_connect_params params
;
17 /* these are sub-states of the _CONNECTING sme_state */
20 CFG80211_CONN_SCANNING
,
21 CFG80211_CONN_SCAN_AGAIN
,
22 CFG80211_CONN_AUTHENTICATE_NEXT
,
23 CFG80211_CONN_AUTHENTICATING
,
24 CFG80211_CONN_ASSOCIATE_NEXT
,
25 CFG80211_CONN_ASSOCIATING
,
34 static int cfg80211_conn_scan(struct wireless_dev
*wdev
)
36 struct cfg80211_registered_device
*drv
= wiphy_to_dev(wdev
->wiphy
);
37 struct cfg80211_scan_request
*request
;
45 if (wdev
->conn
->params
.channel
) {
48 enum ieee80211_band band
;
51 for (band
= 0; band
< IEEE80211_NUM_BANDS
; band
++) {
52 if (!wdev
->wiphy
->bands
[band
])
54 n_channels
+= wdev
->wiphy
->bands
[band
]->n_channels
;
57 request
= kzalloc(sizeof(*request
) + sizeof(request
->ssids
[0]) +
58 sizeof(request
->channels
[0]) * n_channels
,
63 request
->channels
= (void *)((char *)request
+ sizeof(*request
));
64 if (wdev
->conn
->params
.channel
)
65 request
->channels
[0] = wdev
->conn
->params
.channel
;
68 enum ieee80211_band band
;
70 for (band
= 0; band
< IEEE80211_NUM_BANDS
; band
++) {
71 if (!wdev
->wiphy
->bands
[band
])
73 for (j
= 0; j
< wdev
->wiphy
->bands
[band
]->n_channels
;
75 request
->channels
[i
] =
76 &wdev
->wiphy
->bands
[band
]->channels
[j
];
79 request
->n_channels
= n_channels
;
80 request
->ssids
= (void *)(request
->channels
+ n_channels
);
83 memcpy(request
->ssids
[0].ssid
, wdev
->conn
->params
.ssid
,
84 wdev
->conn
->params
.ssid_len
);
85 request
->ssids
[0].ssid_len
= wdev
->conn
->params
.ssid_len
;
87 request
->ifidx
= wdev
->netdev
->ifindex
;
88 request
->wiphy
= &drv
->wiphy
;
90 drv
->scan_req
= request
;
92 err
= drv
->ops
->scan(wdev
->wiphy
, wdev
->netdev
, request
);
94 wdev
->conn
->state
= CFG80211_CONN_SCANNING
;
95 nl80211_send_scan_start(drv
, wdev
->netdev
);
103 static int cfg80211_conn_do_work(struct wireless_dev
*wdev
)
105 struct cfg80211_registered_device
*drv
= wiphy_to_dev(wdev
->wiphy
);
106 struct cfg80211_connect_params
*params
;
112 params
= &wdev
->conn
->params
;
114 switch (wdev
->conn
->state
) {
115 case CFG80211_CONN_SCAN_AGAIN
:
116 return cfg80211_conn_scan(wdev
);
117 case CFG80211_CONN_AUTHENTICATE_NEXT
:
118 BUG_ON(!drv
->ops
->auth
);
119 wdev
->conn
->state
= CFG80211_CONN_AUTHENTICATING
;
120 return cfg80211_mlme_auth(drv
, wdev
->netdev
,
121 params
->channel
, params
->auth_type
,
123 params
->ssid
, params
->ssid_len
,
125 case CFG80211_CONN_ASSOCIATE_NEXT
:
126 BUG_ON(!drv
->ops
->assoc
);
127 wdev
->conn
->state
= CFG80211_CONN_ASSOCIATING
;
129 * We could, later, implement roaming here and then actually
130 * set prev_bssid to non-NULL. But then we need to be aware
131 * that some APs don't like that -- so we'd need to retry
134 err
= cfg80211_mlme_assoc(drv
, wdev
->netdev
,
135 params
->channel
, params
->bssid
, NULL
,
136 params
->ssid
, params
->ssid_len
,
137 params
->ie
, params
->ie_len
,
138 false, ¶ms
->crypto
);
140 cfg80211_mlme_deauth(drv
, wdev
->netdev
, params
->bssid
,
141 NULL
, 0, WLAN_REASON_DEAUTH_LEAVING
);
148 void cfg80211_conn_work(struct work_struct
*work
)
150 struct cfg80211_registered_device
*drv
=
151 container_of(work
, struct cfg80211_registered_device
, conn_work
);
152 struct wireless_dev
*wdev
;
155 mutex_lock(&drv
->devlist_mtx
);
157 list_for_each_entry(wdev
, &drv
->netdev_list
, list
) {
158 if (!netif_running(wdev
->netdev
))
160 if (wdev
->sme_state
!= CFG80211_SME_CONNECTING
)
162 if (cfg80211_conn_do_work(wdev
))
163 cfg80211_connect_result(wdev
->netdev
,
164 wdev
->conn
->params
.bssid
,
166 WLAN_STATUS_UNSPECIFIED_FAILURE
,
170 mutex_unlock(&drv
->devlist_mtx
);
174 static bool cfg80211_get_conn_bss(struct wireless_dev
*wdev
)
176 struct cfg80211_registered_device
*drv
= wiphy_to_dev(wdev
->wiphy
);
177 struct cfg80211_bss
*bss
;
178 u16 capa
= WLAN_CAPABILITY_ESS
;
180 if (wdev
->conn
->params
.privacy
)
181 capa
|= WLAN_CAPABILITY_PRIVACY
;
183 bss
= cfg80211_get_bss(wdev
->wiphy
, NULL
, wdev
->conn
->params
.bssid
,
184 wdev
->conn
->params
.ssid
,
185 wdev
->conn
->params
.ssid_len
,
186 WLAN_CAPABILITY_ESS
| WLAN_CAPABILITY_PRIVACY
,
191 memcpy(wdev
->conn
->bssid
, bss
->bssid
, ETH_ALEN
);
192 wdev
->conn
->params
.bssid
= wdev
->conn
->bssid
;
193 wdev
->conn
->params
.channel
= bss
->channel
;
194 wdev
->conn
->state
= CFG80211_CONN_AUTHENTICATE_NEXT
;
195 schedule_work(&drv
->conn_work
);
197 cfg80211_put_bss(bss
);
201 void cfg80211_sme_scan_done(struct net_device
*dev
)
203 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
204 struct cfg80211_registered_device
*drv
= wiphy_to_dev(wdev
->wiphy
);
206 if (wdev
->sme_state
!= CFG80211_SME_CONNECTING
)
209 if (WARN_ON(!wdev
->conn
))
212 if (wdev
->conn
->state
!= CFG80211_CONN_SCANNING
&&
213 wdev
->conn
->state
!= CFG80211_CONN_SCAN_AGAIN
)
216 if (!cfg80211_get_conn_bss(wdev
)) {
218 if (wdev
->conn
->state
== CFG80211_CONN_SCAN_AGAIN
)
219 schedule_work(&drv
->conn_work
);
221 cfg80211_connect_result(dev
, wdev
->conn
->params
.bssid
,
223 WLAN_STATUS_UNSPECIFIED_FAILURE
,
229 void cfg80211_sme_rx_auth(struct net_device
*dev
, const u8
*buf
, size_t len
)
231 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
232 struct wiphy
*wiphy
= wdev
->wiphy
;
233 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wiphy
);
234 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)buf
;
235 u16 status_code
= le16_to_cpu(mgmt
->u
.auth
.status_code
);
237 /* should only RX auth frames when connecting */
238 if (wdev
->sme_state
!= CFG80211_SME_CONNECTING
)
241 if (WARN_ON(!wdev
->conn
))
244 if (status_code
== WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG
&&
245 wdev
->conn
->auto_auth
&&
246 wdev
->conn
->params
.auth_type
!= NL80211_AUTHTYPE_NETWORK_EAP
) {
247 /* select automatically between only open, shared, leap */
248 switch (wdev
->conn
->params
.auth_type
) {
249 case NL80211_AUTHTYPE_OPEN_SYSTEM
:
250 wdev
->conn
->params
.auth_type
=
251 NL80211_AUTHTYPE_SHARED_KEY
;
253 case NL80211_AUTHTYPE_SHARED_KEY
:
254 wdev
->conn
->params
.auth_type
=
255 NL80211_AUTHTYPE_NETWORK_EAP
;
259 wdev
->conn
->params
.auth_type
=
260 NL80211_AUTHTYPE_OPEN_SYSTEM
;
263 wdev
->conn
->state
= CFG80211_CONN_AUTHENTICATE_NEXT
;
264 schedule_work(&rdev
->conn_work
);
265 } else if (status_code
!= WLAN_STATUS_SUCCESS
) {
266 wdev
->sme_state
= CFG80211_SME_IDLE
;
269 } else if (wdev
->sme_state
== CFG80211_SME_CONNECTING
&&
270 wdev
->conn
->state
== CFG80211_CONN_AUTHENTICATING
) {
271 wdev
->conn
->state
= CFG80211_CONN_ASSOCIATE_NEXT
;
272 schedule_work(&rdev
->conn_work
);
276 static void __cfg80211_connect_result(struct net_device
*dev
, const u8
*bssid
,
277 const u8
*req_ie
, size_t req_ie_len
,
278 const u8
*resp_ie
, size_t resp_ie_len
,
279 u16 status
, bool wextev
, gfp_t gfp
)
281 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
282 struct cfg80211_bss
*bss
;
283 #ifdef CONFIG_WIRELESS_EXT
284 union iwreq_data wrqu
;
287 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_STATION
))
290 if (wdev
->sme_state
== CFG80211_SME_CONNECTED
)
291 nl80211_send_roamed(wiphy_to_dev(wdev
->wiphy
), dev
,
292 bssid
, req_ie
, req_ie_len
,
293 resp_ie
, resp_ie_len
, gfp
);
295 nl80211_send_connect_result(wiphy_to_dev(wdev
->wiphy
), dev
,
296 bssid
, req_ie
, req_ie_len
,
297 resp_ie
, resp_ie_len
,
300 #ifdef CONFIG_WIRELESS_EXT
302 if (req_ie
&& status
== WLAN_STATUS_SUCCESS
) {
303 memset(&wrqu
, 0, sizeof(wrqu
));
304 wrqu
.data
.length
= req_ie_len
;
305 wireless_send_event(dev
, IWEVASSOCRESPIE
, &wrqu
, req_ie
);
308 if (resp_ie
&& status
== WLAN_STATUS_SUCCESS
) {
309 memset(&wrqu
, 0, sizeof(wrqu
));
310 wrqu
.data
.length
= resp_ie_len
;
311 wireless_send_event(dev
, IWEVASSOCRESPIE
, &wrqu
, resp_ie
);
314 memset(&wrqu
, 0, sizeof(wrqu
));
315 wrqu
.ap_addr
.sa_family
= ARPHRD_ETHER
;
316 if (bssid
&& status
== WLAN_STATUS_SUCCESS
)
317 memcpy(wrqu
.ap_addr
.sa_data
, bssid
, ETH_ALEN
);
318 wireless_send_event(dev
, SIOCGIWAP
, &wrqu
, NULL
);
322 if (status
== WLAN_STATUS_SUCCESS
&&
323 wdev
->sme_state
== CFG80211_SME_IDLE
) {
324 wdev
->sme_state
= CFG80211_SME_CONNECTED
;
328 if (wdev
->sme_state
!= CFG80211_SME_CONNECTING
)
331 if (wdev
->current_bss
) {
332 cfg80211_unhold_bss(wdev
->current_bss
);
333 cfg80211_put_bss(&wdev
->current_bss
->pub
);
334 wdev
->current_bss
= NULL
;
338 wdev
->conn
->state
= CFG80211_CONN_IDLE
;
340 if (status
== WLAN_STATUS_SUCCESS
) {
341 bss
= cfg80211_get_bss(wdev
->wiphy
, NULL
, bssid
,
342 wdev
->ssid
, wdev
->ssid_len
,
344 WLAN_CAPABILITY_ESS
);
349 cfg80211_hold_bss(bss_from_pub(bss
));
350 wdev
->current_bss
= bss_from_pub(bss
);
352 wdev
->sme_state
= CFG80211_SME_CONNECTED
;
354 wdev
->sme_state
= CFG80211_SME_IDLE
;
360 void cfg80211_connect_result(struct net_device
*dev
, const u8
*bssid
,
361 const u8
*req_ie
, size_t req_ie_len
,
362 const u8
*resp_ie
, size_t resp_ie_len
,
363 u16 status
, gfp_t gfp
)
365 bool wextev
= status
== WLAN_STATUS_SUCCESS
;
366 __cfg80211_connect_result(dev
, bssid
, req_ie
, req_ie_len
, resp_ie
, resp_ie_len
, status
, wextev
, gfp
);
368 EXPORT_SYMBOL(cfg80211_connect_result
);
370 void cfg80211_roamed(struct net_device
*dev
, const u8
*bssid
,
371 const u8
*req_ie
, size_t req_ie_len
,
372 const u8
*resp_ie
, size_t resp_ie_len
, gfp_t gfp
)
374 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
375 struct cfg80211_bss
*bss
;
376 #ifdef CONFIG_WIRELESS_EXT
377 union iwreq_data wrqu
;
380 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_STATION
))
383 if (WARN_ON(wdev
->sme_state
!= CFG80211_SME_CONNECTED
))
386 /* internal error -- how did we get to CONNECTED w/o BSS? */
387 if (WARN_ON(!wdev
->current_bss
)) {
391 cfg80211_unhold_bss(wdev
->current_bss
);
392 cfg80211_put_bss(&wdev
->current_bss
->pub
);
393 wdev
->current_bss
= NULL
;
395 bss
= cfg80211_get_bss(wdev
->wiphy
, NULL
, bssid
,
396 wdev
->ssid
, wdev
->ssid_len
,
397 WLAN_CAPABILITY_ESS
, WLAN_CAPABILITY_ESS
);
402 cfg80211_hold_bss(bss_from_pub(bss
));
403 wdev
->current_bss
= bss_from_pub(bss
);
405 nl80211_send_roamed(wiphy_to_dev(wdev
->wiphy
), dev
, bssid
,
406 req_ie
, req_ie_len
, resp_ie
, resp_ie_len
, gfp
);
408 #ifdef CONFIG_WIRELESS_EXT
410 memset(&wrqu
, 0, sizeof(wrqu
));
411 wrqu
.data
.length
= req_ie_len
;
412 wireless_send_event(dev
, IWEVASSOCRESPIE
, &wrqu
, req_ie
);
416 memset(&wrqu
, 0, sizeof(wrqu
));
417 wrqu
.data
.length
= resp_ie_len
;
418 wireless_send_event(dev
, IWEVASSOCRESPIE
, &wrqu
, resp_ie
);
421 memset(&wrqu
, 0, sizeof(wrqu
));
422 wrqu
.ap_addr
.sa_family
= ARPHRD_ETHER
;
423 memcpy(wrqu
.ap_addr
.sa_data
, bssid
, ETH_ALEN
);
424 wireless_send_event(dev
, SIOCGIWAP
, &wrqu
, NULL
);
427 EXPORT_SYMBOL(cfg80211_roamed
);
429 void __cfg80211_disconnected(struct net_device
*dev
, gfp_t gfp
, u8
*ie
,
430 size_t ie_len
, u16 reason
, bool from_ap
)
432 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
433 #ifdef CONFIG_WIRELESS_EXT
434 union iwreq_data wrqu
;
437 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_STATION
))
440 if (WARN_ON(wdev
->sme_state
!= CFG80211_SME_CONNECTED
))
443 if (wdev
->current_bss
) {
444 cfg80211_unhold_bss(wdev
->current_bss
);
445 cfg80211_put_bss(&wdev
->current_bss
->pub
);
448 wdev
->current_bss
= NULL
;
449 wdev
->sme_state
= CFG80211_SME_IDLE
;
452 kfree(wdev
->conn
->ie
);
453 wdev
->conn
->ie
= NULL
;
458 nl80211_send_disconnected(wiphy_to_dev(wdev
->wiphy
), dev
,
459 reason
, ie
, ie_len
, from_ap
, gfp
);
461 #ifdef CONFIG_WIRELESS_EXT
462 memset(&wrqu
, 0, sizeof(wrqu
));
463 wrqu
.ap_addr
.sa_family
= ARPHRD_ETHER
;
464 wireless_send_event(dev
, SIOCGIWAP
, &wrqu
, NULL
);
468 void cfg80211_disconnected(struct net_device
*dev
, u16 reason
,
469 u8
*ie
, size_t ie_len
, gfp_t gfp
)
471 __cfg80211_disconnected(dev
, gfp
, ie
, ie_len
, reason
, true);
473 EXPORT_SYMBOL(cfg80211_disconnected
);
475 int cfg80211_connect(struct cfg80211_registered_device
*rdev
,
476 struct net_device
*dev
,
477 struct cfg80211_connect_params
*connect
)
480 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
482 if (wdev
->sme_state
!= CFG80211_SME_IDLE
)
485 if (!rdev
->ops
->connect
) {
486 if (!rdev
->ops
->auth
|| !rdev
->ops
->assoc
)
489 if (WARN_ON(wdev
->conn
))
492 wdev
->conn
= kzalloc(sizeof(*wdev
->conn
), GFP_KERNEL
);
497 * Copy all parameters, and treat explicitly IEs, BSSID, SSID.
499 memcpy(&wdev
->conn
->params
, connect
, sizeof(*connect
));
500 if (connect
->bssid
) {
501 wdev
->conn
->params
.bssid
= wdev
->conn
->bssid
;
502 memcpy(wdev
->conn
->bssid
, connect
->bssid
, ETH_ALEN
);
506 wdev
->conn
->ie
= kmemdup(connect
->ie
, connect
->ie_len
,
508 wdev
->conn
->params
.ie
= wdev
->conn
->ie
;
509 if (!wdev
->conn
->ie
) {
516 if (connect
->auth_type
== NL80211_AUTHTYPE_AUTOMATIC
) {
517 wdev
->conn
->auto_auth
= true;
518 /* start with open system ... should mostly work */
519 wdev
->conn
->params
.auth_type
=
520 NL80211_AUTHTYPE_OPEN_SYSTEM
;
522 wdev
->conn
->auto_auth
= false;
525 memcpy(wdev
->ssid
, connect
->ssid
, connect
->ssid_len
);
526 wdev
->ssid_len
= connect
->ssid_len
;
527 wdev
->conn
->params
.ssid
= wdev
->ssid
;
528 wdev
->conn
->params
.ssid_len
= connect
->ssid_len
;
530 /* don't care about result -- but fill bssid & channel */
531 if (!wdev
->conn
->params
.bssid
|| !wdev
->conn
->params
.channel
)
532 cfg80211_get_conn_bss(wdev
);
534 wdev
->sme_state
= CFG80211_SME_CONNECTING
;
536 /* we're good if we have both BSSID and channel */
537 if (wdev
->conn
->params
.bssid
&& wdev
->conn
->params
.channel
) {
538 wdev
->conn
->state
= CFG80211_CONN_AUTHENTICATE_NEXT
;
539 err
= cfg80211_conn_do_work(wdev
);
541 /* otherwise we'll need to scan for the AP first */
542 err
= cfg80211_conn_scan(wdev
);
544 * If we can't scan right now, then we need to scan again
545 * after the current scan finished, since the parameters
546 * changed (unless we find a good AP anyway).
550 wdev
->conn
->state
= CFG80211_CONN_SCAN_AGAIN
;
556 wdev
->sme_state
= CFG80211_SME_IDLE
;
561 wdev
->sme_state
= CFG80211_SME_CONNECTING
;
562 err
= rdev
->ops
->connect(&rdev
->wiphy
, dev
, connect
);
564 wdev
->sme_state
= CFG80211_SME_IDLE
;
568 memcpy(wdev
->ssid
, connect
->ssid
, connect
->ssid_len
);
569 wdev
->ssid_len
= connect
->ssid_len
;
575 int cfg80211_disconnect(struct cfg80211_registered_device
*rdev
,
576 struct net_device
*dev
, u16 reason
, bool wextev
)
578 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
581 if (wdev
->sme_state
== CFG80211_SME_IDLE
)
584 if (!rdev
->ops
->disconnect
) {
585 if (!rdev
->ops
->deauth
)
588 /* was it connected by userspace SME? */
590 cfg80211_mlme_down(rdev
, dev
);
594 if (wdev
->sme_state
== CFG80211_SME_CONNECTING
&&
595 (wdev
->conn
->state
== CFG80211_CONN_SCANNING
||
596 wdev
->conn
->state
== CFG80211_CONN_SCAN_AGAIN
)) {
597 wdev
->sme_state
= CFG80211_SME_IDLE
;
603 /* wdev->conn->params.bssid must be set if > SCANNING */
604 err
= cfg80211_mlme_deauth(rdev
, dev
, wdev
->conn
->params
.bssid
,
609 err
= rdev
->ops
->disconnect(&rdev
->wiphy
, dev
, reason
);
614 if (wdev
->sme_state
== CFG80211_SME_CONNECTED
)
615 __cfg80211_disconnected(dev
, GFP_KERNEL
, NULL
, 0, 0, false);
616 else if (wdev
->sme_state
== CFG80211_SME_CONNECTING
)
617 __cfg80211_connect_result(dev
, NULL
, NULL
, 0, NULL
, 0,
618 WLAN_STATUS_UNSPECIFIED_FAILURE
,
624 void cfg80211_sme_disassoc(struct net_device
*dev
, int idx
)
626 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
627 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wdev
->wiphy
);
633 if (wdev
->conn
->state
== CFG80211_CONN_IDLE
)
637 * Ok, so the association was made by this SME -- we don't
638 * want it any more so deauthenticate too.
641 if (!wdev
->auth_bsses
[idx
])
644 memcpy(bssid
, wdev
->auth_bsses
[idx
]->pub
.bssid
, ETH_ALEN
);
645 if (cfg80211_mlme_deauth(rdev
, dev
, bssid
,
646 NULL
, 0, WLAN_REASON_DEAUTH_LEAVING
)) {
647 /* whatever -- assume gone anyway */
648 cfg80211_unhold_bss(wdev
->auth_bsses
[idx
]);
649 cfg80211_put_bss(&wdev
->auth_bsses
[idx
]->pub
);
650 wdev
->auth_bsses
[idx
] = NULL
;