]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - net/wireless/sme.c
cfg80211: make aware of net namespaces
[mirror_ubuntu-bionic-kernel.git] / net / wireless / sme.c
CommitLineData
b23aa676
SO
1/*
2 * SME code for cfg80211's connect emulation.
3 *
4 * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
5 * Copyright (C) 2009 Intel Corporation. All rights reserved.
6 */
7
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>
13#include "nl80211.h"
14
6829c878
JB
15struct cfg80211_conn {
16 struct cfg80211_connect_params params;
17 /* these are sub-states of the _CONNECTING sme_state */
18 enum {
19 CFG80211_CONN_IDLE,
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,
26 } state;
27 u8 bssid[ETH_ALEN];
28 u8 *ie;
29 size_t ie_len;
30 bool auto_auth;
31};
32
33
34static int cfg80211_conn_scan(struct wireless_dev *wdev)
35{
79c97e97 36 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
6829c878
JB
37 struct cfg80211_scan_request *request;
38 int n_channels, err;
39
40 ASSERT_RTNL();
79c97e97 41 ASSERT_RDEV_LOCK(rdev);
667503dd 42 ASSERT_WDEV_LOCK(wdev);
6829c878 43
79c97e97 44 if (rdev->scan_req)
6829c878
JB
45 return -EBUSY;
46
47 if (wdev->conn->params.channel) {
48 n_channels = 1;
49 } else {
50 enum ieee80211_band band;
51 n_channels = 0;
52
53 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
54 if (!wdev->wiphy->bands[band])
55 continue;
56 n_channels += wdev->wiphy->bands[band]->n_channels;
57 }
58 }
59 request = kzalloc(sizeof(*request) + sizeof(request->ssids[0]) +
60 sizeof(request->channels[0]) * n_channels,
61 GFP_KERNEL);
62 if (!request)
63 return -ENOMEM;
64
65 request->channels = (void *)((char *)request + sizeof(*request));
66 if (wdev->conn->params.channel)
67 request->channels[0] = wdev->conn->params.channel;
68 else {
69 int i = 0, j;
70 enum ieee80211_band band;
71
72 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
73 if (!wdev->wiphy->bands[band])
74 continue;
75 for (j = 0; j < wdev->wiphy->bands[band]->n_channels;
76 i++, j++)
77 request->channels[i] =
78 &wdev->wiphy->bands[band]->channels[j];
79 }
80 }
81 request->n_channels = n_channels;
82 request->ssids = (void *)(request->channels + n_channels);
83 request->n_ssids = 1;
84
85 memcpy(request->ssids[0].ssid, wdev->conn->params.ssid,
86 wdev->conn->params.ssid_len);
87 request->ssids[0].ssid_len = wdev->conn->params.ssid_len;
88
463d0183 89 request->dev = wdev->netdev;
79c97e97 90 request->wiphy = &rdev->wiphy;
6829c878 91
79c97e97 92 rdev->scan_req = request;
6829c878 93
79c97e97 94 err = rdev->ops->scan(wdev->wiphy, wdev->netdev, request);
6829c878
JB
95 if (!err) {
96 wdev->conn->state = CFG80211_CONN_SCANNING;
79c97e97 97 nl80211_send_scan_start(rdev, wdev->netdev);
463d0183 98 dev_hold(wdev->netdev);
6829c878 99 } else {
79c97e97 100 rdev->scan_req = NULL;
6829c878
JB
101 kfree(request);
102 }
103 return err;
104}
105
106static int cfg80211_conn_do_work(struct wireless_dev *wdev)
107{
79c97e97 108 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
19957bb3
JB
109 struct cfg80211_connect_params *params;
110 int err;
6829c878 111
667503dd
JB
112 ASSERT_WDEV_LOCK(wdev);
113
6829c878
JB
114 if (!wdev->conn)
115 return 0;
116
19957bb3
JB
117 params = &wdev->conn->params;
118
6829c878
JB
119 switch (wdev->conn->state) {
120 case CFG80211_CONN_SCAN_AGAIN:
121 return cfg80211_conn_scan(wdev);
122 case CFG80211_CONN_AUTHENTICATE_NEXT:
79c97e97 123 BUG_ON(!rdev->ops->auth);
19957bb3 124 wdev->conn->state = CFG80211_CONN_AUTHENTICATING;
79c97e97 125 return __cfg80211_mlme_auth(rdev, wdev->netdev,
667503dd
JB
126 params->channel, params->auth_type,
127 params->bssid,
128 params->ssid, params->ssid_len,
fffd0934
JB
129 NULL, 0,
130 params->key, params->key_len,
131 params->key_idx);
6829c878 132 case CFG80211_CONN_ASSOCIATE_NEXT:
79c97e97 133 BUG_ON(!rdev->ops->assoc);
19957bb3 134 wdev->conn->state = CFG80211_CONN_ASSOCIATING;
3e5d7649
JB
135 /*
136 * We could, later, implement roaming here and then actually
137 * set prev_bssid to non-NULL. But then we need to be aware
138 * that some APs don't like that -- so we'd need to retry
139 * the association.
140 */
79c97e97 141 err = __cfg80211_mlme_assoc(rdev, wdev->netdev,
667503dd
JB
142 params->channel, params->bssid,
143 NULL,
144 params->ssid, params->ssid_len,
145 params->ie, params->ie_len,
146 false, &params->crypto);
19957bb3 147 if (err)
79c97e97 148 __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
667503dd
JB
149 NULL, 0,
150 WLAN_REASON_DEAUTH_LEAVING);
19957bb3 151 return err;
6829c878
JB
152 default:
153 return 0;
154 }
155}
156
157void cfg80211_conn_work(struct work_struct *work)
158{
79c97e97 159 struct cfg80211_registered_device *rdev =
6829c878
JB
160 container_of(work, struct cfg80211_registered_device, conn_work);
161 struct wireless_dev *wdev;
162
163 rtnl_lock();
79c97e97
JB
164 cfg80211_lock_rdev(rdev);
165 mutex_lock(&rdev->devlist_mtx);
6829c878 166
79c97e97 167 list_for_each_entry(wdev, &rdev->netdev_list, list) {
667503dd
JB
168 wdev_lock(wdev);
169 if (!netif_running(wdev->netdev)) {
170 wdev_unlock(wdev);
6829c878 171 continue;
667503dd
JB
172 }
173 if (wdev->sme_state != CFG80211_SME_CONNECTING) {
174 wdev_unlock(wdev);
6829c878 175 continue;
667503dd 176 }
6829c878 177 if (cfg80211_conn_do_work(wdev))
667503dd
JB
178 __cfg80211_connect_result(
179 wdev->netdev,
180 wdev->conn->params.bssid,
181 NULL, 0, NULL, 0,
182 WLAN_STATUS_UNSPECIFIED_FAILURE,
183 false);
184 wdev_unlock(wdev);
6829c878
JB
185 }
186
79c97e97
JB
187 mutex_unlock(&rdev->devlist_mtx);
188 cfg80211_unlock_rdev(rdev);
6829c878
JB
189 rtnl_unlock();
190}
191
192static bool cfg80211_get_conn_bss(struct wireless_dev *wdev)
193{
79c97e97 194 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
6829c878
JB
195 struct cfg80211_bss *bss;
196 u16 capa = WLAN_CAPABILITY_ESS;
197
667503dd
JB
198 ASSERT_WDEV_LOCK(wdev);
199
6829c878
JB
200 if (wdev->conn->params.privacy)
201 capa |= WLAN_CAPABILITY_PRIVACY;
202
203 bss = cfg80211_get_bss(wdev->wiphy, NULL, wdev->conn->params.bssid,
204 wdev->conn->params.ssid,
205 wdev->conn->params.ssid_len,
206 WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY,
207 capa);
6829c878
JB
208 if (!bss)
209 return false;
210
211 memcpy(wdev->conn->bssid, bss->bssid, ETH_ALEN);
212 wdev->conn->params.bssid = wdev->conn->bssid;
213 wdev->conn->params.channel = bss->channel;
214 wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
79c97e97 215 schedule_work(&rdev->conn_work);
6829c878
JB
216
217 cfg80211_put_bss(bss);
218 return true;
219}
220
667503dd 221static void __cfg80211_sme_scan_done(struct net_device *dev)
6829c878
JB
222{
223 struct wireless_dev *wdev = dev->ieee80211_ptr;
79c97e97 224 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
6829c878 225
667503dd
JB
226 ASSERT_WDEV_LOCK(wdev);
227
6829c878
JB
228 if (wdev->sme_state != CFG80211_SME_CONNECTING)
229 return;
230
d4b1a687 231 if (!wdev->conn)
6829c878
JB
232 return;
233
234 if (wdev->conn->state != CFG80211_CONN_SCANNING &&
235 wdev->conn->state != CFG80211_CONN_SCAN_AGAIN)
236 return;
237
238 if (!cfg80211_get_conn_bss(wdev)) {
239 /* not found */
240 if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)
79c97e97 241 schedule_work(&rdev->conn_work);
6829c878 242 else
667503dd
JB
243 __cfg80211_connect_result(
244 wdev->netdev,
245 wdev->conn->params.bssid,
246 NULL, 0, NULL, 0,
247 WLAN_STATUS_UNSPECIFIED_FAILURE,
248 false);
6829c878
JB
249 }
250}
251
667503dd
JB
252void cfg80211_sme_scan_done(struct net_device *dev)
253{
254 struct wireless_dev *wdev = dev->ieee80211_ptr;
255
256 wdev_lock(wdev);
257 __cfg80211_sme_scan_done(dev);
258 wdev_unlock(wdev);
259}
260
261void cfg80211_sme_rx_auth(struct net_device *dev,
262 const u8 *buf, size_t len)
6829c878
JB
263{
264 struct wireless_dev *wdev = dev->ieee80211_ptr;
265 struct wiphy *wiphy = wdev->wiphy;
266 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
267 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
268 u16 status_code = le16_to_cpu(mgmt->u.auth.status_code);
269
667503dd
JB
270 ASSERT_WDEV_LOCK(wdev);
271
6829c878
JB
272 /* should only RX auth frames when connecting */
273 if (wdev->sme_state != CFG80211_SME_CONNECTING)
274 return;
275
276 if (WARN_ON(!wdev->conn))
277 return;
278
279 if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG &&
280 wdev->conn->auto_auth &&
281 wdev->conn->params.auth_type != NL80211_AUTHTYPE_NETWORK_EAP) {
282 /* select automatically between only open, shared, leap */
283 switch (wdev->conn->params.auth_type) {
284 case NL80211_AUTHTYPE_OPEN_SYSTEM:
fffd0934
JB
285 if (wdev->connect_keys)
286 wdev->conn->params.auth_type =
287 NL80211_AUTHTYPE_SHARED_KEY;
288 else
289 wdev->conn->params.auth_type =
290 NL80211_AUTHTYPE_NETWORK_EAP;
6829c878
JB
291 break;
292 case NL80211_AUTHTYPE_SHARED_KEY:
293 wdev->conn->params.auth_type =
294 NL80211_AUTHTYPE_NETWORK_EAP;
295 break;
296 default:
297 /* huh? */
298 wdev->conn->params.auth_type =
299 NL80211_AUTHTYPE_OPEN_SYSTEM;
300 break;
301 }
302 wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
303 schedule_work(&rdev->conn_work);
19957bb3 304 } else if (status_code != WLAN_STATUS_SUCCESS) {
4bde0f7d
JB
305 __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
306 status_code, false);
19957bb3 307 } else if (wdev->sme_state == CFG80211_SME_CONNECTING &&
6829c878
JB
308 wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
309 wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
310 schedule_work(&rdev->conn_work);
311 }
312}
b23aa676 313
667503dd
JB
314void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
315 const u8 *req_ie, size_t req_ie_len,
316 const u8 *resp_ie, size_t resp_ie_len,
317 u16 status, bool wextev)
b23aa676
SO
318{
319 struct wireless_dev *wdev = dev->ieee80211_ptr;
320 struct cfg80211_bss *bss;
321#ifdef CONFIG_WIRELESS_EXT
322 union iwreq_data wrqu;
323#endif
324
667503dd
JB
325 ASSERT_WDEV_LOCK(wdev);
326
b23aa676
SO
327 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
328 return;
329
e45cd82a
JB
330 if (wdev->sme_state == CFG80211_SME_CONNECTED)
331 nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev,
332 bssid, req_ie, req_ie_len,
667503dd 333 resp_ie, resp_ie_len, GFP_KERNEL);
e45cd82a
JB
334 else
335 nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev,
336 bssid, req_ie, req_ie_len,
337 resp_ie, resp_ie_len,
667503dd 338 status, GFP_KERNEL);
e45cd82a
JB
339
340#ifdef CONFIG_WIRELESS_EXT
341 if (wextev) {
342 if (req_ie && status == WLAN_STATUS_SUCCESS) {
343 memset(&wrqu, 0, sizeof(wrqu));
344 wrqu.data.length = req_ie_len;
3409ff77 345 wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, req_ie);
e45cd82a
JB
346 }
347
348 if (resp_ie && status == WLAN_STATUS_SUCCESS) {
349 memset(&wrqu, 0, sizeof(wrqu));
350 wrqu.data.length = resp_ie_len;
351 wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie);
352 }
353
354 memset(&wrqu, 0, sizeof(wrqu));
355 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
356 if (bssid && status == WLAN_STATUS_SUCCESS)
357 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
358 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
359 }
360#endif
361
362 if (status == WLAN_STATUS_SUCCESS &&
fffd0934
JB
363 wdev->sme_state == CFG80211_SME_IDLE)
364 goto success;
e45cd82a 365
6829c878 366 if (wdev->sme_state != CFG80211_SME_CONNECTING)
b23aa676
SO
367 return;
368
369 if (wdev->current_bss) {
370 cfg80211_unhold_bss(wdev->current_bss);
19957bb3 371 cfg80211_put_bss(&wdev->current_bss->pub);
b23aa676
SO
372 wdev->current_bss = NULL;
373 }
374
19957bb3
JB
375 if (wdev->conn)
376 wdev->conn->state = CFG80211_CONN_IDLE;
377
fffd0934 378 if (status != WLAN_STATUS_SUCCESS) {
b23aa676 379 wdev->sme_state = CFG80211_SME_IDLE;
19957bb3
JB
380 kfree(wdev->conn);
381 wdev->conn = NULL;
fffd0934
JB
382 kfree(wdev->connect_keys);
383 wdev->connect_keys = NULL;
384 return;
b23aa676 385 }
fffd0934
JB
386
387 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
388 wdev->ssid, wdev->ssid_len,
389 WLAN_CAPABILITY_ESS,
390 WLAN_CAPABILITY_ESS);
391
392 if (WARN_ON(!bss))
393 return;
394
395 cfg80211_hold_bss(bss_from_pub(bss));
396 wdev->current_bss = bss_from_pub(bss);
397
398 success:
399 wdev->sme_state = CFG80211_SME_CONNECTED;
400 cfg80211_upload_connect_keys(wdev);
b23aa676 401}
f2129354
JB
402
403void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
404 const u8 *req_ie, size_t req_ie_len,
405 const u8 *resp_ie, size_t resp_ie_len,
406 u16 status, gfp_t gfp)
407{
667503dd
JB
408 struct wireless_dev *wdev = dev->ieee80211_ptr;
409 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
410 struct cfg80211_event *ev;
411 unsigned long flags;
412
413 ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
414 if (!ev)
415 return;
416
417 ev->type = EVENT_CONNECT_RESULT;
418 memcpy(ev->cr.bssid, bssid, ETH_ALEN);
419 ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev);
420 ev->cr.req_ie_len = req_ie_len;
421 memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len);
422 ev->cr.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len;
423 ev->cr.resp_ie_len = resp_ie_len;
424 memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len);
425 ev->cr.status = status;
426
427 spin_lock_irqsave(&wdev->event_lock, flags);
428 list_add_tail(&ev->list, &wdev->event_list);
429 spin_unlock_irqrestore(&wdev->event_lock, flags);
430 schedule_work(&rdev->event_work);
f2129354 431}
b23aa676
SO
432EXPORT_SYMBOL(cfg80211_connect_result);
433
667503dd
JB
434void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
435 const u8 *req_ie, size_t req_ie_len,
436 const u8 *resp_ie, size_t resp_ie_len)
b23aa676 437{
b23aa676
SO
438 struct cfg80211_bss *bss;
439#ifdef CONFIG_WIRELESS_EXT
440 union iwreq_data wrqu;
441#endif
442
667503dd
JB
443 ASSERT_WDEV_LOCK(wdev);
444
b23aa676
SO
445 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
446 return;
447
448 if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED))
449 return;
450
451 /* internal error -- how did we get to CONNECTED w/o BSS? */
452 if (WARN_ON(!wdev->current_bss)) {
453 return;
454 }
455
456 cfg80211_unhold_bss(wdev->current_bss);
19957bb3 457 cfg80211_put_bss(&wdev->current_bss->pub);
b23aa676
SO
458 wdev->current_bss = NULL;
459
460 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
461 wdev->ssid, wdev->ssid_len,
462 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
463
464 if (WARN_ON(!bss))
465 return;
466
19957bb3
JB
467 cfg80211_hold_bss(bss_from_pub(bss));
468 wdev->current_bss = bss_from_pub(bss);
b23aa676 469
667503dd
JB
470 nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), wdev->netdev, bssid,
471 req_ie, req_ie_len, resp_ie, resp_ie_len,
472 GFP_KERNEL);
b23aa676
SO
473
474#ifdef CONFIG_WIRELESS_EXT
475 if (req_ie) {
476 memset(&wrqu, 0, sizeof(wrqu));
477 wrqu.data.length = req_ie_len;
3409ff77 478 wireless_send_event(wdev->netdev, IWEVASSOCREQIE,
667503dd 479 &wrqu, req_ie);
b23aa676
SO
480 }
481
482 if (resp_ie) {
483 memset(&wrqu, 0, sizeof(wrqu));
484 wrqu.data.length = resp_ie_len;
667503dd
JB
485 wireless_send_event(wdev->netdev, IWEVASSOCRESPIE,
486 &wrqu, resp_ie);
b23aa676
SO
487 }
488
489 memset(&wrqu, 0, sizeof(wrqu));
490 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
491 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
667503dd 492 wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL);
b23aa676
SO
493#endif
494}
667503dd
JB
495
496void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
497 const u8 *req_ie, size_t req_ie_len,
498 const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
499{
500 struct wireless_dev *wdev = dev->ieee80211_ptr;
501 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
502 struct cfg80211_event *ev;
503 unsigned long flags;
504
505 ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
506 if (!ev)
507 return;
508
509 ev->type = EVENT_ROAMED;
510 memcpy(ev->rm.bssid, bssid, ETH_ALEN);
511 ev->rm.req_ie = ((u8 *)ev) + sizeof(*ev);
512 ev->rm.req_ie_len = req_ie_len;
513 memcpy((void *)ev->rm.req_ie, req_ie, req_ie_len);
514 ev->rm.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len;
515 ev->rm.resp_ie_len = resp_ie_len;
516 memcpy((void *)ev->rm.resp_ie, resp_ie, resp_ie_len);
517
518 spin_lock_irqsave(&wdev->event_lock, flags);
519 list_add_tail(&ev->list, &wdev->event_list);
520 spin_unlock_irqrestore(&wdev->event_lock, flags);
521 schedule_work(&rdev->event_work);
522}
b23aa676
SO
523EXPORT_SYMBOL(cfg80211_roamed);
524
667503dd 525void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
6829c878 526 size_t ie_len, u16 reason, bool from_ap)
b23aa676
SO
527{
528 struct wireless_dev *wdev = dev->ieee80211_ptr;
fffd0934
JB
529 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
530 int i;
b23aa676
SO
531#ifdef CONFIG_WIRELESS_EXT
532 union iwreq_data wrqu;
533#endif
534
667503dd
JB
535 ASSERT_WDEV_LOCK(wdev);
536
b23aa676
SO
537 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
538 return;
539
540 if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED))
541 return;
542
543 if (wdev->current_bss) {
544 cfg80211_unhold_bss(wdev->current_bss);
19957bb3 545 cfg80211_put_bss(&wdev->current_bss->pub);
b23aa676
SO
546 }
547
548 wdev->current_bss = NULL;
549 wdev->sme_state = CFG80211_SME_IDLE;
550
6829c878
JB
551 if (wdev->conn) {
552 kfree(wdev->conn->ie);
553 wdev->conn->ie = NULL;
19957bb3
JB
554 kfree(wdev->conn);
555 wdev->conn = NULL;
6829c878
JB
556 }
557
fffd0934
JB
558 nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
559
560 /*
561 * Delete all the keys ... pairwise keys can't really
562 * exist any more anyway, but default keys might.
563 */
564 if (rdev->ops->del_key)
565 for (i = 0; i < 6; i++)
566 rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
b23aa676
SO
567
568#ifdef CONFIG_WIRELESS_EXT
569 memset(&wrqu, 0, sizeof(wrqu));
570 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
571 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
572#endif
573}
574
575void cfg80211_disconnected(struct net_device *dev, u16 reason,
576 u8 *ie, size_t ie_len, gfp_t gfp)
577{
667503dd
JB
578 struct wireless_dev *wdev = dev->ieee80211_ptr;
579 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
580 struct cfg80211_event *ev;
581 unsigned long flags;
582
583 ev = kzalloc(sizeof(*ev) + ie_len, gfp);
584 if (!ev)
585 return;
586
587 ev->type = EVENT_DISCONNECTED;
588 ev->dc.ie = ((u8 *)ev) + sizeof(*ev);
589 ev->dc.ie_len = ie_len;
590 memcpy((void *)ev->dc.ie, ie, ie_len);
591 ev->dc.reason = reason;
592
593 spin_lock_irqsave(&wdev->event_lock, flags);
594 list_add_tail(&ev->list, &wdev->event_list);
595 spin_unlock_irqrestore(&wdev->event_lock, flags);
596 schedule_work(&rdev->event_work);
b23aa676
SO
597}
598EXPORT_SYMBOL(cfg80211_disconnected);
599
667503dd
JB
600int __cfg80211_connect(struct cfg80211_registered_device *rdev,
601 struct net_device *dev,
fffd0934
JB
602 struct cfg80211_connect_params *connect,
603 struct cfg80211_cached_keys *connkeys)
b23aa676 604{
b23aa676 605 struct wireless_dev *wdev = dev->ieee80211_ptr;
667503dd
JB
606 int err;
607
608 ASSERT_WDEV_LOCK(wdev);
b23aa676
SO
609
610 if (wdev->sme_state != CFG80211_SME_IDLE)
611 return -EALREADY;
612
fffd0934
JB
613 if (WARN_ON(wdev->connect_keys)) {
614 kfree(wdev->connect_keys);
615 wdev->connect_keys = NULL;
616 }
617
618 if (connkeys && connkeys->def >= 0) {
619 int idx;
620
621 idx = connkeys->def;
622 /* If given a WEP key we may need it for shared key auth */
623 if (connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP40 ||
624 connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP104) {
625 connect->key_idx = idx;
626 connect->key = connkeys->params[idx].key;
627 connect->key_len = connkeys->params[idx].key_len;
628 }
629 }
630
b23aa676 631 if (!rdev->ops->connect) {
6829c878
JB
632 if (!rdev->ops->auth || !rdev->ops->assoc)
633 return -EOPNOTSUPP;
634
19957bb3
JB
635 if (WARN_ON(wdev->conn))
636 return -EINPROGRESS;
637
638 wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL);
639 if (!wdev->conn)
640 return -ENOMEM;
6829c878
JB
641
642 /*
643 * Copy all parameters, and treat explicitly IEs, BSSID, SSID.
644 */
645 memcpy(&wdev->conn->params, connect, sizeof(*connect));
646 if (connect->bssid) {
647 wdev->conn->params.bssid = wdev->conn->bssid;
648 memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN);
649 }
650
651 if (connect->ie) {
652 wdev->conn->ie = kmemdup(connect->ie, connect->ie_len,
653 GFP_KERNEL);
654 wdev->conn->params.ie = wdev->conn->ie;
19957bb3
JB
655 if (!wdev->conn->ie) {
656 kfree(wdev->conn);
657 wdev->conn = NULL;
6829c878 658 return -ENOMEM;
19957bb3 659 }
6829c878
JB
660 }
661
662 if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
663 wdev->conn->auto_auth = true;
664 /* start with open system ... should mostly work */
665 wdev->conn->params.auth_type =
666 NL80211_AUTHTYPE_OPEN_SYSTEM;
667 } else {
668 wdev->conn->auto_auth = false;
669 }
670
671 memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
672 wdev->ssid_len = connect->ssid_len;
673 wdev->conn->params.ssid = wdev->ssid;
674 wdev->conn->params.ssid_len = connect->ssid_len;
675
676 /* don't care about result -- but fill bssid & channel */
677 if (!wdev->conn->params.bssid || !wdev->conn->params.channel)
678 cfg80211_get_conn_bss(wdev);
679
680 wdev->sme_state = CFG80211_SME_CONNECTING;
fffd0934 681 wdev->connect_keys = connkeys;
6829c878
JB
682
683 /* we're good if we have both BSSID and channel */
684 if (wdev->conn->params.bssid && wdev->conn->params.channel) {
685 wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
686 err = cfg80211_conn_do_work(wdev);
687 } else {
688 /* otherwise we'll need to scan for the AP first */
689 err = cfg80211_conn_scan(wdev);
690 /*
691 * If we can't scan right now, then we need to scan again
692 * after the current scan finished, since the parameters
693 * changed (unless we find a good AP anyway).
694 */
695 if (err == -EBUSY) {
696 err = 0;
697 wdev->conn->state = CFG80211_CONN_SCAN_AGAIN;
698 }
699 }
19957bb3
JB
700 if (err) {
701 kfree(wdev->conn);
702 wdev->conn = NULL;
6829c878 703 wdev->sme_state = CFG80211_SME_IDLE;
fffd0934 704 wdev->connect_keys = NULL;
19957bb3 705 }
6829c878
JB
706
707 return err;
b23aa676
SO
708 } else {
709 wdev->sme_state = CFG80211_SME_CONNECTING;
fffd0934 710 wdev->connect_keys = connkeys;
b23aa676
SO
711 err = rdev->ops->connect(&rdev->wiphy, dev, connect);
712 if (err) {
fffd0934 713 wdev->connect_keys = NULL;
b23aa676
SO
714 wdev->sme_state = CFG80211_SME_IDLE;
715 return err;
716 }
b23aa676 717
6829c878
JB
718 memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
719 wdev->ssid_len = connect->ssid_len;
b23aa676 720
6829c878
JB
721 return 0;
722 }
b23aa676
SO
723}
724
667503dd
JB
725int cfg80211_connect(struct cfg80211_registered_device *rdev,
726 struct net_device *dev,
fffd0934
JB
727 struct cfg80211_connect_params *connect,
728 struct cfg80211_cached_keys *connkeys)
667503dd
JB
729{
730 int err;
731
732 wdev_lock(dev->ieee80211_ptr);
fffd0934 733 err = __cfg80211_connect(rdev, dev, connect, connkeys);
667503dd
JB
734 wdev_unlock(dev->ieee80211_ptr);
735
736 return err;
737}
738
739int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
740 struct net_device *dev, u16 reason, bool wextev)
b23aa676 741{
6829c878 742 struct wireless_dev *wdev = dev->ieee80211_ptr;
b23aa676
SO
743 int err;
744
667503dd
JB
745 ASSERT_WDEV_LOCK(wdev);
746
6829c878
JB
747 if (wdev->sme_state == CFG80211_SME_IDLE)
748 return -EINVAL;
749
fffd0934
JB
750 kfree(wdev->connect_keys);
751 wdev->connect_keys = NULL;
752
b23aa676 753 if (!rdev->ops->disconnect) {
19957bb3
JB
754 if (!rdev->ops->deauth)
755 return -EOPNOTSUPP;
6829c878 756
19957bb3
JB
757 /* was it connected by userspace SME? */
758 if (!wdev->conn) {
759 cfg80211_mlme_down(rdev, dev);
760 return 0;
761 }
6829c878
JB
762
763 if (wdev->sme_state == CFG80211_SME_CONNECTING &&
764 (wdev->conn->state == CFG80211_CONN_SCANNING ||
765 wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) {
766 wdev->sme_state = CFG80211_SME_IDLE;
19957bb3
JB
767 kfree(wdev->conn);
768 wdev->conn = NULL;
6829c878
JB
769 return 0;
770 }
771
6829c878 772 /* wdev->conn->params.bssid must be set if > SCANNING */
667503dd
JB
773 err = __cfg80211_mlme_deauth(rdev, dev,
774 wdev->conn->params.bssid,
775 NULL, 0, reason);
6829c878
JB
776 if (err)
777 return err;
b23aa676
SO
778 } else {
779 err = rdev->ops->disconnect(&rdev->wiphy, dev, reason);
780 if (err)
781 return err;
782 }
783
6829c878 784 if (wdev->sme_state == CFG80211_SME_CONNECTED)
667503dd 785 __cfg80211_disconnected(dev, NULL, 0, 0, false);
6829c878 786 else if (wdev->sme_state == CFG80211_SME_CONNECTING)
f2129354
JB
787 __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0,
788 WLAN_STATUS_UNSPECIFIED_FAILURE,
667503dd 789 wextev);
b23aa676
SO
790
791 return 0;
792}
19957bb3 793
667503dd
JB
794int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
795 struct net_device *dev,
796 u16 reason, bool wextev)
797{
798 int err;
799
800 wdev_lock(dev->ieee80211_ptr);
801 err = __cfg80211_disconnect(rdev, dev, reason, wextev);
802 wdev_unlock(dev->ieee80211_ptr);
803
804 return err;
805}
806
19957bb3
JB
807void cfg80211_sme_disassoc(struct net_device *dev, int idx)
808{
809 struct wireless_dev *wdev = dev->ieee80211_ptr;
810 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
811 u8 bssid[ETH_ALEN];
812
667503dd
JB
813 ASSERT_WDEV_LOCK(wdev);
814
19957bb3
JB
815 if (!wdev->conn)
816 return;
817
818 if (wdev->conn->state == CFG80211_CONN_IDLE)
819 return;
820
821 /*
822 * Ok, so the association was made by this SME -- we don't
823 * want it any more so deauthenticate too.
824 */
825
826 if (!wdev->auth_bsses[idx])
827 return;
828
829 memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN);
ec3f1490
JB
830 if (__cfg80211_mlme_deauth(rdev, dev, bssid,
831 NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) {
19957bb3
JB
832 /* whatever -- assume gone anyway */
833 cfg80211_unhold_bss(wdev->auth_bsses[idx]);
834 cfg80211_put_bss(&wdev->auth_bsses[idx]->pub);
835 wdev->auth_bsses[idx] = NULL;
836 }
837}