linux/net/wireless/mlme.c
<<
>>
Prefs
   1/*
   2 * cfg80211 MLME SAP interface
   3 *
   4 * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
   5 */
   6
   7#include <linux/kernel.h>
   8#include <linux/module.h>
   9#include <linux/netdevice.h>
  10#include <linux/nl80211.h>
  11#include <linux/wireless.h>
  12#include <net/cfg80211.h>
  13#include <net/iw_handler.h>
  14#include "core.h"
  15#include "nl80211.h"
  16
  17void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
  18{
  19        struct wireless_dev *wdev = dev->ieee80211_ptr;
  20        struct wiphy *wiphy = wdev->wiphy;
  21        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
  22        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
  23        u8 *bssid = mgmt->bssid;
  24        int i;
  25        u16 status = le16_to_cpu(mgmt->u.auth.status_code);
  26        bool done = false;
  27
  28        wdev_lock(wdev);
  29
  30        for (i = 0; i < MAX_AUTH_BSSES; i++) {
  31                if (wdev->authtry_bsses[i] &&
  32                    memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid,
  33                                                        ETH_ALEN) == 0) {
  34                        if (status == WLAN_STATUS_SUCCESS) {
  35                                wdev->auth_bsses[i] = wdev->authtry_bsses[i];
  36                        } else {
  37                                cfg80211_unhold_bss(wdev->authtry_bsses[i]);
  38                                cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
  39                        }
  40                        wdev->authtry_bsses[i] = NULL;
  41                        done = true;
  42                        break;
  43                }
  44        }
  45
  46        WARN_ON(!done);
  47
  48        nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
  49        cfg80211_sme_rx_auth(dev, buf, len);
  50
  51        wdev_unlock(wdev);
  52}
  53EXPORT_SYMBOL(cfg80211_send_rx_auth);
  54
  55void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
  56{
  57        u16 status_code;
  58        struct wireless_dev *wdev = dev->ieee80211_ptr;
  59        struct wiphy *wiphy = wdev->wiphy;
  60        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
  61        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
  62        u8 *ie = mgmt->u.assoc_resp.variable;
  63        int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
  64        struct cfg80211_internal_bss *bss = NULL;
  65        bool need_connect_result = true;
  66
  67        wdev_lock(wdev);
  68
  69        status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
  70
  71        /*
  72         * This is a bit of a hack, we don't notify userspace of
  73         * a (re-)association reply if we tried to send a reassoc
  74         * and got a reject -- we only try again with an assoc
  75         * frame instead of reassoc.
  76         */
  77        if (status_code != WLAN_STATUS_SUCCESS && wdev->conn &&
  78            cfg80211_sme_failed_reassoc(wdev))
  79                goto out;
  80
  81        nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL);
  82
  83        if (status_code == WLAN_STATUS_SUCCESS) {
  84                for (i = 0; i < MAX_AUTH_BSSES; i++) {
  85                        if (!wdev->auth_bsses[i])
  86                                continue;
  87                        if (memcmp(wdev->auth_bsses[i]->pub.bssid, mgmt->bssid,
  88                                   ETH_ALEN) == 0) {
  89                                bss = wdev->auth_bsses[i];
  90                                wdev->auth_bsses[i] = NULL;
  91                                /* additional reference to drop hold */
  92                                cfg80211_ref_bss(bss);
  93                                break;
  94                        }
  95                }
  96
  97                WARN_ON(!bss);
  98        } else if (wdev->conn) {
  99                cfg80211_sme_failed_assoc(wdev);
 100                need_connect_result = false;
 101                /*
 102                 * do not call connect_result() now because the
 103                 * sme will schedule work that does it later.
 104                 */
 105                goto out;
 106        }
 107
 108        if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) {
 109                /*
 110                 * This is for the userspace SME, the CONNECTING
 111                 * state will be changed to CONNECTED by
 112                 * __cfg80211_connect_result() below.
 113                 */
 114                wdev->sme_state = CFG80211_SME_CONNECTING;
 115        }
 116
 117        /* this consumes one bss reference (unless bss is NULL) */
 118        __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
 119                                  status_code,
 120                                  status_code == WLAN_STATUS_SUCCESS,
 121                                  bss ? &bss->pub : NULL);
 122        /* drop hold now, and also reference acquired above */
 123        if (bss) {
 124                cfg80211_unhold_bss(bss);
 125                cfg80211_put_bss(&bss->pub);
 126        }
 127
 128 out:
 129        wdev_unlock(wdev);
 130}
 131EXPORT_SYMBOL(cfg80211_send_rx_assoc);
 132
 133static void __cfg80211_send_deauth(struct net_device *dev,
 134                                   const u8 *buf, size_t len)
 135{
 136        struct wireless_dev *wdev = dev->ieee80211_ptr;
 137        struct wiphy *wiphy = wdev->wiphy;
 138        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 139        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
 140        const u8 *bssid = mgmt->bssid;
 141        int i;
 142        bool done = false;
 143
 144        ASSERT_WDEV_LOCK(wdev);
 145
 146        nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
 147
 148        if (wdev->current_bss &&
 149            memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
 150                done = true;
 151                cfg80211_unhold_bss(wdev->current_bss);
 152                cfg80211_put_bss(&wdev->current_bss->pub);
 153                wdev->current_bss = NULL;
 154        } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
 155                if (wdev->auth_bsses[i] &&
 156                    memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
 157                        cfg80211_unhold_bss(wdev->auth_bsses[i]);
 158                        cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
 159                        wdev->auth_bsses[i] = NULL;
 160                        done = true;
 161                        break;
 162                }
 163                if (wdev->authtry_bsses[i] &&
 164                    memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
 165                        cfg80211_unhold_bss(wdev->authtry_bsses[i]);
 166                        cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
 167                        wdev->authtry_bsses[i] = NULL;
 168                        done = true;
 169                        break;
 170                }
 171        }
 172
 173        WARN_ON(!done);
 174
 175        if (wdev->sme_state == CFG80211_SME_CONNECTED) {
 176                u16 reason_code;
 177                bool from_ap;
 178
 179                reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
 180
 181                from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
 182                __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
 183        } else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
 184                __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
 185                                          WLAN_STATUS_UNSPECIFIED_FAILURE,
 186                                          false, NULL);
 187        }
 188}
 189
 190
 191void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len,
 192                          void *cookie)
 193{
 194        struct wireless_dev *wdev = dev->ieee80211_ptr;
 195
 196        BUG_ON(cookie && wdev != cookie);
 197
 198        if (cookie) {
 199                /* called within callback */
 200                __cfg80211_send_deauth(dev, buf, len);
 201        } else {
 202                wdev_lock(wdev);
 203                __cfg80211_send_deauth(dev, buf, len);
 204                wdev_unlock(wdev);
 205        }
 206}
 207EXPORT_SYMBOL(cfg80211_send_deauth);
 208
 209static void __cfg80211_send_disassoc(struct net_device *dev,
 210                                     const u8 *buf, size_t len)
 211{
 212        struct wireless_dev *wdev = dev->ieee80211_ptr;
 213        struct wiphy *wiphy = wdev->wiphy;
 214        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 215        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
 216        const u8 *bssid = mgmt->bssid;
 217        int i;
 218        u16 reason_code;
 219        bool from_ap;
 220        bool done = false;
 221
 222        ASSERT_WDEV_LOCK(wdev);
 223
 224        nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL);
 225
 226        if (wdev->sme_state != CFG80211_SME_CONNECTED)
 227                return;
 228
 229        if (wdev->current_bss &&
 230            memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
 231                for (i = 0; i < MAX_AUTH_BSSES; i++) {
 232                        if (wdev->authtry_bsses[i] || wdev->auth_bsses[i])
 233                                continue;
 234                        wdev->auth_bsses[i] = wdev->current_bss;
 235                        wdev->current_bss = NULL;
 236                        done = true;
 237                        cfg80211_sme_disassoc(dev, i);
 238                        break;
 239                }
 240                WARN_ON(!done);
 241        } else
 242                WARN_ON(1);
 243
 244
 245        reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
 246
 247        from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
 248        __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
 249}
 250
 251void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len,
 252                            void *cookie)
 253{
 254        struct wireless_dev *wdev = dev->ieee80211_ptr;
 255
 256        BUG_ON(cookie && wdev != cookie);
 257
 258        if (cookie) {
 259                /* called within callback */
 260                __cfg80211_send_disassoc(dev, buf, len);
 261        } else {
 262                wdev_lock(wdev);
 263                __cfg80211_send_disassoc(dev, buf, len);
 264                wdev_unlock(wdev);
 265        }
 266}
 267EXPORT_SYMBOL(cfg80211_send_disassoc);
 268
 269void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
 270{
 271        struct wireless_dev *wdev = dev->ieee80211_ptr;
 272        struct wiphy *wiphy = wdev->wiphy;
 273        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 274        int i;
 275        bool done = false;
 276
 277        wdev_lock(wdev);
 278
 279        nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
 280        if (wdev->sme_state == CFG80211_SME_CONNECTING)
 281                __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
 282                                          WLAN_STATUS_UNSPECIFIED_FAILURE,
 283                                          false, NULL);
 284
 285        for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
 286                if (wdev->authtry_bsses[i] &&
 287                    memcmp(wdev->authtry_bsses[i]->pub.bssid,
 288                           addr, ETH_ALEN) == 0) {
 289                        cfg80211_unhold_bss(wdev->authtry_bsses[i]);
 290                        cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
 291                        wdev->authtry_bsses[i] = NULL;
 292                        done = true;
 293                        break;
 294                }
 295        }
 296
 297        WARN_ON(!done);
 298
 299        wdev_unlock(wdev);
 300}
 301EXPORT_SYMBOL(cfg80211_send_auth_timeout);
 302
 303void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
 304{
 305        struct wireless_dev *wdev = dev->ieee80211_ptr;
 306        struct wiphy *wiphy = wdev->wiphy;
 307        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 308        int i;
 309        bool done = false;
 310
 311        wdev_lock(wdev);
 312
 313        nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
 314        if (wdev->sme_state == CFG80211_SME_CONNECTING)
 315                __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
 316                                          WLAN_STATUS_UNSPECIFIED_FAILURE,
 317                                          false, NULL);
 318
 319        for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
 320                if (wdev->auth_bsses[i] &&
 321                    memcmp(wdev->auth_bsses[i]->pub.bssid,
 322                           addr, ETH_ALEN) == 0) {
 323                        cfg80211_unhold_bss(wdev->auth_bsses[i]);
 324                        cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
 325                        wdev->auth_bsses[i] = NULL;
 326                        done = true;
 327                        break;
 328                }
 329        }
 330
 331        WARN_ON(!done);
 332
 333        wdev_unlock(wdev);
 334}
 335EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
 336
 337void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
 338                                  enum nl80211_key_type key_type, int key_id,
 339                                  const u8 *tsc, gfp_t gfp)
 340{
 341        struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
 342        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 343#ifdef CONFIG_WIRELESS_EXT
 344        union iwreq_data wrqu;
 345        char *buf = kmalloc(128, gfp);
 346
 347        if (buf) {
 348                sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
 349                        "keyid=%d %scast addr=%pM)", key_id,
 350                        key_type == NL80211_KEYTYPE_GROUP ? "broad" : "uni",
 351                        addr);
 352                memset(&wrqu, 0, sizeof(wrqu));
 353                wrqu.data.length = strlen(buf);
 354                wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
 355                kfree(buf);
 356        }
 357#endif
 358
 359        nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp);
 360}
 361EXPORT_SYMBOL(cfg80211_michael_mic_failure);
 362
 363/* some MLME handling for userspace SME */
 364int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
 365                         struct net_device *dev,
 366                         struct ieee80211_channel *chan,
 367                         enum nl80211_auth_type auth_type,
 368                         const u8 *bssid,
 369                         const u8 *ssid, int ssid_len,
 370                         const u8 *ie, int ie_len,
 371                         const u8 *key, int key_len, int key_idx)
 372{
 373        struct wireless_dev *wdev = dev->ieee80211_ptr;
 374        struct cfg80211_auth_request req;
 375        struct cfg80211_internal_bss *bss;
 376        int i, err, slot = -1, nfree = 0;
 377
 378        ASSERT_WDEV_LOCK(wdev);
 379
 380        if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
 381                if (!key || !key_len || key_idx < 0 || key_idx > 4)
 382                        return -EINVAL;
 383
 384        if (wdev->current_bss &&
 385            memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
 386                return -EALREADY;
 387
 388        for (i = 0; i < MAX_AUTH_BSSES; i++) {
 389                if (wdev->authtry_bsses[i] &&
 390                    memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid,
 391                                                ETH_ALEN) == 0)
 392                        return -EALREADY;
 393                if (wdev->auth_bsses[i] &&
 394                    memcmp(bssid, wdev->auth_bsses[i]->pub.bssid,
 395                                                ETH_ALEN) == 0)
 396                        return -EALREADY;
 397        }
 398
 399        memset(&req, 0, sizeof(req));
 400
 401        req.ie = ie;
 402        req.ie_len = ie_len;
 403        req.auth_type = auth_type;
 404        req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
 405                                   WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
 406        req.key = key;
 407        req.key_len = key_len;
 408        req.key_idx = key_idx;
 409        if (!req.bss)
 410                return -ENOENT;
 411
 412        bss = bss_from_pub(req.bss);
 413
 414        for (i = 0; i < MAX_AUTH_BSSES; i++) {
 415                if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) {
 416                        slot = i;
 417                        nfree++;
 418                }
 419        }
 420
 421        /* we need one free slot for disassoc and one for this auth */
 422        if (nfree < 2) {
 423                err = -ENOSPC;
 424                goto out;
 425        }
 426
 427        wdev->authtry_bsses[slot] = bss;
 428        cfg80211_hold_bss(bss);
 429
 430        err = rdev->ops->auth(&rdev->wiphy, dev, &req);
 431        if (err) {
 432                wdev->authtry_bsses[slot] = NULL;
 433                cfg80211_unhold_bss(bss);
 434        }
 435
 436 out:
 437        if (err)
 438                cfg80211_put_bss(req.bss);
 439        return err;
 440}
 441
 442int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
 443                       struct net_device *dev, struct ieee80211_channel *chan,
 444                       enum nl80211_auth_type auth_type, const u8 *bssid,
 445                       const u8 *ssid, int ssid_len,
 446                       const u8 *ie, int ie_len,
 447                       const u8 *key, int key_len, int key_idx)
 448{
 449        int err;
 450
 451        wdev_lock(dev->ieee80211_ptr);
 452        err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
 453                                   ssid, ssid_len, ie, ie_len,
 454                                   key, key_len, key_idx);
 455        wdev_unlock(dev->ieee80211_ptr);
 456
 457        return err;
 458}
 459
 460int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
 461                          struct net_device *dev,
 462                          struct ieee80211_channel *chan,
 463                          const u8 *bssid, const u8 *prev_bssid,
 464                          const u8 *ssid, int ssid_len,
 465                          const u8 *ie, int ie_len, bool use_mfp,
 466                          struct cfg80211_crypto_settings *crypt)
 467{
 468        struct wireless_dev *wdev = dev->ieee80211_ptr;
 469        struct cfg80211_assoc_request req;
 470        struct cfg80211_internal_bss *bss;
 471        int i, err, slot = -1;
 472
 473        ASSERT_WDEV_LOCK(wdev);
 474
 475        memset(&req, 0, sizeof(req));
 476
 477        if (wdev->current_bss)
 478                return -EALREADY;
 479
 480        req.ie = ie;
 481        req.ie_len = ie_len;
 482        memcpy(&req.crypto, crypt, sizeof(req.crypto));
 483        req.use_mfp = use_mfp;
 484        req.prev_bssid = prev_bssid;
 485        req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
 486                                   WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
 487        if (!req.bss)
 488                return -ENOENT;
 489
 490        bss = bss_from_pub(req.bss);
 491
 492        for (i = 0; i < MAX_AUTH_BSSES; i++) {
 493                if (bss == wdev->auth_bsses[i]) {
 494                        slot = i;
 495                        break;
 496                }
 497        }
 498
 499        if (slot < 0) {
 500                err = -ENOTCONN;
 501                goto out;
 502        }
 503
 504        err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
 505 out:
 506        /* still a reference in wdev->auth_bsses[slot] */
 507        cfg80211_put_bss(req.bss);
 508        return err;
 509}
 510
 511int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
 512                        struct net_device *dev,
 513                        struct ieee80211_channel *chan,
 514                        const u8 *bssid, const u8 *prev_bssid,
 515                        const u8 *ssid, int ssid_len,
 516                        const u8 *ie, int ie_len, bool use_mfp,
 517                        struct cfg80211_crypto_settings *crypt)
 518{
 519        struct wireless_dev *wdev = dev->ieee80211_ptr;
 520        int err;
 521
 522        wdev_lock(wdev);
 523        err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
 524                                    ssid, ssid_len, ie, ie_len, use_mfp, crypt);
 525        wdev_unlock(wdev);
 526
 527        return err;
 528}
 529
 530int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
 531                           struct net_device *dev, const u8 *bssid,
 532                           const u8 *ie, int ie_len, u16 reason)
 533{
 534        struct wireless_dev *wdev = dev->ieee80211_ptr;
 535        struct cfg80211_deauth_request req;
 536        int i;
 537
 538        ASSERT_WDEV_LOCK(wdev);
 539
 540        memset(&req, 0, sizeof(req));
 541        req.reason_code = reason;
 542        req.ie = ie;
 543        req.ie_len = ie_len;
 544        if (wdev->current_bss &&
 545            memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
 546                req.bss = &wdev->current_bss->pub;
 547        } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
 548                if (wdev->auth_bsses[i] &&
 549                    memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
 550                        req.bss = &wdev->auth_bsses[i]->pub;
 551                        break;
 552                }
 553                if (wdev->authtry_bsses[i] &&
 554                    memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
 555                        req.bss = &wdev->authtry_bsses[i]->pub;
 556                        break;
 557                }
 558        }
 559
 560        if (!req.bss)
 561                return -ENOTCONN;
 562
 563        return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
 564}
 565
 566int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
 567                         struct net_device *dev, const u8 *bssid,
 568                         const u8 *ie, int ie_len, u16 reason)
 569{
 570        struct wireless_dev *wdev = dev->ieee80211_ptr;
 571        int err;
 572
 573        wdev_lock(wdev);
 574        err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason);
 575        wdev_unlock(wdev);
 576
 577        return err;
 578}
 579
 580static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
 581                                    struct net_device *dev, const u8 *bssid,
 582                                    const u8 *ie, int ie_len, u16 reason)
 583{
 584        struct wireless_dev *wdev = dev->ieee80211_ptr;
 585        struct cfg80211_disassoc_request req;
 586
 587        ASSERT_WDEV_LOCK(wdev);
 588
 589        if (wdev->sme_state != CFG80211_SME_CONNECTED)
 590                return -ENOTCONN;
 591
 592        if (WARN_ON(!wdev->current_bss))
 593                return -ENOTCONN;
 594
 595        memset(&req, 0, sizeof(req));
 596        req.reason_code = reason;
 597        req.ie = ie;
 598        req.ie_len = ie_len;
 599        if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0)
 600                req.bss = &wdev->current_bss->pub;
 601        else
 602                return -ENOTCONN;
 603
 604        return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev);
 605}
 606
 607int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
 608                           struct net_device *dev, const u8 *bssid,
 609                           const u8 *ie, int ie_len, u16 reason)
 610{
 611        struct wireless_dev *wdev = dev->ieee80211_ptr;
 612        int err;
 613
 614        wdev_lock(wdev);
 615        err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason);
 616        wdev_unlock(wdev);
 617
 618        return err;
 619}
 620
 621void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
 622                        struct net_device *dev)
 623{
 624        struct wireless_dev *wdev = dev->ieee80211_ptr;
 625        struct cfg80211_deauth_request req;
 626        int i;
 627
 628        ASSERT_WDEV_LOCK(wdev);
 629
 630        if (!rdev->ops->deauth)
 631                return;
 632
 633        memset(&req, 0, sizeof(req));
 634        req.reason_code = WLAN_REASON_DEAUTH_LEAVING;
 635        req.ie = NULL;
 636        req.ie_len = 0;
 637
 638        if (wdev->current_bss) {
 639                req.bss = &wdev->current_bss->pub;
 640                rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
 641                if (wdev->current_bss) {
 642                        cfg80211_unhold_bss(wdev->current_bss);
 643                        cfg80211_put_bss(&wdev->current_bss->pub);
 644                        wdev->current_bss = NULL;
 645                }
 646        }
 647
 648        for (i = 0; i < MAX_AUTH_BSSES; i++) {
 649                if (wdev->auth_bsses[i]) {
 650                        req.bss = &wdev->auth_bsses[i]->pub;
 651                        rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
 652                        if (wdev->auth_bsses[i]) {
 653                                cfg80211_unhold_bss(wdev->auth_bsses[i]);
 654                                cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
 655                                wdev->auth_bsses[i] = NULL;
 656                        }
 657                }
 658                if (wdev->authtry_bsses[i]) {
 659                        req.bss = &wdev->authtry_bsses[i]->pub;
 660                        rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
 661                        if (wdev->authtry_bsses[i]) {
 662                                cfg80211_unhold_bss(wdev->authtry_bsses[i]);
 663                                cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
 664                                wdev->authtry_bsses[i] = NULL;
 665                        }
 666                }
 667        }
 668}
 669