LCOV - code coverage report
Current view: top level - net/wireless - sme.c (source / functions) Hit Total Coverage
Test: Real Lines: 0 592 0.0 %
Date: 2020-10-17 15:46:16 Functions: 0 30 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * SME code for cfg80211
       4                 :            :  * both driver SME event handling and the SME implementation
       5                 :            :  * (for nl80211's connect() and wext)
       6                 :            :  *
       7                 :            :  * Copyright 2009       Johannes Berg <johannes@sipsolutions.net>
       8                 :            :  * Copyright (C) 2009   Intel Corporation. All rights reserved.
       9                 :            :  * Copyright 2017       Intel Deutschland GmbH
      10                 :            :  */
      11                 :            : 
      12                 :            : #include <linux/etherdevice.h>
      13                 :            : #include <linux/if_arp.h>
      14                 :            : #include <linux/slab.h>
      15                 :            : #include <linux/workqueue.h>
      16                 :            : #include <linux/wireless.h>
      17                 :            : #include <linux/export.h>
      18                 :            : #include <net/iw_handler.h>
      19                 :            : #include <net/cfg80211.h>
      20                 :            : #include <net/rtnetlink.h>
      21                 :            : #include "nl80211.h"
      22                 :            : #include "reg.h"
      23                 :            : #include "rdev-ops.h"
      24                 :            : 
      25                 :            : /*
      26                 :            :  * Software SME in cfg80211, using auth/assoc/deauth calls to the
      27                 :            :  * driver. This is is for implementing nl80211's connect/disconnect
      28                 :            :  * and wireless extensions (if configured.)
      29                 :            :  */
      30                 :            : 
      31                 :            : struct cfg80211_conn {
      32                 :            :         struct cfg80211_connect_params params;
      33                 :            :         /* these are sub-states of the _CONNECTING sme_state */
      34                 :            :         enum {
      35                 :            :                 CFG80211_CONN_SCANNING,
      36                 :            :                 CFG80211_CONN_SCAN_AGAIN,
      37                 :            :                 CFG80211_CONN_AUTHENTICATE_NEXT,
      38                 :            :                 CFG80211_CONN_AUTHENTICATING,
      39                 :            :                 CFG80211_CONN_AUTH_FAILED_TIMEOUT,
      40                 :            :                 CFG80211_CONN_ASSOCIATE_NEXT,
      41                 :            :                 CFG80211_CONN_ASSOCIATING,
      42                 :            :                 CFG80211_CONN_ASSOC_FAILED,
      43                 :            :                 CFG80211_CONN_ASSOC_FAILED_TIMEOUT,
      44                 :            :                 CFG80211_CONN_DEAUTH,
      45                 :            :                 CFG80211_CONN_ABANDON,
      46                 :            :                 CFG80211_CONN_CONNECTED,
      47                 :            :         } state;
      48                 :            :         u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
      49                 :            :         const u8 *ie;
      50                 :            :         size_t ie_len;
      51                 :            :         bool auto_auth, prev_bssid_valid;
      52                 :            : };
      53                 :            : 
      54                 :          0 : static void cfg80211_sme_free(struct wireless_dev *wdev)
      55                 :            : {
      56                 :          0 :         if (!wdev->conn)
      57                 :          0 :                 return;
      58                 :            : 
      59                 :          0 :         kfree(wdev->conn->ie);
      60                 :          0 :         kfree(wdev->conn);
      61                 :          0 :         wdev->conn = NULL;
      62                 :            : }
      63                 :            : 
      64                 :          0 : static int cfg80211_conn_scan(struct wireless_dev *wdev)
      65                 :            : {
      66                 :          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
      67                 :            :         struct cfg80211_scan_request *request;
      68                 :            :         int n_channels, err;
      69                 :            : 
      70                 :          0 :         ASSERT_RTNL();
      71                 :            :         ASSERT_WDEV_LOCK(wdev);
      72                 :            : 
      73                 :          0 :         if (rdev->scan_req || rdev->scan_msg)
      74                 :            :                 return -EBUSY;
      75                 :            : 
      76                 :          0 :         if (wdev->conn->params.channel)
      77                 :            :                 n_channels = 1;
      78                 :            :         else
      79                 :          0 :                 n_channels = ieee80211_get_num_supported_channels(wdev->wiphy);
      80                 :            : 
      81                 :          0 :         request = kzalloc(sizeof(*request) + sizeof(request->ssids[0]) +
      82                 :          0 :                           sizeof(request->channels[0]) * n_channels,
      83                 :            :                           GFP_KERNEL);
      84                 :          0 :         if (!request)
      85                 :            :                 return -ENOMEM;
      86                 :            : 
      87                 :          0 :         if (wdev->conn->params.channel) {
      88                 :          0 :                 enum nl80211_band band = wdev->conn->params.channel->band;
      89                 :          0 :                 struct ieee80211_supported_band *sband =
      90                 :          0 :                         wdev->wiphy->bands[band];
      91                 :            : 
      92                 :          0 :                 if (!sband) {
      93                 :          0 :                         kfree(request);
      94                 :          0 :                         return -EINVAL;
      95                 :            :                 }
      96                 :          0 :                 request->channels[0] = wdev->conn->params.channel;
      97                 :          0 :                 request->rates[band] = (1 << sband->n_bitrates) - 1;
      98                 :            :         } else {
      99                 :            :                 int i = 0, j;
     100                 :            :                 enum nl80211_band band;
     101                 :            :                 struct ieee80211_supported_band *bands;
     102                 :            :                 struct ieee80211_channel *channel;
     103                 :            : 
     104                 :          0 :                 for (band = 0; band < NUM_NL80211_BANDS; band++) {
     105                 :          0 :                         bands = wdev->wiphy->bands[band];
     106                 :          0 :                         if (!bands)
     107                 :          0 :                                 continue;
     108                 :          0 :                         for (j = 0; j < bands->n_channels; j++) {
     109                 :          0 :                                 channel = &bands->channels[j];
     110                 :          0 :                                 if (channel->flags & IEEE80211_CHAN_DISABLED)
     111                 :          0 :                                         continue;
     112                 :          0 :                                 request->channels[i++] = channel;
     113                 :            :                         }
     114                 :          0 :                         request->rates[band] = (1 << bands->n_bitrates) - 1;
     115                 :            :                 }
     116                 :          0 :                 n_channels = i;
     117                 :            :         }
     118                 :          0 :         request->n_channels = n_channels;
     119                 :          0 :         request->ssids = (void *)&request->channels[n_channels];
     120                 :          0 :         request->n_ssids = 1;
     121                 :            : 
     122                 :          0 :         memcpy(request->ssids[0].ssid, wdev->conn->params.ssid,
     123                 :            :                 wdev->conn->params.ssid_len);
     124                 :          0 :         request->ssids[0].ssid_len = wdev->conn->params.ssid_len;
     125                 :            : 
     126                 :          0 :         eth_broadcast_addr(request->bssid);
     127                 :            : 
     128                 :          0 :         request->wdev = wdev;
     129                 :          0 :         request->wiphy = &rdev->wiphy;
     130                 :          0 :         request->scan_start = jiffies;
     131                 :            : 
     132                 :          0 :         rdev->scan_req = request;
     133                 :            : 
     134                 :          0 :         err = rdev_scan(rdev, request);
     135                 :          0 :         if (!err) {
     136                 :          0 :                 wdev->conn->state = CFG80211_CONN_SCANNING;
     137                 :          0 :                 nl80211_send_scan_start(rdev, wdev);
     138                 :          0 :                 dev_hold(wdev->netdev);
     139                 :            :         } else {
     140                 :          0 :                 rdev->scan_req = NULL;
     141                 :          0 :                 kfree(request);
     142                 :            :         }
     143                 :          0 :         return err;
     144                 :            : }
     145                 :            : 
     146                 :          0 : static int cfg80211_conn_do_work(struct wireless_dev *wdev,
     147                 :            :                                  enum nl80211_timeout_reason *treason)
     148                 :            : {
     149                 :          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
     150                 :            :         struct cfg80211_connect_params *params;
     151                 :          0 :         struct cfg80211_assoc_request req = {};
     152                 :            :         int err;
     153                 :            : 
     154                 :            :         ASSERT_WDEV_LOCK(wdev);
     155                 :            : 
     156                 :          0 :         if (!wdev->conn)
     157                 :            :                 return 0;
     158                 :            : 
     159                 :            :         params = &wdev->conn->params;
     160                 :            : 
     161                 :          0 :         switch (wdev->conn->state) {
     162                 :            :         case CFG80211_CONN_SCANNING:
     163                 :            :                 /* didn't find it during scan ... */
     164                 :            :                 return -ENOENT;
     165                 :            :         case CFG80211_CONN_SCAN_AGAIN:
     166                 :          0 :                 return cfg80211_conn_scan(wdev);
     167                 :            :         case CFG80211_CONN_AUTHENTICATE_NEXT:
     168                 :          0 :                 if (WARN_ON(!rdev->ops->auth))
     169                 :            :                         return -EOPNOTSUPP;
     170                 :          0 :                 wdev->conn->state = CFG80211_CONN_AUTHENTICATING;
     171                 :          0 :                 return cfg80211_mlme_auth(rdev, wdev->netdev,
     172                 :            :                                           params->channel, params->auth_type,
     173                 :            :                                           params->bssid,
     174                 :          0 :                                           params->ssid, params->ssid_len,
     175                 :            :                                           NULL, 0,
     176                 :          0 :                                           params->key, params->key_len,
     177                 :          0 :                                           params->key_idx, NULL, 0);
     178                 :            :         case CFG80211_CONN_AUTH_FAILED_TIMEOUT:
     179                 :          0 :                 *treason = NL80211_TIMEOUT_AUTH;
     180                 :          0 :                 return -ENOTCONN;
     181                 :            :         case CFG80211_CONN_ASSOCIATE_NEXT:
     182                 :          0 :                 if (WARN_ON(!rdev->ops->assoc))
     183                 :            :                         return -EOPNOTSUPP;
     184                 :          0 :                 wdev->conn->state = CFG80211_CONN_ASSOCIATING;
     185                 :          0 :                 if (wdev->conn->prev_bssid_valid)
     186                 :          0 :                         req.prev_bssid = wdev->conn->prev_bssid;
     187                 :          0 :                 req.ie = params->ie;
     188                 :          0 :                 req.ie_len = params->ie_len;
     189                 :          0 :                 req.use_mfp = params->mfp != NL80211_MFP_NO;
     190                 :          0 :                 req.crypto = params->crypto;
     191                 :          0 :                 req.flags = params->flags;
     192                 :          0 :                 req.ht_capa = params->ht_capa;
     193                 :          0 :                 req.ht_capa_mask = params->ht_capa_mask;
     194                 :          0 :                 req.vht_capa = params->vht_capa;
     195                 :          0 :                 req.vht_capa_mask = params->vht_capa_mask;
     196                 :            : 
     197                 :          0 :                 err = cfg80211_mlme_assoc(rdev, wdev->netdev, params->channel,
     198                 :            :                                           params->bssid, params->ssid,
     199                 :          0 :                                           params->ssid_len, &req);
     200                 :          0 :                 if (err)
     201                 :          0 :                         cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
     202                 :            :                                              NULL, 0,
     203                 :            :                                              WLAN_REASON_DEAUTH_LEAVING,
     204                 :            :                                              false);
     205                 :          0 :                 return err;
     206                 :            :         case CFG80211_CONN_ASSOC_FAILED_TIMEOUT:
     207                 :          0 :                 *treason = NL80211_TIMEOUT_ASSOC;
     208                 :            :                 /* fall through */
     209                 :            :         case CFG80211_CONN_ASSOC_FAILED:
     210                 :          0 :                 cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
     211                 :            :                                      NULL, 0,
     212                 :            :                                      WLAN_REASON_DEAUTH_LEAVING, false);
     213                 :          0 :                 return -ENOTCONN;
     214                 :            :         case CFG80211_CONN_DEAUTH:
     215                 :          0 :                 cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
     216                 :            :                                      NULL, 0,
     217                 :            :                                      WLAN_REASON_DEAUTH_LEAVING, false);
     218                 :            :                 /* fall through */
     219                 :            :         case CFG80211_CONN_ABANDON:
     220                 :            :                 /* free directly, disconnected event already sent */
     221                 :          0 :                 cfg80211_sme_free(wdev);
     222                 :          0 :                 return 0;
     223                 :            :         default:
     224                 :          0 :                 return 0;
     225                 :            :         }
     226                 :            : }
     227                 :            : 
     228                 :          0 : void cfg80211_conn_work(struct work_struct *work)
     229                 :            : {
     230                 :            :         struct cfg80211_registered_device *rdev =
     231                 :            :                 container_of(work, struct cfg80211_registered_device, conn_work);
     232                 :            :         struct wireless_dev *wdev;
     233                 :            :         u8 bssid_buf[ETH_ALEN], *bssid = NULL;
     234                 :            :         enum nl80211_timeout_reason treason;
     235                 :            : 
     236                 :          0 :         rtnl_lock();
     237                 :            : 
     238                 :          0 :         list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
     239                 :          0 :                 if (!wdev->netdev)
     240                 :          0 :                         continue;
     241                 :            : 
     242                 :            :                 wdev_lock(wdev);
     243                 :          0 :                 if (!netif_running(wdev->netdev)) {
     244                 :            :                         wdev_unlock(wdev);
     245                 :          0 :                         continue;
     246                 :            :                 }
     247                 :          0 :                 if (!wdev->conn ||
     248                 :          0 :                     wdev->conn->state == CFG80211_CONN_CONNECTED) {
     249                 :            :                         wdev_unlock(wdev);
     250                 :          0 :                         continue;
     251                 :            :                 }
     252                 :          0 :                 if (wdev->conn->params.bssid) {
     253                 :          0 :                         memcpy(bssid_buf, wdev->conn->params.bssid, ETH_ALEN);
     254                 :            :                         bssid = bssid_buf;
     255                 :            :                 }
     256                 :          0 :                 treason = NL80211_TIMEOUT_UNSPECIFIED;
     257                 :          0 :                 if (cfg80211_conn_do_work(wdev, &treason)) {
     258                 :            :                         struct cfg80211_connect_resp_params cr;
     259                 :            : 
     260                 :          0 :                         memset(&cr, 0, sizeof(cr));
     261                 :          0 :                         cr.status = -1;
     262                 :          0 :                         cr.bssid = bssid;
     263                 :          0 :                         cr.timeout_reason = treason;
     264                 :          0 :                         __cfg80211_connect_result(wdev->netdev, &cr, false);
     265                 :            :                 }
     266                 :            :                 wdev_unlock(wdev);
     267                 :            :         }
     268                 :            : 
     269                 :          0 :         rtnl_unlock();
     270                 :          0 : }
     271                 :            : 
     272                 :            : /* Returned bss is reference counted and must be cleaned up appropriately. */
     273                 :          0 : static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev)
     274                 :            : {
     275                 :          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
     276                 :            :         struct cfg80211_bss *bss;
     277                 :            : 
     278                 :            :         ASSERT_WDEV_LOCK(wdev);
     279                 :            : 
     280                 :          0 :         bss = cfg80211_get_bss(wdev->wiphy, wdev->conn->params.channel,
     281                 :            :                                wdev->conn->params.bssid,
     282                 :            :                                wdev->conn->params.ssid,
     283                 :            :                                wdev->conn->params.ssid_len,
     284                 :            :                                wdev->conn_bss_type,
     285                 :          0 :                                IEEE80211_PRIVACY(wdev->conn->params.privacy));
     286                 :          0 :         if (!bss)
     287                 :            :                 return NULL;
     288                 :            : 
     289                 :          0 :         memcpy(wdev->conn->bssid, bss->bssid, ETH_ALEN);
     290                 :          0 :         wdev->conn->params.bssid = wdev->conn->bssid;
     291                 :          0 :         wdev->conn->params.channel = bss->channel;
     292                 :          0 :         wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
     293                 :          0 :         schedule_work(&rdev->conn_work);
     294                 :            : 
     295                 :          0 :         return bss;
     296                 :            : }
     297                 :            : 
     298                 :          0 : static void __cfg80211_sme_scan_done(struct net_device *dev)
     299                 :            : {
     300                 :          0 :         struct wireless_dev *wdev = dev->ieee80211_ptr;
     301                 :          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
     302                 :            :         struct cfg80211_bss *bss;
     303                 :            : 
     304                 :            :         ASSERT_WDEV_LOCK(wdev);
     305                 :            : 
     306                 :          0 :         if (!wdev->conn)
     307                 :            :                 return;
     308                 :            : 
     309                 :          0 :         if (wdev->conn->state != CFG80211_CONN_SCANNING &&
     310                 :            :             wdev->conn->state != CFG80211_CONN_SCAN_AGAIN)
     311                 :            :                 return;
     312                 :            : 
     313                 :          0 :         bss = cfg80211_get_conn_bss(wdev);
     314                 :          0 :         if (bss)
     315                 :          0 :                 cfg80211_put_bss(&rdev->wiphy, bss);
     316                 :            :         else
     317                 :          0 :                 schedule_work(&rdev->conn_work);
     318                 :            : }
     319                 :            : 
     320                 :          0 : void cfg80211_sme_scan_done(struct net_device *dev)
     321                 :            : {
     322                 :          0 :         struct wireless_dev *wdev = dev->ieee80211_ptr;
     323                 :            : 
     324                 :            :         wdev_lock(wdev);
     325                 :          0 :         __cfg80211_sme_scan_done(dev);
     326                 :            :         wdev_unlock(wdev);
     327                 :          0 : }
     328                 :            : 
     329                 :          0 : void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len)
     330                 :            : {
     331                 :          0 :         struct wiphy *wiphy = wdev->wiphy;
     332                 :            :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
     333                 :            :         struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
     334                 :          0 :         u16 status_code = le16_to_cpu(mgmt->u.auth.status_code);
     335                 :            : 
     336                 :            :         ASSERT_WDEV_LOCK(wdev);
     337                 :            : 
     338                 :          0 :         if (!wdev->conn || wdev->conn->state == CFG80211_CONN_CONNECTED)
     339                 :          0 :                 return;
     340                 :            : 
     341                 :          0 :         if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG &&
     342                 :          0 :             wdev->conn->auto_auth &&
     343                 :          0 :             wdev->conn->params.auth_type != NL80211_AUTHTYPE_NETWORK_EAP) {
     344                 :            :                 /* select automatically between only open, shared, leap */
     345                 :          0 :                 switch (wdev->conn->params.auth_type) {
     346                 :            :                 case NL80211_AUTHTYPE_OPEN_SYSTEM:
     347                 :          0 :                         if (wdev->connect_keys)
     348                 :          0 :                                 wdev->conn->params.auth_type =
     349                 :            :                                         NL80211_AUTHTYPE_SHARED_KEY;
     350                 :            :                         else
     351                 :          0 :                                 wdev->conn->params.auth_type =
     352                 :            :                                         NL80211_AUTHTYPE_NETWORK_EAP;
     353                 :            :                         break;
     354                 :            :                 case NL80211_AUTHTYPE_SHARED_KEY:
     355                 :          0 :                         wdev->conn->params.auth_type =
     356                 :            :                                 NL80211_AUTHTYPE_NETWORK_EAP;
     357                 :          0 :                         break;
     358                 :            :                 default:
     359                 :            :                         /* huh? */
     360                 :          0 :                         wdev->conn->params.auth_type =
     361                 :            :                                 NL80211_AUTHTYPE_OPEN_SYSTEM;
     362                 :          0 :                         break;
     363                 :            :                 }
     364                 :          0 :                 wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
     365                 :          0 :                 schedule_work(&rdev->conn_work);
     366                 :          0 :         } else if (status_code != WLAN_STATUS_SUCCESS) {
     367                 :            :                 struct cfg80211_connect_resp_params cr;
     368                 :            : 
     369                 :          0 :                 memset(&cr, 0, sizeof(cr));
     370                 :          0 :                 cr.status = status_code;
     371                 :          0 :                 cr.bssid = mgmt->bssid;
     372                 :            :                 cr.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED;
     373                 :          0 :                 __cfg80211_connect_result(wdev->netdev, &cr, false);
     374                 :          0 :         } else if (wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
     375                 :          0 :                 wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
     376                 :          0 :                 schedule_work(&rdev->conn_work);
     377                 :            :         }
     378                 :            : }
     379                 :            : 
     380                 :          0 : bool cfg80211_sme_rx_assoc_resp(struct wireless_dev *wdev, u16 status)
     381                 :            : {
     382                 :          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
     383                 :            : 
     384                 :          0 :         if (!wdev->conn)
     385                 :            :                 return false;
     386                 :            : 
     387                 :          0 :         if (status == WLAN_STATUS_SUCCESS) {
     388                 :          0 :                 wdev->conn->state = CFG80211_CONN_CONNECTED;
     389                 :          0 :                 return false;
     390                 :            :         }
     391                 :            : 
     392                 :          0 :         if (wdev->conn->prev_bssid_valid) {
     393                 :            :                 /*
     394                 :            :                  * Some stupid APs don't accept reassoc, so we
     395                 :            :                  * need to fall back to trying regular assoc;
     396                 :            :                  * return true so no event is sent to userspace.
     397                 :            :                  */
     398                 :          0 :                 wdev->conn->prev_bssid_valid = false;
     399                 :          0 :                 wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
     400                 :          0 :                 schedule_work(&rdev->conn_work);
     401                 :          0 :                 return true;
     402                 :            :         }
     403                 :            : 
     404                 :          0 :         wdev->conn->state = CFG80211_CONN_ASSOC_FAILED;
     405                 :          0 :         schedule_work(&rdev->conn_work);
     406                 :          0 :         return false;
     407                 :            : }
     408                 :            : 
     409                 :          0 : void cfg80211_sme_deauth(struct wireless_dev *wdev)
     410                 :            : {
     411                 :          0 :         cfg80211_sme_free(wdev);
     412                 :          0 : }
     413                 :            : 
     414                 :          0 : void cfg80211_sme_auth_timeout(struct wireless_dev *wdev)
     415                 :            : {
     416                 :          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
     417                 :            : 
     418                 :          0 :         if (!wdev->conn)
     419                 :          0 :                 return;
     420                 :            : 
     421                 :          0 :         wdev->conn->state = CFG80211_CONN_AUTH_FAILED_TIMEOUT;
     422                 :          0 :         schedule_work(&rdev->conn_work);
     423                 :            : }
     424                 :            : 
     425                 :          0 : void cfg80211_sme_disassoc(struct wireless_dev *wdev)
     426                 :            : {
     427                 :          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
     428                 :            : 
     429                 :          0 :         if (!wdev->conn)
     430                 :          0 :                 return;
     431                 :            : 
     432                 :          0 :         wdev->conn->state = CFG80211_CONN_DEAUTH;
     433                 :          0 :         schedule_work(&rdev->conn_work);
     434                 :            : }
     435                 :            : 
     436                 :          0 : void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev)
     437                 :            : {
     438                 :          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
     439                 :            : 
     440                 :          0 :         if (!wdev->conn)
     441                 :          0 :                 return;
     442                 :            : 
     443                 :          0 :         wdev->conn->state = CFG80211_CONN_ASSOC_FAILED_TIMEOUT;
     444                 :          0 :         schedule_work(&rdev->conn_work);
     445                 :            : }
     446                 :            : 
     447                 :          0 : void cfg80211_sme_abandon_assoc(struct wireless_dev *wdev)
     448                 :            : {
     449                 :          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
     450                 :            : 
     451                 :          0 :         if (!wdev->conn)
     452                 :          0 :                 return;
     453                 :            : 
     454                 :          0 :         wdev->conn->state = CFG80211_CONN_ABANDON;
     455                 :          0 :         schedule_work(&rdev->conn_work);
     456                 :            : }
     457                 :            : 
     458                 :          0 : static int cfg80211_sme_get_conn_ies(struct wireless_dev *wdev,
     459                 :            :                                      const u8 *ies, size_t ies_len,
     460                 :            :                                      const u8 **out_ies, size_t *out_ies_len)
     461                 :            : {
     462                 :          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
     463                 :            :         u8 *buf;
     464                 :            :         size_t offs;
     465                 :            : 
     466                 :          0 :         if (!rdev->wiphy.extended_capabilities_len ||
     467                 :          0 :             (ies && cfg80211_find_ie(WLAN_EID_EXT_CAPABILITY, ies, ies_len))) {
     468                 :          0 :                 *out_ies = kmemdup(ies, ies_len, GFP_KERNEL);
     469                 :          0 :                 if (!*out_ies)
     470                 :            :                         return -ENOMEM;
     471                 :          0 :                 *out_ies_len = ies_len;
     472                 :          0 :                 return 0;
     473                 :            :         }
     474                 :            : 
     475                 :          0 :         buf = kmalloc(ies_len + rdev->wiphy.extended_capabilities_len + 2,
     476                 :            :                       GFP_KERNEL);
     477                 :          0 :         if (!buf)
     478                 :            :                 return -ENOMEM;
     479                 :            : 
     480                 :          0 :         if (ies_len) {
     481                 :            :                 static const u8 before_extcapa[] = {
     482                 :            :                         /* not listing IEs expected to be created by driver */
     483                 :            :                         WLAN_EID_RSN,
     484                 :            :                         WLAN_EID_QOS_CAPA,
     485                 :            :                         WLAN_EID_RRM_ENABLED_CAPABILITIES,
     486                 :            :                         WLAN_EID_MOBILITY_DOMAIN,
     487                 :            :                         WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
     488                 :            :                         WLAN_EID_BSS_COEX_2040,
     489                 :            :                 };
     490                 :            : 
     491                 :            :                 offs = ieee80211_ie_split(ies, ies_len, before_extcapa,
     492                 :            :                                           ARRAY_SIZE(before_extcapa), 0);
     493                 :          0 :                 memcpy(buf, ies, offs);
     494                 :            :                 /* leave a whole for extended capabilities IE */
     495                 :          0 :                 memcpy(buf + offs + rdev->wiphy.extended_capabilities_len + 2,
     496                 :            :                        ies + offs, ies_len - offs);
     497                 :            :         } else {
     498                 :            :                 offs = 0;
     499                 :            :         }
     500                 :            : 
     501                 :            :         /* place extended capabilities IE (with only driver capabilities) */
     502                 :          0 :         buf[offs] = WLAN_EID_EXT_CAPABILITY;
     503                 :          0 :         buf[offs + 1] = rdev->wiphy.extended_capabilities_len;
     504                 :          0 :         memcpy(buf + offs + 2,
     505                 :          0 :                rdev->wiphy.extended_capabilities,
     506                 :          0 :                rdev->wiphy.extended_capabilities_len);
     507                 :            : 
     508                 :          0 :         *out_ies = buf;
     509                 :          0 :         *out_ies_len = ies_len + rdev->wiphy.extended_capabilities_len + 2;
     510                 :            : 
     511                 :          0 :         return 0;
     512                 :            : }
     513                 :            : 
     514                 :          0 : static int cfg80211_sme_connect(struct wireless_dev *wdev,
     515                 :            :                                 struct cfg80211_connect_params *connect,
     516                 :            :                                 const u8 *prev_bssid)
     517                 :            : {
     518                 :          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
     519                 :            :         struct cfg80211_bss *bss;
     520                 :            :         int err;
     521                 :            : 
     522                 :          0 :         if (!rdev->ops->auth || !rdev->ops->assoc)
     523                 :            :                 return -EOPNOTSUPP;
     524                 :            : 
     525                 :          0 :         if (wdev->current_bss) {
     526                 :          0 :                 cfg80211_unhold_bss(wdev->current_bss);
     527                 :          0 :                 cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
     528                 :          0 :                 wdev->current_bss = NULL;
     529                 :            : 
     530                 :          0 :                 cfg80211_sme_free(wdev);
     531                 :            :         }
     532                 :            : 
     533                 :          0 :         if (WARN_ON(wdev->conn))
     534                 :            :                 return -EINPROGRESS;
     535                 :            : 
     536                 :          0 :         wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL);
     537                 :          0 :         if (!wdev->conn)
     538                 :            :                 return -ENOMEM;
     539                 :            : 
     540                 :            :         /*
     541                 :            :          * Copy all parameters, and treat explicitly IEs, BSSID, SSID.
     542                 :            :          */
     543                 :          0 :         memcpy(&wdev->conn->params, connect, sizeof(*connect));
     544                 :          0 :         if (connect->bssid) {
     545                 :          0 :                 wdev->conn->params.bssid = wdev->conn->bssid;
     546                 :          0 :                 memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN);
     547                 :            :         }
     548                 :            : 
     549                 :          0 :         if (cfg80211_sme_get_conn_ies(wdev, connect->ie, connect->ie_len,
     550                 :          0 :                                       &wdev->conn->ie,
     551                 :            :                                       &wdev->conn->params.ie_len)) {
     552                 :          0 :                 kfree(wdev->conn);
     553                 :          0 :                 wdev->conn = NULL;
     554                 :          0 :                 return -ENOMEM;
     555                 :            :         }
     556                 :          0 :         wdev->conn->params.ie = wdev->conn->ie;
     557                 :            : 
     558                 :          0 :         if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
     559                 :          0 :                 wdev->conn->auto_auth = true;
     560                 :            :                 /* start with open system ... should mostly work */
     561                 :          0 :                 wdev->conn->params.auth_type =
     562                 :            :                         NL80211_AUTHTYPE_OPEN_SYSTEM;
     563                 :            :         } else {
     564                 :          0 :                 wdev->conn->auto_auth = false;
     565                 :            :         }
     566                 :            : 
     567                 :          0 :         wdev->conn->params.ssid = wdev->ssid;
     568                 :          0 :         wdev->conn->params.ssid_len = wdev->ssid_len;
     569                 :            : 
     570                 :            :         /* see if we have the bss already */
     571                 :          0 :         bss = cfg80211_get_conn_bss(wdev);
     572                 :            : 
     573                 :          0 :         if (prev_bssid) {
     574                 :          0 :                 memcpy(wdev->conn->prev_bssid, prev_bssid, ETH_ALEN);
     575                 :          0 :                 wdev->conn->prev_bssid_valid = true;
     576                 :            :         }
     577                 :            : 
     578                 :            :         /* we're good if we have a matching bss struct */
     579                 :          0 :         if (bss) {
     580                 :            :                 enum nl80211_timeout_reason treason;
     581                 :            : 
     582                 :          0 :                 err = cfg80211_conn_do_work(wdev, &treason);
     583                 :          0 :                 cfg80211_put_bss(wdev->wiphy, bss);
     584                 :            :         } else {
     585                 :            :                 /* otherwise we'll need to scan for the AP first */
     586                 :          0 :                 err = cfg80211_conn_scan(wdev);
     587                 :            : 
     588                 :            :                 /*
     589                 :            :                  * If we can't scan right now, then we need to scan again
     590                 :            :                  * after the current scan finished, since the parameters
     591                 :            :                  * changed (unless we find a good AP anyway).
     592                 :            :                  */
     593                 :          0 :                 if (err == -EBUSY) {
     594                 :            :                         err = 0;
     595                 :          0 :                         wdev->conn->state = CFG80211_CONN_SCAN_AGAIN;
     596                 :            :                 }
     597                 :            :         }
     598                 :            : 
     599                 :          0 :         if (err)
     600                 :          0 :                 cfg80211_sme_free(wdev);
     601                 :            : 
     602                 :          0 :         return err;
     603                 :            : }
     604                 :            : 
     605                 :          0 : static int cfg80211_sme_disconnect(struct wireless_dev *wdev, u16 reason)
     606                 :            : {
     607                 :          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
     608                 :            :         int err;
     609                 :            : 
     610                 :          0 :         if (!wdev->conn)
     611                 :            :                 return 0;
     612                 :            : 
     613                 :          0 :         if (!rdev->ops->deauth)
     614                 :            :                 return -EOPNOTSUPP;
     615                 :            : 
     616                 :          0 :         if (wdev->conn->state == CFG80211_CONN_SCANNING ||
     617                 :            :             wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) {
     618                 :            :                 err = 0;
     619                 :            :                 goto out;
     620                 :            :         }
     621                 :            : 
     622                 :            :         /* wdev->conn->params.bssid must be set if > SCANNING */
     623                 :          0 :         err = cfg80211_mlme_deauth(rdev, wdev->netdev,
     624                 :            :                                    wdev->conn->params.bssid,
     625                 :            :                                    NULL, 0, reason, false);
     626                 :            :  out:
     627                 :          0 :         cfg80211_sme_free(wdev);
     628                 :          0 :         return err;
     629                 :            : }
     630                 :            : 
     631                 :            : /*
     632                 :            :  * code shared for in-device and software SME
     633                 :            :  */
     634                 :            : 
     635                 :          0 : static bool cfg80211_is_all_idle(void)
     636                 :            : {
     637                 :            :         struct cfg80211_registered_device *rdev;
     638                 :            :         struct wireless_dev *wdev;
     639                 :            :         bool is_all_idle = true;
     640                 :            : 
     641                 :            :         /*
     642                 :            :          * All devices must be idle as otherwise if you are actively
     643                 :            :          * scanning some new beacon hints could be learned and would
     644                 :            :          * count as new regulatory hints.
     645                 :            :          * Also if there is any other active beaconing interface we
     646                 :            :          * need not issue a disconnect hint and reset any info such
     647                 :            :          * as chan dfs state, etc.
     648                 :            :          */
     649                 :          0 :         list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
     650                 :          0 :                 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
     651                 :            :                         wdev_lock(wdev);
     652                 :          0 :                         if (wdev->conn || wdev->current_bss ||
     653                 :          0 :                             cfg80211_beaconing_iface_active(wdev))
     654                 :            :                                 is_all_idle = false;
     655                 :            :                         wdev_unlock(wdev);
     656                 :            :                 }
     657                 :            :         }
     658                 :            : 
     659                 :          0 :         return is_all_idle;
     660                 :            : }
     661                 :            : 
     662                 :          0 : static void disconnect_work(struct work_struct *work)
     663                 :            : {
     664                 :          0 :         rtnl_lock();
     665                 :          0 :         if (cfg80211_is_all_idle())
     666                 :          0 :                 regulatory_hint_disconnect();
     667                 :          0 :         rtnl_unlock();
     668                 :          0 : }
     669                 :            : 
     670                 :            : DECLARE_WORK(cfg80211_disconnect_work, disconnect_work);
     671                 :            : 
     672                 :            : 
     673                 :            : /*
     674                 :            :  * API calls for drivers implementing connect/disconnect and
     675                 :            :  * SME event handling
     676                 :            :  */
     677                 :            : 
     678                 :            : /* This method must consume bss one way or another */
     679                 :          0 : void __cfg80211_connect_result(struct net_device *dev,
     680                 :            :                                struct cfg80211_connect_resp_params *cr,
     681                 :            :                                bool wextev)
     682                 :            : {
     683                 :          0 :         struct wireless_dev *wdev = dev->ieee80211_ptr;
     684                 :            :         const u8 *country_ie;
     685                 :            : #ifdef CONFIG_CFG80211_WEXT
     686                 :            :         union iwreq_data wrqu;
     687                 :            : #endif
     688                 :            : 
     689                 :            :         ASSERT_WDEV_LOCK(wdev);
     690                 :            : 
     691                 :          0 :         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
     692                 :            :                     wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) {
     693                 :          0 :                 cfg80211_put_bss(wdev->wiphy, cr->bss);
     694                 :          0 :                 return;
     695                 :            :         }
     696                 :            : 
     697                 :          0 :         nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev, cr,
     698                 :            :                                     GFP_KERNEL);
     699                 :            : 
     700                 :            : #ifdef CONFIG_CFG80211_WEXT
     701                 :          0 :         if (wextev) {
     702                 :          0 :                 if (cr->req_ie && cr->status == WLAN_STATUS_SUCCESS) {
     703                 :          0 :                         memset(&wrqu, 0, sizeof(wrqu));
     704                 :          0 :                         wrqu.data.length = cr->req_ie_len;
     705                 :          0 :                         wireless_send_event(dev, IWEVASSOCREQIE, &wrqu,
     706                 :            :                                             cr->req_ie);
     707                 :            :                 }
     708                 :            : 
     709                 :          0 :                 if (cr->resp_ie && cr->status == WLAN_STATUS_SUCCESS) {
     710                 :          0 :                         memset(&wrqu, 0, sizeof(wrqu));
     711                 :          0 :                         wrqu.data.length = cr->resp_ie_len;
     712                 :          0 :                         wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu,
     713                 :            :                                             cr->resp_ie);
     714                 :            :                 }
     715                 :            : 
     716                 :          0 :                 memset(&wrqu, 0, sizeof(wrqu));
     717                 :          0 :                 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
     718                 :          0 :                 if (cr->bssid && cr->status == WLAN_STATUS_SUCCESS) {
     719                 :          0 :                         memcpy(wrqu.ap_addr.sa_data, cr->bssid, ETH_ALEN);
     720                 :          0 :                         memcpy(wdev->wext.prev_bssid, cr->bssid, ETH_ALEN);
     721                 :          0 :                         wdev->wext.prev_bssid_valid = true;
     722                 :            :                 }
     723                 :          0 :                 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
     724                 :            :         }
     725                 :            : #endif
     726                 :            : 
     727                 :          0 :         if (!cr->bss && (cr->status == WLAN_STATUS_SUCCESS)) {
     728                 :          0 :                 WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect);
     729                 :          0 :                 cr->bss = cfg80211_get_bss(wdev->wiphy, NULL, cr->bssid,
     730                 :          0 :                                            wdev->ssid, wdev->ssid_len,
     731                 :            :                                            wdev->conn_bss_type,
     732                 :            :                                            IEEE80211_PRIVACY_ANY);
     733                 :          0 :                 if (cr->bss)
     734                 :          0 :                         cfg80211_hold_bss(bss_from_pub(cr->bss));
     735                 :            :         }
     736                 :            : 
     737                 :          0 :         if (wdev->current_bss) {
     738                 :          0 :                 cfg80211_unhold_bss(wdev->current_bss);
     739                 :          0 :                 cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
     740                 :          0 :                 wdev->current_bss = NULL;
     741                 :            :         }
     742                 :            : 
     743                 :          0 :         if (cr->status != WLAN_STATUS_SUCCESS) {
     744                 :          0 :                 kzfree(wdev->connect_keys);
     745                 :          0 :                 wdev->connect_keys = NULL;
     746                 :          0 :                 wdev->ssid_len = 0;
     747                 :          0 :                 wdev->conn_owner_nlportid = 0;
     748                 :          0 :                 if (cr->bss) {
     749                 :          0 :                         cfg80211_unhold_bss(bss_from_pub(cr->bss));
     750                 :          0 :                         cfg80211_put_bss(wdev->wiphy, cr->bss);
     751                 :            :                 }
     752                 :          0 :                 cfg80211_sme_free(wdev);
     753                 :          0 :                 return;
     754                 :            :         }
     755                 :            : 
     756                 :          0 :         if (WARN_ON(!cr->bss))
     757                 :            :                 return;
     758                 :            : 
     759                 :          0 :         wdev->current_bss = bss_from_pub(cr->bss);
     760                 :            : 
     761                 :          0 :         if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP))
     762                 :          0 :                 cfg80211_upload_connect_keys(wdev);
     763                 :            : 
     764                 :            :         rcu_read_lock();
     765                 :          0 :         country_ie = ieee80211_bss_get_ie(cr->bss, WLAN_EID_COUNTRY);
     766                 :          0 :         if (!country_ie) {
     767                 :            :                 rcu_read_unlock();
     768                 :            :                 return;
     769                 :            :         }
     770                 :            : 
     771                 :          0 :         country_ie = kmemdup(country_ie, 2 + country_ie[1], GFP_ATOMIC);
     772                 :            :         rcu_read_unlock();
     773                 :            : 
     774                 :          0 :         if (!country_ie)
     775                 :            :                 return;
     776                 :            : 
     777                 :            :         /*
     778                 :            :          * ieee80211_bss_get_ie() ensures we can access:
     779                 :            :          * - country_ie + 2, the start of the country ie data, and
     780                 :            :          * - and country_ie[1] which is the IE length
     781                 :            :          */
     782                 :          0 :         regulatory_hint_country_ie(wdev->wiphy, cr->bss->channel->band,
     783                 :            :                                    country_ie + 2, country_ie[1]);
     784                 :          0 :         kfree(country_ie);
     785                 :            : }
     786                 :            : 
     787                 :            : /* Consumes bss object one way or another */
     788                 :          0 : void cfg80211_connect_done(struct net_device *dev,
     789                 :            :                            struct cfg80211_connect_resp_params *params,
     790                 :            :                            gfp_t gfp)
     791                 :            : {
     792                 :          0 :         struct wireless_dev *wdev = dev->ieee80211_ptr;
     793                 :          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
     794                 :            :         struct cfg80211_event *ev;
     795                 :            :         unsigned long flags;
     796                 :            :         u8 *next;
     797                 :            : 
     798                 :          0 :         if (params->bss) {
     799                 :            :                 struct cfg80211_internal_bss *ibss = bss_from_pub(params->bss);
     800                 :            : 
     801                 :          0 :                 if (list_empty(&ibss->list)) {
     802                 :            :                         struct cfg80211_bss *found = NULL, *tmp = params->bss;
     803                 :            : 
     804                 :          0 :                         found = cfg80211_get_bss(wdev->wiphy, NULL,
     805                 :          0 :                                                  params->bss->bssid,
     806                 :          0 :                                                  wdev->ssid, wdev->ssid_len,
     807                 :            :                                                  wdev->conn_bss_type,
     808                 :            :                                                  IEEE80211_PRIVACY_ANY);
     809                 :          0 :                         if (found) {
     810                 :            :                                 /* The same BSS is already updated so use it
     811                 :            :                                  * instead, as it has latest info.
     812                 :            :                                  */
     813                 :          0 :                                 params->bss = found;
     814                 :            :                         } else {
     815                 :            :                                 /* Update with BSS provided by driver, it will
     816                 :            :                                  * be freshly added and ref cnted, we can free
     817                 :            :                                  * the old one.
     818                 :            :                                  *
     819                 :            :                                  * signal_valid can be false, as we are not
     820                 :            :                                  * expecting the BSS to be found.
     821                 :            :                                  *
     822                 :            :                                  * keep the old timestamp to avoid confusion
     823                 :            :                                  */
     824                 :          0 :                                 cfg80211_bss_update(rdev, ibss, false,
     825                 :            :                                                     ibss->ts);
     826                 :            :                         }
     827                 :            : 
     828                 :          0 :                         cfg80211_put_bss(wdev->wiphy, tmp);
     829                 :            :                 }
     830                 :            :         }
     831                 :            : 
     832                 :          0 :         ev = kzalloc(sizeof(*ev) + (params->bssid ? ETH_ALEN : 0) +
     833                 :          0 :                      params->req_ie_len + params->resp_ie_len +
     834                 :          0 :                      params->fils.kek_len + params->fils.pmk_len +
     835                 :          0 :                      (params->fils.pmkid ? WLAN_PMKID_LEN : 0), gfp);
     836                 :          0 :         if (!ev) {
     837                 :          0 :                 cfg80211_put_bss(wdev->wiphy, params->bss);
     838                 :          0 :                 return;
     839                 :            :         }
     840                 :            : 
     841                 :          0 :         ev->type = EVENT_CONNECT_RESULT;
     842                 :          0 :         next = ((u8 *)ev) + sizeof(*ev);
     843                 :          0 :         if (params->bssid) {
     844                 :          0 :                 ev->cr.bssid = next;
     845                 :          0 :                 memcpy((void *)ev->cr.bssid, params->bssid, ETH_ALEN);
     846                 :          0 :                 next += ETH_ALEN;
     847                 :            :         }
     848                 :          0 :         if (params->req_ie_len) {
     849                 :          0 :                 ev->cr.req_ie = next;
     850                 :          0 :                 ev->cr.req_ie_len = params->req_ie_len;
     851                 :          0 :                 memcpy((void *)ev->cr.req_ie, params->req_ie,
     852                 :            :                        params->req_ie_len);
     853                 :          0 :                 next += params->req_ie_len;
     854                 :            :         }
     855                 :          0 :         if (params->resp_ie_len) {
     856                 :          0 :                 ev->cr.resp_ie = next;
     857                 :          0 :                 ev->cr.resp_ie_len = params->resp_ie_len;
     858                 :          0 :                 memcpy((void *)ev->cr.resp_ie, params->resp_ie,
     859                 :            :                        params->resp_ie_len);
     860                 :          0 :                 next += params->resp_ie_len;
     861                 :            :         }
     862                 :          0 :         if (params->fils.kek_len) {
     863                 :          0 :                 ev->cr.fils.kek = next;
     864                 :          0 :                 ev->cr.fils.kek_len = params->fils.kek_len;
     865                 :          0 :                 memcpy((void *)ev->cr.fils.kek, params->fils.kek,
     866                 :            :                        params->fils.kek_len);
     867                 :          0 :                 next += params->fils.kek_len;
     868                 :            :         }
     869                 :          0 :         if (params->fils.pmk_len) {
     870                 :          0 :                 ev->cr.fils.pmk = next;
     871                 :          0 :                 ev->cr.fils.pmk_len = params->fils.pmk_len;
     872                 :          0 :                 memcpy((void *)ev->cr.fils.pmk, params->fils.pmk,
     873                 :            :                        params->fils.pmk_len);
     874                 :          0 :                 next += params->fils.pmk_len;
     875                 :            :         }
     876                 :          0 :         if (params->fils.pmkid) {
     877                 :          0 :                 ev->cr.fils.pmkid = next;
     878                 :          0 :                 memcpy((void *)ev->cr.fils.pmkid, params->fils.pmkid,
     879                 :            :                        WLAN_PMKID_LEN);
     880                 :            :                 next += WLAN_PMKID_LEN;
     881                 :            :         }
     882                 :          0 :         ev->cr.fils.update_erp_next_seq_num = params->fils.update_erp_next_seq_num;
     883                 :          0 :         if (params->fils.update_erp_next_seq_num)
     884                 :          0 :                 ev->cr.fils.erp_next_seq_num = params->fils.erp_next_seq_num;
     885                 :          0 :         if (params->bss)
     886                 :          0 :                 cfg80211_hold_bss(bss_from_pub(params->bss));
     887                 :          0 :         ev->cr.bss = params->bss;
     888                 :          0 :         ev->cr.status = params->status;
     889                 :          0 :         ev->cr.timeout_reason = params->timeout_reason;
     890                 :            : 
     891                 :          0 :         spin_lock_irqsave(&wdev->event_lock, flags);
     892                 :          0 :         list_add_tail(&ev->list, &wdev->event_list);
     893                 :            :         spin_unlock_irqrestore(&wdev->event_lock, flags);
     894                 :          0 :         queue_work(cfg80211_wq, &rdev->event_work);
     895                 :            : }
     896                 :            : EXPORT_SYMBOL(cfg80211_connect_done);
     897                 :            : 
     898                 :            : /* Consumes bss object one way or another */
     899                 :          0 : void __cfg80211_roamed(struct wireless_dev *wdev,
     900                 :            :                        struct cfg80211_roam_info *info)
     901                 :            : {
     902                 :            : #ifdef CONFIG_CFG80211_WEXT
     903                 :            :         union iwreq_data wrqu;
     904                 :            : #endif
     905                 :            :         ASSERT_WDEV_LOCK(wdev);
     906                 :            : 
     907                 :          0 :         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
     908                 :            :                     wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
     909                 :            :                 goto out;
     910                 :            : 
     911                 :          0 :         if (WARN_ON(!wdev->current_bss))
     912                 :            :                 goto out;
     913                 :            : 
     914                 :          0 :         cfg80211_unhold_bss(wdev->current_bss);
     915                 :          0 :         cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
     916                 :          0 :         wdev->current_bss = NULL;
     917                 :            : 
     918                 :          0 :         if (WARN_ON(!info->bss))
     919                 :          0 :                 return;
     920                 :            : 
     921                 :          0 :         cfg80211_hold_bss(bss_from_pub(info->bss));
     922                 :          0 :         wdev->current_bss = bss_from_pub(info->bss);
     923                 :            : 
     924                 :          0 :         nl80211_send_roamed(wiphy_to_rdev(wdev->wiphy),
     925                 :            :                             wdev->netdev, info, GFP_KERNEL);
     926                 :            : 
     927                 :            : #ifdef CONFIG_CFG80211_WEXT
     928                 :          0 :         if (info->req_ie) {
     929                 :          0 :                 memset(&wrqu, 0, sizeof(wrqu));
     930                 :          0 :                 wrqu.data.length = info->req_ie_len;
     931                 :          0 :                 wireless_send_event(wdev->netdev, IWEVASSOCREQIE,
     932                 :            :                                     &wrqu, info->req_ie);
     933                 :            :         }
     934                 :            : 
     935                 :          0 :         if (info->resp_ie) {
     936                 :          0 :                 memset(&wrqu, 0, sizeof(wrqu));
     937                 :          0 :                 wrqu.data.length = info->resp_ie_len;
     938                 :          0 :                 wireless_send_event(wdev->netdev, IWEVASSOCRESPIE,
     939                 :            :                                     &wrqu, info->resp_ie);
     940                 :            :         }
     941                 :            : 
     942                 :          0 :         memset(&wrqu, 0, sizeof(wrqu));
     943                 :          0 :         wrqu.ap_addr.sa_family = ARPHRD_ETHER;
     944                 :          0 :         memcpy(wrqu.ap_addr.sa_data, info->bss->bssid, ETH_ALEN);
     945                 :          0 :         memcpy(wdev->wext.prev_bssid, info->bss->bssid, ETH_ALEN);
     946                 :          0 :         wdev->wext.prev_bssid_valid = true;
     947                 :          0 :         wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL);
     948                 :            : #endif
     949                 :            : 
     950                 :          0 :         return;
     951                 :            : out:
     952                 :          0 :         cfg80211_put_bss(wdev->wiphy, info->bss);
     953                 :            : }
     954                 :            : 
     955                 :            : /* Consumes info->bss object one way or another */
     956                 :          0 : void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info,
     957                 :            :                      gfp_t gfp)
     958                 :            : {
     959                 :          0 :         struct wireless_dev *wdev = dev->ieee80211_ptr;
     960                 :          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
     961                 :            :         struct cfg80211_event *ev;
     962                 :            :         unsigned long flags;
     963                 :            :         u8 *next;
     964                 :            : 
     965                 :          0 :         if (!info->bss) {
     966                 :          0 :                 info->bss = cfg80211_get_bss(wdev->wiphy, info->channel,
     967                 :          0 :                                              info->bssid, wdev->ssid,
     968                 :          0 :                                              wdev->ssid_len,
     969                 :            :                                              wdev->conn_bss_type,
     970                 :            :                                              IEEE80211_PRIVACY_ANY);
     971                 :            :         }
     972                 :            : 
     973                 :          0 :         if (WARN_ON(!info->bss))
     974                 :            :                 return;
     975                 :            : 
     976                 :          0 :         ev = kzalloc(sizeof(*ev) + info->req_ie_len + info->resp_ie_len +
     977                 :          0 :                      info->fils.kek_len + info->fils.pmk_len +
     978                 :          0 :                      (info->fils.pmkid ? WLAN_PMKID_LEN : 0), gfp);
     979                 :          0 :         if (!ev) {
     980                 :          0 :                 cfg80211_put_bss(wdev->wiphy, info->bss);
     981                 :          0 :                 return;
     982                 :            :         }
     983                 :            : 
     984                 :          0 :         ev->type = EVENT_ROAMED;
     985                 :          0 :         next = ((u8 *)ev) + sizeof(*ev);
     986                 :          0 :         if (info->req_ie_len) {
     987                 :          0 :                 ev->rm.req_ie = next;
     988                 :          0 :                 ev->rm.req_ie_len = info->req_ie_len;
     989                 :          0 :                 memcpy((void *)ev->rm.req_ie, info->req_ie, info->req_ie_len);
     990                 :          0 :                 next += info->req_ie_len;
     991                 :            :         }
     992                 :          0 :         if (info->resp_ie_len) {
     993                 :          0 :                 ev->rm.resp_ie = next;
     994                 :          0 :                 ev->rm.resp_ie_len = info->resp_ie_len;
     995                 :          0 :                 memcpy((void *)ev->rm.resp_ie, info->resp_ie,
     996                 :            :                        info->resp_ie_len);
     997                 :          0 :                 next += info->resp_ie_len;
     998                 :            :         }
     999                 :          0 :         if (info->fils.kek_len) {
    1000                 :          0 :                 ev->rm.fils.kek = next;
    1001                 :          0 :                 ev->rm.fils.kek_len = info->fils.kek_len;
    1002                 :          0 :                 memcpy((void *)ev->rm.fils.kek, info->fils.kek,
    1003                 :            :                        info->fils.kek_len);
    1004                 :          0 :                 next += info->fils.kek_len;
    1005                 :            :         }
    1006                 :          0 :         if (info->fils.pmk_len) {
    1007                 :          0 :                 ev->rm.fils.pmk = next;
    1008                 :          0 :                 ev->rm.fils.pmk_len = info->fils.pmk_len;
    1009                 :          0 :                 memcpy((void *)ev->rm.fils.pmk, info->fils.pmk,
    1010                 :            :                        info->fils.pmk_len);
    1011                 :          0 :                 next += info->fils.pmk_len;
    1012                 :            :         }
    1013                 :          0 :         if (info->fils.pmkid) {
    1014                 :          0 :                 ev->rm.fils.pmkid = next;
    1015                 :          0 :                 memcpy((void *)ev->rm.fils.pmkid, info->fils.pmkid,
    1016                 :            :                        WLAN_PMKID_LEN);
    1017                 :            :                 next += WLAN_PMKID_LEN;
    1018                 :            :         }
    1019                 :          0 :         ev->rm.fils.update_erp_next_seq_num = info->fils.update_erp_next_seq_num;
    1020                 :          0 :         if (info->fils.update_erp_next_seq_num)
    1021                 :          0 :                 ev->rm.fils.erp_next_seq_num = info->fils.erp_next_seq_num;
    1022                 :          0 :         ev->rm.bss = info->bss;
    1023                 :            : 
    1024                 :          0 :         spin_lock_irqsave(&wdev->event_lock, flags);
    1025                 :          0 :         list_add_tail(&ev->list, &wdev->event_list);
    1026                 :            :         spin_unlock_irqrestore(&wdev->event_lock, flags);
    1027                 :          0 :         queue_work(cfg80211_wq, &rdev->event_work);
    1028                 :            : }
    1029                 :            : EXPORT_SYMBOL(cfg80211_roamed);
    1030                 :            : 
    1031                 :          0 : void __cfg80211_port_authorized(struct wireless_dev *wdev, const u8 *bssid)
    1032                 :            : {
    1033                 :            :         ASSERT_WDEV_LOCK(wdev);
    1034                 :            : 
    1035                 :          0 :         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
    1036                 :            :                 return;
    1037                 :            : 
    1038                 :          0 :         if (WARN_ON(!wdev->current_bss) ||
    1039                 :          0 :             WARN_ON(!ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
    1040                 :            :                 return;
    1041                 :            : 
    1042                 :          0 :         nl80211_send_port_authorized(wiphy_to_rdev(wdev->wiphy), wdev->netdev,
    1043                 :            :                                      bssid);
    1044                 :            : }
    1045                 :            : 
    1046                 :          0 : void cfg80211_port_authorized(struct net_device *dev, const u8 *bssid,
    1047                 :            :                               gfp_t gfp)
    1048                 :            : {
    1049                 :          0 :         struct wireless_dev *wdev = dev->ieee80211_ptr;
    1050                 :          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
    1051                 :            :         struct cfg80211_event *ev;
    1052                 :            :         unsigned long flags;
    1053                 :            : 
    1054                 :          0 :         if (WARN_ON(!bssid))
    1055                 :            :                 return;
    1056                 :            : 
    1057                 :          0 :         ev = kzalloc(sizeof(*ev), gfp);
    1058                 :          0 :         if (!ev)
    1059                 :            :                 return;
    1060                 :            : 
    1061                 :          0 :         ev->type = EVENT_PORT_AUTHORIZED;
    1062                 :          0 :         memcpy(ev->pa.bssid, bssid, ETH_ALEN);
    1063                 :            : 
    1064                 :            :         /*
    1065                 :            :          * Use the wdev event list so that if there are pending
    1066                 :            :          * connected/roamed events, they will be reported first.
    1067                 :            :          */
    1068                 :          0 :         spin_lock_irqsave(&wdev->event_lock, flags);
    1069                 :          0 :         list_add_tail(&ev->list, &wdev->event_list);
    1070                 :            :         spin_unlock_irqrestore(&wdev->event_lock, flags);
    1071                 :          0 :         queue_work(cfg80211_wq, &rdev->event_work);
    1072                 :            : }
    1073                 :            : EXPORT_SYMBOL(cfg80211_port_authorized);
    1074                 :            : 
    1075                 :          0 : void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
    1076                 :            :                              size_t ie_len, u16 reason, bool from_ap)
    1077                 :            : {
    1078                 :          0 :         struct wireless_dev *wdev = dev->ieee80211_ptr;
    1079                 :          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
    1080                 :            :         int i;
    1081                 :            : #ifdef CONFIG_CFG80211_WEXT
    1082                 :            :         union iwreq_data wrqu;
    1083                 :            : #endif
    1084                 :            : 
    1085                 :            :         ASSERT_WDEV_LOCK(wdev);
    1086                 :            : 
    1087                 :          0 :         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
    1088                 :            :                     wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
    1089                 :          0 :                 return;
    1090                 :            : 
    1091                 :          0 :         if (wdev->current_bss) {
    1092                 :          0 :                 cfg80211_unhold_bss(wdev->current_bss);
    1093                 :          0 :                 cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
    1094                 :            :         }
    1095                 :            : 
    1096                 :          0 :         wdev->current_bss = NULL;
    1097                 :          0 :         wdev->ssid_len = 0;
    1098                 :          0 :         wdev->conn_owner_nlportid = 0;
    1099                 :          0 :         kzfree(wdev->connect_keys);
    1100                 :          0 :         wdev->connect_keys = NULL;
    1101                 :            : 
    1102                 :          0 :         nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
    1103                 :            : 
    1104                 :            :         /* stop critical protocol if supported */
    1105                 :          0 :         if (rdev->ops->crit_proto_stop && rdev->crit_proto_nlportid) {
    1106                 :          0 :                 rdev->crit_proto_nlportid = 0;
    1107                 :          0 :                 rdev_crit_proto_stop(rdev, wdev);
    1108                 :            :         }
    1109                 :            : 
    1110                 :            :         /*
    1111                 :            :          * Delete all the keys ... pairwise keys can't really
    1112                 :            :          * exist any more anyway, but default keys might.
    1113                 :            :          */
    1114                 :          0 :         if (rdev->ops->del_key)
    1115                 :          0 :                 for (i = 0; i < 6; i++)
    1116                 :          0 :                         rdev_del_key(rdev, dev, i, false, NULL);
    1117                 :            : 
    1118                 :          0 :         rdev_set_qos_map(rdev, dev, NULL);
    1119                 :            : 
    1120                 :            : #ifdef CONFIG_CFG80211_WEXT
    1121                 :          0 :         memset(&wrqu, 0, sizeof(wrqu));
    1122                 :          0 :         wrqu.ap_addr.sa_family = ARPHRD_ETHER;
    1123                 :          0 :         wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
    1124                 :          0 :         wdev->wext.connect.ssid_len = 0;
    1125                 :            : #endif
    1126                 :            : 
    1127                 :            :         schedule_work(&cfg80211_disconnect_work);
    1128                 :            : }
    1129                 :            : 
    1130                 :          0 : void cfg80211_disconnected(struct net_device *dev, u16 reason,
    1131                 :            :                            const u8 *ie, size_t ie_len,
    1132                 :            :                            bool locally_generated, gfp_t gfp)
    1133                 :            : {
    1134                 :          0 :         struct wireless_dev *wdev = dev->ieee80211_ptr;
    1135                 :          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
    1136                 :            :         struct cfg80211_event *ev;
    1137                 :            :         unsigned long flags;
    1138                 :            : 
    1139                 :          0 :         ev = kzalloc(sizeof(*ev) + ie_len, gfp);
    1140                 :          0 :         if (!ev)
    1141                 :          0 :                 return;
    1142                 :            : 
    1143                 :          0 :         ev->type = EVENT_DISCONNECTED;
    1144                 :          0 :         ev->dc.ie = ((u8 *)ev) + sizeof(*ev);
    1145                 :          0 :         ev->dc.ie_len = ie_len;
    1146                 :          0 :         memcpy((void *)ev->dc.ie, ie, ie_len);
    1147                 :          0 :         ev->dc.reason = reason;
    1148                 :          0 :         ev->dc.locally_generated = locally_generated;
    1149                 :            : 
    1150                 :          0 :         spin_lock_irqsave(&wdev->event_lock, flags);
    1151                 :          0 :         list_add_tail(&ev->list, &wdev->event_list);
    1152                 :            :         spin_unlock_irqrestore(&wdev->event_lock, flags);
    1153                 :          0 :         queue_work(cfg80211_wq, &rdev->event_work);
    1154                 :            : }
    1155                 :            : EXPORT_SYMBOL(cfg80211_disconnected);
    1156                 :            : 
    1157                 :            : /*
    1158                 :            :  * API calls for nl80211/wext compatibility code
    1159                 :            :  */
    1160                 :          0 : int cfg80211_connect(struct cfg80211_registered_device *rdev,
    1161                 :            :                      struct net_device *dev,
    1162                 :            :                      struct cfg80211_connect_params *connect,
    1163                 :            :                      struct cfg80211_cached_keys *connkeys,
    1164                 :            :                      const u8 *prev_bssid)
    1165                 :            : {
    1166                 :          0 :         struct wireless_dev *wdev = dev->ieee80211_ptr;
    1167                 :            :         int err;
    1168                 :            : 
    1169                 :            :         ASSERT_WDEV_LOCK(wdev);
    1170                 :            : 
    1171                 :            :         /*
    1172                 :            :          * If we have an ssid_len, we're trying to connect or are
    1173                 :            :          * already connected, so reject a new SSID unless it's the
    1174                 :            :          * same (which is the case for re-association.)
    1175                 :            :          */
    1176                 :          0 :         if (wdev->ssid_len &&
    1177                 :          0 :             (wdev->ssid_len != connect->ssid_len ||
    1178                 :          0 :              memcmp(wdev->ssid, connect->ssid, wdev->ssid_len)))
    1179                 :            :                 return -EALREADY;
    1180                 :            : 
    1181                 :            :         /*
    1182                 :            :          * If connected, reject (re-)association unless prev_bssid
    1183                 :            :          * matches the current BSSID.
    1184                 :            :          */
    1185                 :          0 :         if (wdev->current_bss) {
    1186                 :          0 :                 if (!prev_bssid)
    1187                 :            :                         return -EALREADY;
    1188                 :          0 :                 if (!ether_addr_equal(prev_bssid, wdev->current_bss->pub.bssid))
    1189                 :            :                         return -ENOTCONN;
    1190                 :            :         }
    1191                 :            : 
    1192                 :            :         /*
    1193                 :            :          * Reject if we're in the process of connecting with WEP,
    1194                 :            :          * this case isn't very interesting and trying to handle
    1195                 :            :          * it would make the code much more complex.
    1196                 :            :          */
    1197                 :          0 :         if (wdev->connect_keys)
    1198                 :            :                 return -EINPROGRESS;
    1199                 :            : 
    1200                 :          0 :         cfg80211_oper_and_ht_capa(&connect->ht_capa_mask,
    1201                 :            :                                   rdev->wiphy.ht_capa_mod_mask);
    1202                 :          0 :         cfg80211_oper_and_vht_capa(&connect->vht_capa_mask,
    1203                 :            :                                    rdev->wiphy.vht_capa_mod_mask);
    1204                 :            : 
    1205                 :          0 :         if (connkeys && connkeys->def >= 0) {
    1206                 :            :                 int idx;
    1207                 :            :                 u32 cipher;
    1208                 :            : 
    1209                 :            :                 idx = connkeys->def;
    1210                 :          0 :                 cipher = connkeys->params[idx].cipher;
    1211                 :            :                 /* If given a WEP key we may need it for shared key auth */
    1212                 :          0 :                 if (cipher == WLAN_CIPHER_SUITE_WEP40 ||
    1213                 :          0 :                     cipher == WLAN_CIPHER_SUITE_WEP104) {
    1214                 :          0 :                         connect->key_idx = idx;
    1215                 :          0 :                         connect->key = connkeys->params[idx].key;
    1216                 :          0 :                         connect->key_len = connkeys->params[idx].key_len;
    1217                 :            : 
    1218                 :            :                         /*
    1219                 :            :                          * If ciphers are not set (e.g. when going through
    1220                 :            :                          * iwconfig), we have to set them appropriately here.
    1221                 :            :                          */
    1222                 :          0 :                         if (connect->crypto.cipher_group == 0)
    1223                 :          0 :                                 connect->crypto.cipher_group = cipher;
    1224                 :            : 
    1225                 :          0 :                         if (connect->crypto.n_ciphers_pairwise == 0) {
    1226                 :          0 :                                 connect->crypto.n_ciphers_pairwise = 1;
    1227                 :          0 :                                 connect->crypto.ciphers_pairwise[0] = cipher;
    1228                 :            :                         }
    1229                 :            :                 }
    1230                 :            : 
    1231                 :          0 :                 connect->crypto.wep_keys = connkeys->params;
    1232                 :          0 :                 connect->crypto.wep_tx_key = connkeys->def;
    1233                 :            :         } else {
    1234                 :          0 :                 if (WARN_ON(connkeys))
    1235                 :            :                         return -EINVAL;
    1236                 :            :         }
    1237                 :            : 
    1238                 :          0 :         wdev->connect_keys = connkeys;
    1239                 :          0 :         memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
    1240                 :          0 :         wdev->ssid_len = connect->ssid_len;
    1241                 :            : 
    1242                 :          0 :         wdev->conn_bss_type = connect->pbss ? IEEE80211_BSS_TYPE_PBSS :
    1243                 :            :                                               IEEE80211_BSS_TYPE_ESS;
    1244                 :            : 
    1245                 :          0 :         if (!rdev->ops->connect)
    1246                 :          0 :                 err = cfg80211_sme_connect(wdev, connect, prev_bssid);
    1247                 :            :         else
    1248                 :          0 :                 err = rdev_connect(rdev, dev, connect);
    1249                 :            : 
    1250                 :          0 :         if (err) {
    1251                 :          0 :                 wdev->connect_keys = NULL;
    1252                 :            :                 /*
    1253                 :            :                  * This could be reassoc getting refused, don't clear
    1254                 :            :                  * ssid_len in that case.
    1255                 :            :                  */
    1256                 :          0 :                 if (!wdev->current_bss)
    1257                 :          0 :                         wdev->ssid_len = 0;
    1258                 :          0 :                 return err;
    1259                 :            :         }
    1260                 :            : 
    1261                 :            :         return 0;
    1262                 :            : }
    1263                 :            : 
    1264                 :          0 : int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
    1265                 :            :                         struct net_device *dev, u16 reason, bool wextev)
    1266                 :            : {
    1267                 :          0 :         struct wireless_dev *wdev = dev->ieee80211_ptr;
    1268                 :            :         int err = 0;
    1269                 :            : 
    1270                 :            :         ASSERT_WDEV_LOCK(wdev);
    1271                 :            : 
    1272                 :          0 :         kzfree(wdev->connect_keys);
    1273                 :          0 :         wdev->connect_keys = NULL;
    1274                 :            : 
    1275                 :          0 :         wdev->conn_owner_nlportid = 0;
    1276                 :            : 
    1277                 :          0 :         if (wdev->conn)
    1278                 :          0 :                 err = cfg80211_sme_disconnect(wdev, reason);
    1279                 :          0 :         else if (!rdev->ops->disconnect)
    1280                 :          0 :                 cfg80211_mlme_down(rdev, dev);
    1281                 :          0 :         else if (wdev->ssid_len)
    1282                 :          0 :                 err = rdev_disconnect(rdev, dev, reason);
    1283                 :            : 
    1284                 :            :         /*
    1285                 :            :          * Clear ssid_len unless we actually were fully connected,
    1286                 :            :          * in which case cfg80211_disconnected() will take care of
    1287                 :            :          * this later.
    1288                 :            :          */
    1289                 :          0 :         if (!wdev->current_bss)
    1290                 :          0 :                 wdev->ssid_len = 0;
    1291                 :            : 
    1292                 :          0 :         return err;
    1293                 :            : }
    1294                 :            : 
    1295                 :            : /*
    1296                 :            :  * Used to clean up after the connection / connection attempt owner socket
    1297                 :            :  * disconnects
    1298                 :            :  */
    1299                 :          0 : void cfg80211_autodisconnect_wk(struct work_struct *work)
    1300                 :            : {
    1301                 :            :         struct wireless_dev *wdev =
    1302                 :            :                 container_of(work, struct wireless_dev, disconnect_wk);
    1303                 :          0 :         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
    1304                 :            : 
    1305                 :            :         wdev_lock(wdev);
    1306                 :            : 
    1307                 :          0 :         if (wdev->conn_owner_nlportid) {
    1308                 :          0 :                 switch (wdev->iftype) {
    1309                 :            :                 case NL80211_IFTYPE_ADHOC:
    1310                 :          0 :                         __cfg80211_leave_ibss(rdev, wdev->netdev, false);
    1311                 :          0 :                         break;
    1312                 :            :                 case NL80211_IFTYPE_AP:
    1313                 :            :                 case NL80211_IFTYPE_P2P_GO:
    1314                 :          0 :                         __cfg80211_stop_ap(rdev, wdev->netdev, false);
    1315                 :          0 :                         break;
    1316                 :            :                 case NL80211_IFTYPE_MESH_POINT:
    1317                 :          0 :                         __cfg80211_leave_mesh(rdev, wdev->netdev);
    1318                 :          0 :                         break;
    1319                 :            :                 case NL80211_IFTYPE_STATION:
    1320                 :            :                 case NL80211_IFTYPE_P2P_CLIENT:
    1321                 :            :                         /*
    1322                 :            :                          * Use disconnect_bssid if still connecting and
    1323                 :            :                          * ops->disconnect not implemented.  Otherwise we can
    1324                 :            :                          * use cfg80211_disconnect.
    1325                 :            :                          */
    1326                 :          0 :                         if (rdev->ops->disconnect || wdev->current_bss)
    1327                 :          0 :                                 cfg80211_disconnect(rdev, wdev->netdev,
    1328                 :            :                                                     WLAN_REASON_DEAUTH_LEAVING,
    1329                 :            :                                                     true);
    1330                 :            :                         else
    1331                 :          0 :                                 cfg80211_mlme_deauth(rdev, wdev->netdev,
    1332                 :          0 :                                                      wdev->disconnect_bssid,
    1333                 :            :                                                      NULL, 0,
    1334                 :            :                                                      WLAN_REASON_DEAUTH_LEAVING,
    1335                 :            :                                                      false);
    1336                 :            :                         break;
    1337                 :            :                 default:
    1338                 :            :                         break;
    1339                 :            :                 }
    1340                 :            :         }
    1341                 :            : 
    1342                 :            :         wdev_unlock(wdev);
    1343                 :          0 : }
    

Generated by: LCOV version 1.14