cfg80211: send events for userspace SME
[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         union {
107                 struct cfg80211_auth_request auth_req;
108                 struct cfg80211_assoc_request assoc_req;
109         } u;
110
111         memset(&u, 0, sizeof(u));
112
113         if (!wdev->conn)
114                 return 0;
115
116         switch (wdev->conn->state) {
117         case CFG80211_CONN_SCAN_AGAIN:
118                 return cfg80211_conn_scan(wdev);
119         case CFG80211_CONN_AUTHENTICATE_NEXT:
120                 u.auth_req.chan = wdev->conn->params.channel;
121                 u.auth_req.peer_addr = wdev->conn->params.bssid;
122                 u.auth_req.ssid = wdev->conn->params.ssid;
123                 u.auth_req.ssid_len = wdev->conn->params.ssid_len;
124                 u.auth_req.auth_type = wdev->conn->params.auth_type;
125                 u.auth_req.ie = NULL;
126                 u.auth_req.ie_len = 0;
127                 wdev->conn->state = CFG80211_CONN_AUTHENTICATING;
128                 BUG_ON(!drv->ops->auth);
129                 return drv->ops->auth(wdev->wiphy, wdev->netdev, &u.auth_req);
130         case CFG80211_CONN_ASSOCIATE_NEXT:
131                 u.assoc_req.chan = wdev->conn->params.channel;
132                 u.assoc_req.peer_addr = wdev->conn->params.bssid;
133                 u.assoc_req.ssid = wdev->conn->params.ssid;
134                 u.assoc_req.ssid_len = wdev->conn->params.ssid_len;
135                 u.assoc_req.ie = wdev->conn->params.ie;
136                 u.assoc_req.ie_len = wdev->conn->params.ie_len;
137                 u.assoc_req.use_mfp = false;
138                 memcpy(&u.assoc_req.crypto, &wdev->conn->params.crypto,
139                         sizeof(u.assoc_req.crypto));
140                 wdev->conn->state = CFG80211_CONN_ASSOCIATING;
141                 BUG_ON(!drv->ops->assoc);
142                 return drv->ops->assoc(wdev->wiphy, wdev->netdev,
143                                         &u.assoc_req);
144         default:
145                 return 0;
146         }
147 }
148
149 void cfg80211_conn_work(struct work_struct *work)
150 {
151         struct cfg80211_registered_device *drv =
152                 container_of(work, struct cfg80211_registered_device, conn_work);
153         struct wireless_dev *wdev;
154
155         rtnl_lock();
156         mutex_lock(&drv->devlist_mtx);
157
158         list_for_each_entry(wdev, &drv->netdev_list, list) {
159                 if (!netif_running(wdev->netdev))
160                         continue;
161                 if (wdev->sme_state != CFG80211_SME_CONNECTING)
162                         continue;
163                 if (cfg80211_conn_do_work(wdev))
164                         cfg80211_connect_result(wdev->netdev,
165                                                 wdev->conn->params.bssid,
166                                                 NULL, 0, NULL, 0,
167                                                 WLAN_STATUS_UNSPECIFIED_FAILURE,
168                                                 GFP_ATOMIC);
169         }
170
171         mutex_unlock(&drv->devlist_mtx);
172         rtnl_unlock();
173 }
174
175 static bool cfg80211_get_conn_bss(struct wireless_dev *wdev)
176 {
177         struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy);
178         struct cfg80211_bss *bss;
179         u16 capa = WLAN_CAPABILITY_ESS;
180
181         if (wdev->conn->params.privacy)
182                 capa |= WLAN_CAPABILITY_PRIVACY;
183
184         bss = cfg80211_get_bss(wdev->wiphy, NULL, wdev->conn->params.bssid,
185                                wdev->conn->params.ssid,
186                                wdev->conn->params.ssid_len,
187                                WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY,
188                                capa);
189
190         if (!bss)
191                 return false;
192
193         memcpy(wdev->conn->bssid, bss->bssid, ETH_ALEN);
194         wdev->conn->params.bssid = wdev->conn->bssid;
195         wdev->conn->params.channel = bss->channel;
196         wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
197         schedule_work(&drv->conn_work);
198
199         cfg80211_put_bss(bss);
200         return true;
201 }
202
203 void cfg80211_sme_scan_done(struct net_device *dev)
204 {
205         struct wireless_dev *wdev = dev->ieee80211_ptr;
206         struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy);
207
208         if (wdev->sme_state != CFG80211_SME_CONNECTING)
209                 return;
210
211         if (WARN_ON(!wdev->conn))
212                 return;
213
214         if (wdev->conn->state != CFG80211_CONN_SCANNING &&
215             wdev->conn->state != CFG80211_CONN_SCAN_AGAIN)
216                 return;
217
218         if (!cfg80211_get_conn_bss(wdev)) {
219                 /* not found */
220                 if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)
221                         schedule_work(&drv->conn_work);
222                 else
223                         cfg80211_connect_result(dev, wdev->conn->params.bssid,
224                                                 NULL, 0, NULL, 0,
225                                                 WLAN_STATUS_UNSPECIFIED_FAILURE,
226                                                 GFP_ATOMIC);
227                 return;
228         }
229 }
230
231 void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
232 {
233         struct wireless_dev *wdev = dev->ieee80211_ptr;
234         struct wiphy *wiphy = wdev->wiphy;
235         struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
236         struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
237         u16 status_code = le16_to_cpu(mgmt->u.auth.status_code);
238
239         /* should only RX auth frames when connecting */
240         if (wdev->sme_state != CFG80211_SME_CONNECTING)
241                 return;
242
243         if (WARN_ON(!wdev->conn))
244                 return;
245
246         if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG &&
247             wdev->conn->auto_auth &&
248             wdev->conn->params.auth_type != NL80211_AUTHTYPE_NETWORK_EAP) {
249                 /* select automatically between only open, shared, leap */
250                 switch (wdev->conn->params.auth_type) {
251                 case NL80211_AUTHTYPE_OPEN_SYSTEM:
252                         wdev->conn->params.auth_type =
253                                 NL80211_AUTHTYPE_SHARED_KEY;
254                         break;
255                 case NL80211_AUTHTYPE_SHARED_KEY:
256                         wdev->conn->params.auth_type =
257                                 NL80211_AUTHTYPE_NETWORK_EAP;
258                         break;
259                 default:
260                         /* huh? */
261                         wdev->conn->params.auth_type =
262                                 NL80211_AUTHTYPE_OPEN_SYSTEM;
263                         break;
264                 }
265                 wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
266                 schedule_work(&rdev->conn_work);
267         } else if (status_code != WLAN_STATUS_SUCCESS)
268                 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);
273         }
274 }
275
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)
280 {
281         struct wireless_dev *wdev = dev->ieee80211_ptr;
282         struct cfg80211_bss *bss;
283 #ifdef CONFIG_WIRELESS_EXT
284         union iwreq_data wrqu;
285 #endif
286
287         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
288                 return;
289
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);
294         else
295                 nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev,
296                                             bssid, req_ie, req_ie_len,
297                                             resp_ie, resp_ie_len,
298                                             status, gfp);
299
300 #ifdef CONFIG_WIRELESS_EXT
301         if (wextev) {
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);
306                 }
307
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);
312                 }
313
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);
319         }
320 #endif
321
322         if (status == WLAN_STATUS_SUCCESS &&
323             wdev->sme_state == CFG80211_SME_IDLE) {
324                 wdev->sme_state = CFG80211_SME_CONNECTED;
325                 return;
326         }
327
328         if (wdev->sme_state != CFG80211_SME_CONNECTING)
329                 return;
330
331         if (wdev->current_bss) {
332                 cfg80211_unhold_bss(wdev->current_bss);
333                 cfg80211_put_bss(wdev->current_bss);
334                 wdev->current_bss = NULL;
335         }
336
337         if (status == WLAN_STATUS_SUCCESS) {
338                 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
339                                        wdev->ssid, wdev->ssid_len,
340                                        WLAN_CAPABILITY_ESS,
341                                        WLAN_CAPABILITY_ESS);
342
343                 if (WARN_ON(!bss))
344                         return;
345
346                 cfg80211_hold_bss(bss);
347                 wdev->current_bss = bss;
348
349                 wdev->sme_state = CFG80211_SME_CONNECTED;
350         } else {
351                 wdev->sme_state = CFG80211_SME_IDLE;
352         }
353
354         if (wdev->conn)
355                 wdev->conn->state = CFG80211_CONN_IDLE;
356 }
357
358 void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
359                              const u8 *req_ie, size_t req_ie_len,
360                              const u8 *resp_ie, size_t resp_ie_len,
361                              u16 status, gfp_t gfp)
362 {
363         bool wextev = status == WLAN_STATUS_SUCCESS;
364         __cfg80211_connect_result(dev, bssid, req_ie, req_ie_len, resp_ie, resp_ie_len, status, wextev, gfp);
365 }
366 EXPORT_SYMBOL(cfg80211_connect_result);
367
368 void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
369                      const u8 *req_ie, size_t req_ie_len,
370                      const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
371 {
372         struct wireless_dev *wdev = dev->ieee80211_ptr;
373         struct cfg80211_bss *bss;
374 #ifdef CONFIG_WIRELESS_EXT
375         union iwreq_data wrqu;
376 #endif
377
378         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
379                 return;
380
381         if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED))
382                 return;
383
384         /* internal error -- how did we get to CONNECTED w/o BSS? */
385         if (WARN_ON(!wdev->current_bss)) {
386                 return;
387         }
388
389         cfg80211_unhold_bss(wdev->current_bss);
390         cfg80211_put_bss(wdev->current_bss);
391         wdev->current_bss = NULL;
392
393         bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
394                                wdev->ssid, wdev->ssid_len,
395                                WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
396
397         if (WARN_ON(!bss))
398                 return;
399
400         cfg80211_hold_bss(bss);
401         wdev->current_bss = bss;
402
403         nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, bssid,
404                             req_ie, req_ie_len, resp_ie, resp_ie_len, gfp);
405
406 #ifdef CONFIG_WIRELESS_EXT
407         if (req_ie) {
408                 memset(&wrqu, 0, sizeof(wrqu));
409                 wrqu.data.length = req_ie_len;
410                 wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie);
411         }
412
413         if (resp_ie) {
414                 memset(&wrqu, 0, sizeof(wrqu));
415                 wrqu.data.length = resp_ie_len;
416                 wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie);
417         }
418
419         memset(&wrqu, 0, sizeof(wrqu));
420         wrqu.ap_addr.sa_family = ARPHRD_ETHER;
421         memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
422         wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
423 #endif
424 }
425 EXPORT_SYMBOL(cfg80211_roamed);
426
427 void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie,
428                              size_t ie_len, u16 reason, bool from_ap)
429 {
430         struct wireless_dev *wdev = dev->ieee80211_ptr;
431 #ifdef CONFIG_WIRELESS_EXT
432         union iwreq_data wrqu;
433 #endif
434
435         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
436                 return;
437
438         if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED))
439                 return;
440
441         if (wdev->current_bss) {
442                 cfg80211_unhold_bss(wdev->current_bss);
443                 cfg80211_put_bss(wdev->current_bss);
444         }
445
446         wdev->current_bss = NULL;
447         wdev->sme_state = CFG80211_SME_IDLE;
448
449         if (wdev->conn) {
450                 kfree(wdev->conn->ie);
451                 wdev->conn->ie = NULL;
452         }
453
454         nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev,
455                                   reason, ie, ie_len, from_ap, gfp);
456
457 #ifdef CONFIG_WIRELESS_EXT
458         memset(&wrqu, 0, sizeof(wrqu));
459         wrqu.ap_addr.sa_family = ARPHRD_ETHER;
460         wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
461 #endif
462 }
463
464 void cfg80211_disconnected(struct net_device *dev, u16 reason,
465                            u8 *ie, size_t ie_len, gfp_t gfp)
466 {
467         __cfg80211_disconnected(dev, gfp, ie, ie_len, reason, true);
468 }
469 EXPORT_SYMBOL(cfg80211_disconnected);
470
471 int cfg80211_connect(struct cfg80211_registered_device *rdev,
472                      struct net_device *dev,
473                      struct cfg80211_connect_params *connect)
474 {
475         int err;
476         struct wireless_dev *wdev = dev->ieee80211_ptr;
477
478         if (wdev->sme_state != CFG80211_SME_IDLE)
479                 return -EALREADY;
480
481         if (!rdev->ops->connect) {
482                 if (!rdev->ops->auth || !rdev->ops->assoc)
483                         return -EOPNOTSUPP;
484
485                 if (!wdev->conn) {
486                         wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL);
487                         if (!wdev->conn)
488                                 return -ENOMEM;
489                 } else
490                         memset(wdev->conn, 0, sizeof(*wdev->conn));
491
492                 /*
493                  * Copy all parameters, and treat explicitly IEs, BSSID, SSID.
494                  */
495                 memcpy(&wdev->conn->params, connect, sizeof(*connect));
496                 if (connect->bssid) {
497                         wdev->conn->params.bssid = wdev->conn->bssid;
498                         memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN);
499                 }
500
501                 if (connect->ie) {
502                         wdev->conn->ie = kmemdup(connect->ie, connect->ie_len,
503                                                 GFP_KERNEL);
504                         wdev->conn->params.ie = wdev->conn->ie;
505                         if (!wdev->conn->ie)
506                                 return -ENOMEM;
507                 }
508
509                 if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
510                         wdev->conn->auto_auth = true;
511                         /* start with open system ... should mostly work */
512                         wdev->conn->params.auth_type =
513                                 NL80211_AUTHTYPE_OPEN_SYSTEM;
514                 } else {
515                         wdev->conn->auto_auth = false;
516                 }
517
518                 memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
519                 wdev->ssid_len = connect->ssid_len;
520                 wdev->conn->params.ssid = wdev->ssid;
521                 wdev->conn->params.ssid_len = connect->ssid_len;
522
523                 /* don't care about result -- but fill bssid & channel */
524                 if (!wdev->conn->params.bssid || !wdev->conn->params.channel)
525                         cfg80211_get_conn_bss(wdev);
526
527                 wdev->sme_state = CFG80211_SME_CONNECTING;
528
529                 /* we're good if we have both BSSID and channel */
530                 if (wdev->conn->params.bssid && wdev->conn->params.channel) {
531                         wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
532                         err = cfg80211_conn_do_work(wdev);
533                 } else {
534                         /* otherwise we'll need to scan for the AP first */
535                         err = cfg80211_conn_scan(wdev);
536                         /*
537                          * If we can't scan right now, then we need to scan again
538                          * after the current scan finished, since the parameters
539                          * changed (unless we find a good AP anyway).
540                          */
541                         if (err == -EBUSY) {
542                                 err = 0;
543                                 wdev->conn->state = CFG80211_CONN_SCAN_AGAIN;
544                         }
545                 }
546                 if (err)
547                         wdev->sme_state = CFG80211_SME_IDLE;
548
549                 return err;
550         } else {
551                 wdev->sme_state = CFG80211_SME_CONNECTING;
552                 err = rdev->ops->connect(&rdev->wiphy, dev, connect);
553                 if (err) {
554                         wdev->sme_state = CFG80211_SME_IDLE;
555                         return err;
556                 }
557
558                 memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
559                 wdev->ssid_len = connect->ssid_len;
560
561                 return 0;
562         }
563 }
564
565 int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
566                         struct net_device *dev, u16 reason, bool wextev)
567 {
568         struct wireless_dev *wdev = dev->ieee80211_ptr;
569         int err;
570
571         if (wdev->sme_state == CFG80211_SME_IDLE)
572                 return -EINVAL;
573
574         if (!rdev->ops->disconnect) {
575                 struct cfg80211_deauth_request deauth;
576                 u8 bssid[ETH_ALEN];
577
578                 /* internal bug. */
579                 if (WARN_ON(!wdev->conn))
580                         return -EINVAL;
581
582                 if (wdev->sme_state == CFG80211_SME_CONNECTING &&
583                     (wdev->conn->state == CFG80211_CONN_SCANNING ||
584                      wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) {
585                         wdev->sme_state = CFG80211_SME_IDLE;
586                         return 0;
587                 }
588
589                 if (!rdev->ops->deauth)
590                         return -EOPNOTSUPP;
591
592                 memset(&deauth, 0, sizeof(deauth));
593
594                 /* wdev->conn->params.bssid must be set if > SCANNING */
595                 memcpy(bssid, wdev->conn->params.bssid, ETH_ALEN);
596                 deauth.peer_addr = bssid;
597                 deauth.reason_code = reason;
598
599                 err = rdev->ops->deauth(&rdev->wiphy, dev, &deauth);
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 }