cfg80211: keep track of BSSes
[pandora-kernel.git] / net / wireless / sme.c
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
15 struct 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
34 static int cfg80211_conn_scan(struct wireless_dev *wdev)
35 {
36         struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy);
37         struct cfg80211_scan_request *request;
38         int n_channels, err;
39
40         ASSERT_RTNL();
41
42         if (drv->scan_req)
43                 return -EBUSY;
44
45         if (wdev->conn->params.channel) {
46                 n_channels = 1;
47         } else {
48                 enum ieee80211_band band;
49                 n_channels = 0;
50
51                 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
52                         if (!wdev->wiphy->bands[band])
53                                 continue;
54                         n_channels += wdev->wiphy->bands[band]->n_channels;
55                 }
56         }
57         request = kzalloc(sizeof(*request) + sizeof(request->ssids[0]) +
58                           sizeof(request->channels[0]) * n_channels,
59                           GFP_KERNEL);
60         if (!request)
61                 return -ENOMEM;
62
63         request->channels = (void *)((char *)request + sizeof(*request));
64         if (wdev->conn->params.channel)
65                 request->channels[0] = wdev->conn->params.channel;
66         else {
67                 int i = 0, j;
68                 enum ieee80211_band band;
69
70                 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
71                         if (!wdev->wiphy->bands[band])
72                                 continue;
73                         for (j = 0; j < wdev->wiphy->bands[band]->n_channels;
74                              i++, j++)
75                                 request->channels[i] =
76                                         &wdev->wiphy->bands[band]->channels[j];
77                 }
78         }
79         request->n_channels = n_channels;
80         request->ssids = (void *)(request->channels + n_channels);
81         request->n_ssids = 1;
82
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;
86
87         request->ifidx = wdev->netdev->ifindex;
88         request->wiphy = &drv->wiphy;
89
90         drv->scan_req = request;
91
92         err = drv->ops->scan(wdev->wiphy, wdev->netdev, request);
93         if (!err) {
94                 wdev->conn->state = CFG80211_CONN_SCANNING;
95                 nl80211_send_scan_start(drv, wdev->netdev);
96         } else {
97                 drv->scan_req = NULL;
98                 kfree(request);
99         }
100         return err;
101 }
102
103 static int cfg80211_conn_do_work(struct wireless_dev *wdev)
104 {
105         struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy);
106         struct cfg80211_connect_params *params;
107         int err;
108
109         if (!wdev->conn)
110                 return 0;
111
112         params = &wdev->conn->params;
113
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,
122                                           params->bssid,
123                                           params->ssid, params->ssid_len,
124                                           NULL, 0);
125         case CFG80211_CONN_ASSOCIATE_NEXT:
126                 BUG_ON(!drv->ops->assoc);
127                 wdev->conn->state = CFG80211_CONN_ASSOCIATING;
128                 err = cfg80211_mlme_assoc(drv, wdev->netdev,
129                                           params->channel, params->bssid,
130                                           params->ssid, params->ssid_len,
131                                           params->ie, params->ie_len,
132                                           false, &params->crypto);
133                 if (err)
134                         cfg80211_mlme_deauth(drv, wdev->netdev, params->bssid,
135                                              NULL, 0, WLAN_REASON_DEAUTH_LEAVING);
136                 return err;
137         default:
138                 return 0;
139         }
140 }
141
142 void cfg80211_conn_work(struct work_struct *work)
143 {
144         struct cfg80211_registered_device *drv =
145                 container_of(work, struct cfg80211_registered_device, conn_work);
146         struct wireless_dev *wdev;
147
148         rtnl_lock();
149         mutex_lock(&drv->devlist_mtx);
150
151         list_for_each_entry(wdev, &drv->netdev_list, list) {
152                 if (!netif_running(wdev->netdev))
153                         continue;
154                 if (wdev->sme_state != CFG80211_SME_CONNECTING)
155                         continue;
156                 if (cfg80211_conn_do_work(wdev))
157                         cfg80211_connect_result(wdev->netdev,
158                                                 wdev->conn->params.bssid,
159                                                 NULL, 0, NULL, 0,
160                                                 WLAN_STATUS_UNSPECIFIED_FAILURE,
161                                                 GFP_ATOMIC);
162         }
163
164         mutex_unlock(&drv->devlist_mtx);
165         rtnl_unlock();
166 }
167
168 static bool cfg80211_get_conn_bss(struct wireless_dev *wdev)
169 {
170         struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy);
171         struct cfg80211_bss *bss;
172         u16 capa = WLAN_CAPABILITY_ESS;
173
174         if (wdev->conn->params.privacy)
175                 capa |= WLAN_CAPABILITY_PRIVACY;
176
177         bss = cfg80211_get_bss(wdev->wiphy, NULL, wdev->conn->params.bssid,
178                                wdev->conn->params.ssid,
179                                wdev->conn->params.ssid_len,
180                                WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY,
181                                capa);
182         if (!bss)
183                 return false;
184
185         memcpy(wdev->conn->bssid, bss->bssid, ETH_ALEN);
186         wdev->conn->params.bssid = wdev->conn->bssid;
187         wdev->conn->params.channel = bss->channel;
188         wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
189         schedule_work(&drv->conn_work);
190
191         cfg80211_put_bss(bss);
192         return true;
193 }
194
195 void cfg80211_sme_scan_done(struct net_device *dev)
196 {
197         struct wireless_dev *wdev = dev->ieee80211_ptr;
198         struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy);
199
200         if (wdev->sme_state != CFG80211_SME_CONNECTING)
201                 return;
202
203         if (WARN_ON(!wdev->conn))
204                 return;
205
206         if (wdev->conn->state != CFG80211_CONN_SCANNING &&
207             wdev->conn->state != CFG80211_CONN_SCAN_AGAIN)
208                 return;
209
210         if (!cfg80211_get_conn_bss(wdev)) {
211                 /* not found */
212                 if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)
213                         schedule_work(&drv->conn_work);
214                 else
215                         cfg80211_connect_result(dev, wdev->conn->params.bssid,
216                                                 NULL, 0, NULL, 0,
217                                                 WLAN_STATUS_UNSPECIFIED_FAILURE,
218                                                 GFP_ATOMIC);
219                 return;
220         }
221 }
222
223 void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
224 {
225         struct wireless_dev *wdev = dev->ieee80211_ptr;
226         struct wiphy *wiphy = wdev->wiphy;
227         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
228         struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
229         u16 status_code = le16_to_cpu(mgmt->u.auth.status_code);
230
231         /* should only RX auth frames when connecting */
232         if (wdev->sme_state != CFG80211_SME_CONNECTING)
233                 return;
234
235         if (WARN_ON(!wdev->conn))
236                 return;
237
238         if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG &&
239             wdev->conn->auto_auth &&
240             wdev->conn->params.auth_type != NL80211_AUTHTYPE_NETWORK_EAP) {
241                 /* select automatically between only open, shared, leap */
242                 switch (wdev->conn->params.auth_type) {
243                 case NL80211_AUTHTYPE_OPEN_SYSTEM:
244                         wdev->conn->params.auth_type =
245                                 NL80211_AUTHTYPE_SHARED_KEY;
246                         break;
247                 case NL80211_AUTHTYPE_SHARED_KEY:
248                         wdev->conn->params.auth_type =
249                                 NL80211_AUTHTYPE_NETWORK_EAP;
250                         break;
251                 default:
252                         /* huh? */
253                         wdev->conn->params.auth_type =
254                                 NL80211_AUTHTYPE_OPEN_SYSTEM;
255                         break;
256                 }
257                 wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
258                 schedule_work(&rdev->conn_work);
259         } else if (status_code != WLAN_STATUS_SUCCESS) {
260                 wdev->sme_state = CFG80211_SME_IDLE;
261                 kfree(wdev->conn);
262                 wdev->conn = NULL;
263         } else if (wdev->sme_state == CFG80211_SME_CONNECTING &&
264                  wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
265                 wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
266                 schedule_work(&rdev->conn_work);
267         }
268 }
269
270 static void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
271                                       const u8 *req_ie, size_t req_ie_len,
272                                       const u8 *resp_ie, size_t resp_ie_len,
273                                       u16 status, bool wextev, gfp_t gfp)
274 {
275         struct wireless_dev *wdev = dev->ieee80211_ptr;
276         struct cfg80211_bss *bss;
277 #ifdef CONFIG_WIRELESS_EXT
278         union iwreq_data wrqu;
279 #endif
280
281         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
282                 return;
283
284         if (wdev->sme_state == CFG80211_SME_CONNECTED)
285                 nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev,
286                                     bssid, req_ie, req_ie_len,
287                                     resp_ie, resp_ie_len, gfp);
288         else
289                 nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev,
290                                             bssid, req_ie, req_ie_len,
291                                             resp_ie, resp_ie_len,
292                                             status, gfp);
293
294 #ifdef CONFIG_WIRELESS_EXT
295         if (wextev) {
296                 if (req_ie && status == WLAN_STATUS_SUCCESS) {
297                         memset(&wrqu, 0, sizeof(wrqu));
298                         wrqu.data.length = req_ie_len;
299                         wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie);
300                 }
301
302                 if (resp_ie && status == WLAN_STATUS_SUCCESS) {
303                         memset(&wrqu, 0, sizeof(wrqu));
304                         wrqu.data.length = resp_ie_len;
305                         wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie);
306                 }
307
308                 memset(&wrqu, 0, sizeof(wrqu));
309                 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
310                 if (bssid && status == WLAN_STATUS_SUCCESS)
311                         memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
312                 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
313         }
314 #endif
315
316         if (status == WLAN_STATUS_SUCCESS &&
317             wdev->sme_state == CFG80211_SME_IDLE) {
318                 wdev->sme_state = CFG80211_SME_CONNECTED;
319                 return;
320         }
321
322         if (wdev->sme_state != CFG80211_SME_CONNECTING)
323                 return;
324
325         if (wdev->current_bss) {
326                 cfg80211_unhold_bss(wdev->current_bss);
327                 cfg80211_put_bss(&wdev->current_bss->pub);
328                 wdev->current_bss = NULL;
329         }
330
331         if (wdev->conn)
332                 wdev->conn->state = CFG80211_CONN_IDLE;
333
334         if (status == WLAN_STATUS_SUCCESS) {
335                 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
336                                        wdev->ssid, wdev->ssid_len,
337                                        WLAN_CAPABILITY_ESS,
338                                        WLAN_CAPABILITY_ESS);
339
340                 if (WARN_ON(!bss))
341                         return;
342
343                 cfg80211_hold_bss(bss_from_pub(bss));
344                 wdev->current_bss = bss_from_pub(bss);
345
346                 wdev->sme_state = CFG80211_SME_CONNECTED;
347         } else {
348                 wdev->sme_state = CFG80211_SME_IDLE;
349                 kfree(wdev->conn);
350                 wdev->conn = NULL;
351         }
352 }
353
354 void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
355                              const u8 *req_ie, size_t req_ie_len,
356                              const u8 *resp_ie, size_t resp_ie_len,
357                              u16 status, gfp_t gfp)
358 {
359         bool wextev = status == WLAN_STATUS_SUCCESS;
360         __cfg80211_connect_result(dev, bssid, req_ie, req_ie_len, resp_ie, resp_ie_len, status, wextev, gfp);
361 }
362 EXPORT_SYMBOL(cfg80211_connect_result);
363
364 void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
365                      const u8 *req_ie, size_t req_ie_len,
366                      const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
367 {
368         struct wireless_dev *wdev = dev->ieee80211_ptr;
369         struct cfg80211_bss *bss;
370 #ifdef CONFIG_WIRELESS_EXT
371         union iwreq_data wrqu;
372 #endif
373
374         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
375                 return;
376
377         if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED))
378                 return;
379
380         /* internal error -- how did we get to CONNECTED w/o BSS? */
381         if (WARN_ON(!wdev->current_bss)) {
382                 return;
383         }
384
385         cfg80211_unhold_bss(wdev->current_bss);
386         cfg80211_put_bss(&wdev->current_bss->pub);
387         wdev->current_bss = NULL;
388
389         bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
390                                wdev->ssid, wdev->ssid_len,
391                                WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
392
393         if (WARN_ON(!bss))
394                 return;
395
396         cfg80211_hold_bss(bss_from_pub(bss));
397         wdev->current_bss = bss_from_pub(bss);
398
399         nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, bssid,
400                             req_ie, req_ie_len, resp_ie, resp_ie_len, gfp);
401
402 #ifdef CONFIG_WIRELESS_EXT
403         if (req_ie) {
404                 memset(&wrqu, 0, sizeof(wrqu));
405                 wrqu.data.length = req_ie_len;
406                 wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie);
407         }
408
409         if (resp_ie) {
410                 memset(&wrqu, 0, sizeof(wrqu));
411                 wrqu.data.length = resp_ie_len;
412                 wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie);
413         }
414
415         memset(&wrqu, 0, sizeof(wrqu));
416         wrqu.ap_addr.sa_family = ARPHRD_ETHER;
417         memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
418         wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
419 #endif
420 }
421 EXPORT_SYMBOL(cfg80211_roamed);
422
423 void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie,
424                              size_t ie_len, u16 reason, bool from_ap)
425 {
426         struct wireless_dev *wdev = dev->ieee80211_ptr;
427 #ifdef CONFIG_WIRELESS_EXT
428         union iwreq_data wrqu;
429 #endif
430
431         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
432                 return;
433
434         if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED))
435                 return;
436
437         if (wdev->current_bss) {
438                 cfg80211_unhold_bss(wdev->current_bss);
439                 cfg80211_put_bss(&wdev->current_bss->pub);
440         }
441
442         wdev->current_bss = NULL;
443         wdev->sme_state = CFG80211_SME_IDLE;
444
445         if (wdev->conn) {
446                 kfree(wdev->conn->ie);
447                 wdev->conn->ie = NULL;
448                 kfree(wdev->conn);
449                 wdev->conn = NULL;
450         }
451
452         nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev,
453                                   reason, ie, ie_len, from_ap, gfp);
454
455 #ifdef CONFIG_WIRELESS_EXT
456         memset(&wrqu, 0, sizeof(wrqu));
457         wrqu.ap_addr.sa_family = ARPHRD_ETHER;
458         wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
459 #endif
460 }
461
462 void cfg80211_disconnected(struct net_device *dev, u16 reason,
463                            u8 *ie, size_t ie_len, gfp_t gfp)
464 {
465         __cfg80211_disconnected(dev, gfp, ie, ie_len, reason, true);
466 }
467 EXPORT_SYMBOL(cfg80211_disconnected);
468
469 int cfg80211_connect(struct cfg80211_registered_device *rdev,
470                      struct net_device *dev,
471                      struct cfg80211_connect_params *connect)
472 {
473         int err;
474         struct wireless_dev *wdev = dev->ieee80211_ptr;
475
476         if (wdev->sme_state != CFG80211_SME_IDLE)
477                 return -EALREADY;
478
479         if (!rdev->ops->connect) {
480                 if (!rdev->ops->auth || !rdev->ops->assoc)
481                         return -EOPNOTSUPP;
482
483                 if (WARN_ON(wdev->conn))
484                         return -EINPROGRESS;
485
486                 wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL);
487                 if (!wdev->conn)
488                         return -ENOMEM;
489
490                 /*
491                  * Copy all parameters, and treat explicitly IEs, BSSID, SSID.
492                  */
493                 memcpy(&wdev->conn->params, connect, sizeof(*connect));
494                 if (connect->bssid) {
495                         wdev->conn->params.bssid = wdev->conn->bssid;
496                         memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN);
497                 }
498
499                 if (connect->ie) {
500                         wdev->conn->ie = kmemdup(connect->ie, connect->ie_len,
501                                                 GFP_KERNEL);
502                         wdev->conn->params.ie = wdev->conn->ie;
503                         if (!wdev->conn->ie) {
504                                 kfree(wdev->conn);
505                                 wdev->conn = NULL;
506                                 return -ENOMEM;
507                         }
508                 }
509
510                 if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
511                         wdev->conn->auto_auth = true;
512                         /* start with open system ... should mostly work */
513                         wdev->conn->params.auth_type =
514                                 NL80211_AUTHTYPE_OPEN_SYSTEM;
515                 } else {
516                         wdev->conn->auto_auth = false;
517                 }
518
519                 memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
520                 wdev->ssid_len = connect->ssid_len;
521                 wdev->conn->params.ssid = wdev->ssid;
522                 wdev->conn->params.ssid_len = connect->ssid_len;
523
524                 /* don't care about result -- but fill bssid & channel */
525                 if (!wdev->conn->params.bssid || !wdev->conn->params.channel)
526                         cfg80211_get_conn_bss(wdev);
527
528                 wdev->sme_state = CFG80211_SME_CONNECTING;
529
530                 /* we're good if we have both BSSID and channel */
531                 if (wdev->conn->params.bssid && wdev->conn->params.channel) {
532                         wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
533                         err = cfg80211_conn_do_work(wdev);
534                 } else {
535                         /* otherwise we'll need to scan for the AP first */
536                         err = cfg80211_conn_scan(wdev);
537                         /*
538                          * If we can't scan right now, then we need to scan again
539                          * after the current scan finished, since the parameters
540                          * changed (unless we find a good AP anyway).
541                          */
542                         if (err == -EBUSY) {
543                                 err = 0;
544                                 wdev->conn->state = CFG80211_CONN_SCAN_AGAIN;
545                         }
546                 }
547                 if (err) {
548                         kfree(wdev->conn);
549                         wdev->conn = NULL;
550                         wdev->sme_state = CFG80211_SME_IDLE;
551                 }
552
553                 return err;
554         } else {
555                 wdev->sme_state = CFG80211_SME_CONNECTING;
556                 err = rdev->ops->connect(&rdev->wiphy, dev, connect);
557                 if (err) {
558                         wdev->sme_state = CFG80211_SME_IDLE;
559                         return err;
560                 }
561
562                 memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
563                 wdev->ssid_len = connect->ssid_len;
564
565                 return 0;
566         }
567 }
568
569 int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
570                         struct net_device *dev, u16 reason, bool wextev)
571 {
572         struct wireless_dev *wdev = dev->ieee80211_ptr;
573         int err;
574
575         if (wdev->sme_state == CFG80211_SME_IDLE)
576                 return -EINVAL;
577
578         if (!rdev->ops->disconnect) {
579                 if (!rdev->ops->deauth)
580                         return -EOPNOTSUPP;
581
582                 /* was it connected by userspace SME? */
583                 if (!wdev->conn) {
584                         cfg80211_mlme_down(rdev, dev);
585                         return 0;
586                 }
587
588                 if (wdev->sme_state == CFG80211_SME_CONNECTING &&
589                     (wdev->conn->state == CFG80211_CONN_SCANNING ||
590                      wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) {
591                         wdev->sme_state = CFG80211_SME_IDLE;
592                         kfree(wdev->conn);
593                         wdev->conn = NULL;
594                         return 0;
595                 }
596
597                 /* wdev->conn->params.bssid must be set if > SCANNING */
598                 err = cfg80211_mlme_deauth(rdev, dev, wdev->conn->params.bssid,
599                                            NULL, 0, reason);
600                 if (err)
601                         return err;
602         } else {
603                 err = rdev->ops->disconnect(&rdev->wiphy, dev, reason);
604                 if (err)
605                         return err;
606         }
607
608         if (wdev->sme_state == CFG80211_SME_CONNECTED)
609                 __cfg80211_disconnected(dev, GFP_KERNEL, NULL, 0, 0, false);
610         else if (wdev->sme_state == CFG80211_SME_CONNECTING)
611                 __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0,
612                                           WLAN_STATUS_UNSPECIFIED_FAILURE,
613                                           wextev, GFP_KERNEL);
614
615         return 0;
616 }
617
618 void cfg80211_sme_disassoc(struct net_device *dev, int idx)
619 {
620         struct wireless_dev *wdev = dev->ieee80211_ptr;
621         struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
622         u8 bssid[ETH_ALEN];
623
624         if (!wdev->conn)
625                 return;
626
627         if (wdev->conn->state == CFG80211_CONN_IDLE)
628                 return;
629
630         /*
631          * Ok, so the association was made by this SME -- we don't
632          * want it any more so deauthenticate too.
633          */
634
635         if (!wdev->auth_bsses[idx])
636                 return;
637
638         memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN);
639         if (cfg80211_mlme_deauth(rdev, dev, bssid,
640                                  NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) {
641                 /* whatever -- assume gone anyway */
642                 cfg80211_unhold_bss(wdev->auth_bsses[idx]);
643                 cfg80211_put_bss(&wdev->auth_bsses[idx]->pub);
644                 wdev->auth_bsses[idx] = NULL;
645         }
646 }