]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame_incremental - net/wireless/sme.c
cfg80211: make aware of net namespaces
[mirror_ubuntu-bionic-kernel.git] / net / wireless / sme.c
... / ...
CommitLineData
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
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{
36 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
37 struct cfg80211_scan_request *request;
38 int n_channels, err;
39
40 ASSERT_RTNL();
41 ASSERT_RDEV_LOCK(rdev);
42 ASSERT_WDEV_LOCK(wdev);
43
44 if (rdev->scan_req)
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
89 request->dev = wdev->netdev;
90 request->wiphy = &rdev->wiphy;
91
92 rdev->scan_req = request;
93
94 err = rdev->ops->scan(wdev->wiphy, wdev->netdev, request);
95 if (!err) {
96 wdev->conn->state = CFG80211_CONN_SCANNING;
97 nl80211_send_scan_start(rdev, wdev->netdev);
98 dev_hold(wdev->netdev);
99 } else {
100 rdev->scan_req = NULL;
101 kfree(request);
102 }
103 return err;
104}
105
106static int cfg80211_conn_do_work(struct wireless_dev *wdev)
107{
108 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
109 struct cfg80211_connect_params *params;
110 int err;
111
112 ASSERT_WDEV_LOCK(wdev);
113
114 if (!wdev->conn)
115 return 0;
116
117 params = &wdev->conn->params;
118
119 switch (wdev->conn->state) {
120 case CFG80211_CONN_SCAN_AGAIN:
121 return cfg80211_conn_scan(wdev);
122 case CFG80211_CONN_AUTHENTICATE_NEXT:
123 BUG_ON(!rdev->ops->auth);
124 wdev->conn->state = CFG80211_CONN_AUTHENTICATING;
125 return __cfg80211_mlme_auth(rdev, wdev->netdev,
126 params->channel, params->auth_type,
127 params->bssid,
128 params->ssid, params->ssid_len,
129 NULL, 0,
130 params->key, params->key_len,
131 params->key_idx);
132 case CFG80211_CONN_ASSOCIATE_NEXT:
133 BUG_ON(!rdev->ops->assoc);
134 wdev->conn->state = CFG80211_CONN_ASSOCIATING;
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 */
141 err = __cfg80211_mlme_assoc(rdev, wdev->netdev,
142 params->channel, params->bssid,
143 NULL,
144 params->ssid, params->ssid_len,
145 params->ie, params->ie_len,
146 false, &params->crypto);
147 if (err)
148 __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
149 NULL, 0,
150 WLAN_REASON_DEAUTH_LEAVING);
151 return err;
152 default:
153 return 0;
154 }
155}
156
157void cfg80211_conn_work(struct work_struct *work)
158{
159 struct cfg80211_registered_device *rdev =
160 container_of(work, struct cfg80211_registered_device, conn_work);
161 struct wireless_dev *wdev;
162
163 rtnl_lock();
164 cfg80211_lock_rdev(rdev);
165 mutex_lock(&rdev->devlist_mtx);
166
167 list_for_each_entry(wdev, &rdev->netdev_list, list) {
168 wdev_lock(wdev);
169 if (!netif_running(wdev->netdev)) {
170 wdev_unlock(wdev);
171 continue;
172 }
173 if (wdev->sme_state != CFG80211_SME_CONNECTING) {
174 wdev_unlock(wdev);
175 continue;
176 }
177 if (cfg80211_conn_do_work(wdev))
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);
185 }
186
187 mutex_unlock(&rdev->devlist_mtx);
188 cfg80211_unlock_rdev(rdev);
189 rtnl_unlock();
190}
191
192static bool cfg80211_get_conn_bss(struct wireless_dev *wdev)
193{
194 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
195 struct cfg80211_bss *bss;
196 u16 capa = WLAN_CAPABILITY_ESS;
197
198 ASSERT_WDEV_LOCK(wdev);
199
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);
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;
215 schedule_work(&rdev->conn_work);
216
217 cfg80211_put_bss(bss);
218 return true;
219}
220
221static void __cfg80211_sme_scan_done(struct net_device *dev)
222{
223 struct wireless_dev *wdev = dev->ieee80211_ptr;
224 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
225
226 ASSERT_WDEV_LOCK(wdev);
227
228 if (wdev->sme_state != CFG80211_SME_CONNECTING)
229 return;
230
231 if (!wdev->conn)
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)
241 schedule_work(&rdev->conn_work);
242 else
243 __cfg80211_connect_result(
244 wdev->netdev,
245 wdev->conn->params.bssid,
246 NULL, 0, NULL, 0,
247 WLAN_STATUS_UNSPECIFIED_FAILURE,
248 false);
249 }
250}
251
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)
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
270 ASSERT_WDEV_LOCK(wdev);
271
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:
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;
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);
304 } else if (status_code != WLAN_STATUS_SUCCESS) {
305 __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
306 status_code, false);
307 } else if (wdev->sme_state == CFG80211_SME_CONNECTING &&
308 wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
309 wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
310 schedule_work(&rdev->conn_work);
311 }
312}
313
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)
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
325 ASSERT_WDEV_LOCK(wdev);
326
327 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
328 return;
329
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,
333 resp_ie, resp_ie_len, GFP_KERNEL);
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,
338 status, GFP_KERNEL);
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;
345 wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, req_ie);
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 &&
363 wdev->sme_state == CFG80211_SME_IDLE)
364 goto success;
365
366 if (wdev->sme_state != CFG80211_SME_CONNECTING)
367 return;
368
369 if (wdev->current_bss) {
370 cfg80211_unhold_bss(wdev->current_bss);
371 cfg80211_put_bss(&wdev->current_bss->pub);
372 wdev->current_bss = NULL;
373 }
374
375 if (wdev->conn)
376 wdev->conn->state = CFG80211_CONN_IDLE;
377
378 if (status != WLAN_STATUS_SUCCESS) {
379 wdev->sme_state = CFG80211_SME_IDLE;
380 kfree(wdev->conn);
381 wdev->conn = NULL;
382 kfree(wdev->connect_keys);
383 wdev->connect_keys = NULL;
384 return;
385 }
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);
401}
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{
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);
431}
432EXPORT_SYMBOL(cfg80211_connect_result);
433
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)
437{
438 struct cfg80211_bss *bss;
439#ifdef CONFIG_WIRELESS_EXT
440 union iwreq_data wrqu;
441#endif
442
443 ASSERT_WDEV_LOCK(wdev);
444
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);
457 cfg80211_put_bss(&wdev->current_bss->pub);
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
467 cfg80211_hold_bss(bss_from_pub(bss));
468 wdev->current_bss = bss_from_pub(bss);
469
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);
473
474#ifdef CONFIG_WIRELESS_EXT
475 if (req_ie) {
476 memset(&wrqu, 0, sizeof(wrqu));
477 wrqu.data.length = req_ie_len;
478 wireless_send_event(wdev->netdev, IWEVASSOCREQIE,
479 &wrqu, req_ie);
480 }
481
482 if (resp_ie) {
483 memset(&wrqu, 0, sizeof(wrqu));
484 wrqu.data.length = resp_ie_len;
485 wireless_send_event(wdev->netdev, IWEVASSOCRESPIE,
486 &wrqu, resp_ie);
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);
492 wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL);
493#endif
494}
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}
523EXPORT_SYMBOL(cfg80211_roamed);
524
525void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
526 size_t ie_len, u16 reason, bool from_ap)
527{
528 struct wireless_dev *wdev = dev->ieee80211_ptr;
529 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
530 int i;
531#ifdef CONFIG_WIRELESS_EXT
532 union iwreq_data wrqu;
533#endif
534
535 ASSERT_WDEV_LOCK(wdev);
536
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);
545 cfg80211_put_bss(&wdev->current_bss->pub);
546 }
547
548 wdev->current_bss = NULL;
549 wdev->sme_state = CFG80211_SME_IDLE;
550
551 if (wdev->conn) {
552 kfree(wdev->conn->ie);
553 wdev->conn->ie = NULL;
554 kfree(wdev->conn);
555 wdev->conn = NULL;
556 }
557
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);
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{
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);
597}
598EXPORT_SYMBOL(cfg80211_disconnected);
599
600int __cfg80211_connect(struct cfg80211_registered_device *rdev,
601 struct net_device *dev,
602 struct cfg80211_connect_params *connect,
603 struct cfg80211_cached_keys *connkeys)
604{
605 struct wireless_dev *wdev = dev->ieee80211_ptr;
606 int err;
607
608 ASSERT_WDEV_LOCK(wdev);
609
610 if (wdev->sme_state != CFG80211_SME_IDLE)
611 return -EALREADY;
612
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
631 if (!rdev->ops->connect) {
632 if (!rdev->ops->auth || !rdev->ops->assoc)
633 return -EOPNOTSUPP;
634
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;
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;
655 if (!wdev->conn->ie) {
656 kfree(wdev->conn);
657 wdev->conn = NULL;
658 return -ENOMEM;
659 }
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;
681 wdev->connect_keys = connkeys;
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 }
700 if (err) {
701 kfree(wdev->conn);
702 wdev->conn = NULL;
703 wdev->sme_state = CFG80211_SME_IDLE;
704 wdev->connect_keys = NULL;
705 }
706
707 return err;
708 } else {
709 wdev->sme_state = CFG80211_SME_CONNECTING;
710 wdev->connect_keys = connkeys;
711 err = rdev->ops->connect(&rdev->wiphy, dev, connect);
712 if (err) {
713 wdev->connect_keys = NULL;
714 wdev->sme_state = CFG80211_SME_IDLE;
715 return err;
716 }
717
718 memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
719 wdev->ssid_len = connect->ssid_len;
720
721 return 0;
722 }
723}
724
725int cfg80211_connect(struct cfg80211_registered_device *rdev,
726 struct net_device *dev,
727 struct cfg80211_connect_params *connect,
728 struct cfg80211_cached_keys *connkeys)
729{
730 int err;
731
732 wdev_lock(dev->ieee80211_ptr);
733 err = __cfg80211_connect(rdev, dev, connect, connkeys);
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)
741{
742 struct wireless_dev *wdev = dev->ieee80211_ptr;
743 int err;
744
745 ASSERT_WDEV_LOCK(wdev);
746
747 if (wdev->sme_state == CFG80211_SME_IDLE)
748 return -EINVAL;
749
750 kfree(wdev->connect_keys);
751 wdev->connect_keys = NULL;
752
753 if (!rdev->ops->disconnect) {
754 if (!rdev->ops->deauth)
755 return -EOPNOTSUPP;
756
757 /* was it connected by userspace SME? */
758 if (!wdev->conn) {
759 cfg80211_mlme_down(rdev, dev);
760 return 0;
761 }
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;
767 kfree(wdev->conn);
768 wdev->conn = NULL;
769 return 0;
770 }
771
772 /* wdev->conn->params.bssid must be set if > SCANNING */
773 err = __cfg80211_mlme_deauth(rdev, dev,
774 wdev->conn->params.bssid,
775 NULL, 0, reason);
776 if (err)
777 return err;
778 } else {
779 err = rdev->ops->disconnect(&rdev->wiphy, dev, reason);
780 if (err)
781 return err;
782 }
783
784 if (wdev->sme_state == CFG80211_SME_CONNECTED)
785 __cfg80211_disconnected(dev, NULL, 0, 0, false);
786 else if (wdev->sme_state == CFG80211_SME_CONNECTING)
787 __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0,
788 WLAN_STATUS_UNSPECIFIED_FAILURE,
789 wextev);
790
791 return 0;
792}
793
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
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
813 ASSERT_WDEV_LOCK(wdev);
814
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);
830 if (__cfg80211_mlme_deauth(rdev, dev, bssid,
831 NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) {
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}