linux/net/wireless/sme.c
<<
>>
Prefs
   1/*
   2 * SME code for cfg80211's connect emulation.
   3 *
   4 * Copyright 2009       Johannes Berg <johannes@sipsolutions.net>
   5 * Copyright (C) 2009   Intel Corporation. All rights reserved.
   6 */
   7
   8#include <linux/etherdevice.h>
   9#include <linux/if_arp.h>
  10#include <linux/workqueue.h>
  11#include <linux/wireless.h>
  12#include <net/iw_handler.h>
  13#include <net/cfg80211.h>
  14#include <net/rtnetlink.h>
  15#include "nl80211.h"
  16#include "reg.h"
  17
  18struct cfg80211_conn {
  19        struct cfg80211_connect_params params;
  20        /* these are sub-states of the _CONNECTING sme_state */
  21        enum {
  22                CFG80211_CONN_IDLE,
  23                CFG80211_CONN_SCANNING,
  24                CFG80211_CONN_SCAN_AGAIN,
  25                CFG80211_CONN_AUTHENTICATE_NEXT,
  26                CFG80211_CONN_AUTHENTICATING,
  27                CFG80211_CONN_ASSOCIATE_NEXT,
  28                CFG80211_CONN_ASSOCIATING,
  29                CFG80211_CONN_DEAUTH_ASSOC_FAIL,
  30        } state;
  31        u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
  32        u8 *ie;
  33        size_t ie_len;
  34        bool auto_auth, prev_bssid_valid;
  35};
  36
  37
  38static int cfg80211_conn_scan(struct wireless_dev *wdev)
  39{
  40        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
  41        struct cfg80211_scan_request *request;
  42        int n_channels, err;
  43
  44        ASSERT_RTNL();
  45        ASSERT_RDEV_LOCK(rdev);
  46        ASSERT_WDEV_LOCK(wdev);
  47
  48        if (rdev->scan_req)
  49                return -EBUSY;
  50
  51        if (wdev->conn->params.channel) {
  52                n_channels = 1;
  53        } else {
  54                enum ieee80211_band band;
  55                n_channels = 0;
  56
  57                for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
  58                        if (!wdev->wiphy->bands[band])
  59                                continue;
  60                        n_channels += wdev->wiphy->bands[band]->n_channels;
  61                }
  62        }
  63        request = kzalloc(sizeof(*request) + sizeof(request->ssids[0]) +
  64                          sizeof(request->channels[0]) * n_channels,
  65                          GFP_KERNEL);
  66        if (!request)
  67                return -ENOMEM;
  68
  69        if (wdev->conn->params.channel)
  70                request->channels[0] = wdev->conn->params.channel;
  71        else {
  72                int i = 0, j;
  73                enum ieee80211_band band;
  74
  75                for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
  76                        if (!wdev->wiphy->bands[band])
  77                                continue;
  78                        for (j = 0; j < wdev->wiphy->bands[band]->n_channels;
  79                             i++, j++)
  80                                request->channels[i] =
  81                                        &wdev->wiphy->bands[band]->channels[j];
  82                }
  83        }
  84        request->n_channels = n_channels;
  85        request->ssids = (void *)&request->channels[n_channels];
  86        request->n_ssids = 1;
  87
  88        memcpy(request->ssids[0].ssid, wdev->conn->params.ssid,
  89                wdev->conn->params.ssid_len);
  90        request->ssids[0].ssid_len = wdev->conn->params.ssid_len;
  91
  92        request->dev = wdev->netdev;
  93        request->wiphy = &rdev->wiphy;
  94
  95        rdev->scan_req = request;
  96
  97        err = rdev->ops->scan(wdev->wiphy, wdev->netdev, request);
  98        if (!err) {
  99                wdev->conn->state = CFG80211_CONN_SCANNING;
 100                nl80211_send_scan_start(rdev, wdev->netdev);
 101                dev_hold(wdev->netdev);
 102        } else {
 103                rdev->scan_req = NULL;
 104                kfree(request);
 105        }
 106        return err;
 107}
 108
 109static int cfg80211_conn_do_work(struct wireless_dev *wdev)
 110{
 111        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
 112        struct cfg80211_connect_params *params;
 113        const u8 *prev_bssid = NULL;
 114        int err;
 115
 116        ASSERT_WDEV_LOCK(wdev);
 117
 118        if (!wdev->conn)
 119                return 0;
 120
 121        params = &wdev->conn->params;
 122
 123        switch (wdev->conn->state) {
 124        case CFG80211_CONN_SCAN_AGAIN:
 125                return cfg80211_conn_scan(wdev);
 126        case CFG80211_CONN_AUTHENTICATE_NEXT:
 127                BUG_ON(!rdev->ops->auth);
 128                wdev->conn->state = CFG80211_CONN_AUTHENTICATING;
 129                return __cfg80211_mlme_auth(rdev, wdev->netdev,
 130                                            params->channel, params->auth_type,
 131                                            params->bssid,
 132                                            params->ssid, params->ssid_len,
 133                                            NULL, 0,
 134                                            params->key, params->key_len,
 135                                            params->key_idx);
 136        case CFG80211_CONN_ASSOCIATE_NEXT:
 137                BUG_ON(!rdev->ops->assoc);
 138                wdev->conn->state = CFG80211_CONN_ASSOCIATING;
 139                if (wdev->conn->prev_bssid_valid)
 140                        prev_bssid = wdev->conn->prev_bssid;
 141                err = __cfg80211_mlme_assoc(rdev, wdev->netdev,
 142                                            params->channel, params->bssid,
 143                                            prev_bssid,
 144                                            params->ssid, params->ssid_len,
 145                                            params->ie, params->ie_len,
 146                                            false, &params->crypto);
 147                if (err)
 148                        __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
 149                                               NULL, 0,
 150                                               WLAN_REASON_DEAUTH_LEAVING);
 151                return err;
 152        case CFG80211_CONN_DEAUTH_ASSOC_FAIL:
 153                __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
 154                                       NULL, 0,
 155                                       WLAN_REASON_DEAUTH_LEAVING);
 156                /* return an error so that we call __cfg80211_connect_result() */
 157                return -EINVAL;
 158        default:
 159                return 0;
 160        }
 161}
 162
 163void cfg80211_conn_work(struct work_struct *work)
 164{
 165        struct cfg80211_registered_device *rdev =
 166                container_of(work, struct cfg80211_registered_device, conn_work);
 167        struct wireless_dev *wdev;
 168        u8 bssid_buf[ETH_ALEN], *bssid = NULL;
 169
 170        rtnl_lock();
 171        cfg80211_lock_rdev(rdev);
 172        mutex_lock(&rdev->devlist_mtx);
 173
 174        list_for_each_entry(wdev, &rdev->netdev_list, list) {
 175                wdev_lock(wdev);
 176                if (!netif_running(wdev->netdev)) {
 177                        wdev_unlock(wdev);
 178                        continue;
 179                }
 180                if (wdev->sme_state != CFG80211_SME_CONNECTING) {
 181                        wdev_unlock(wdev);
 182                        continue;
 183                }
 184                if (wdev->conn->params.bssid) {
 185                        memcpy(bssid_buf, wdev->conn->params.bssid, ETH_ALEN);
 186                        bssid = bssid_buf;
 187                }
 188                if (cfg80211_conn_do_work(wdev))
 189                        __cfg80211_connect_result(
 190                                        wdev->netdev, bssid,
 191                                        NULL, 0, NULL, 0,
 192                                        WLAN_STATUS_UNSPECIFIED_FAILURE,
 193                                        false, NULL);
 194                wdev_unlock(wdev);
 195        }
 196
 197        mutex_unlock(&rdev->devlist_mtx);
 198        cfg80211_unlock_rdev(rdev);
 199        rtnl_unlock();
 200}
 201
 202static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev)
 203{
 204        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
 205        struct cfg80211_bss *bss;
 206        u16 capa = WLAN_CAPABILITY_ESS;
 207
 208        ASSERT_WDEV_LOCK(wdev);
 209
 210        if (wdev->conn->params.privacy)
 211                capa |= WLAN_CAPABILITY_PRIVACY;
 212
 213        bss = cfg80211_get_bss(wdev->wiphy, NULL, wdev->conn->params.bssid,
 214                               wdev->conn->params.ssid,
 215                               wdev->conn->params.ssid_len,
 216                               WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY,
 217                               capa);
 218        if (!bss)
 219                return NULL;
 220
 221        memcpy(wdev->conn->bssid, bss->bssid, ETH_ALEN);
 222        wdev->conn->params.bssid = wdev->conn->bssid;
 223        wdev->conn->params.channel = bss->channel;
 224        wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
 225        schedule_work(&rdev->conn_work);
 226
 227        return bss;
 228}
 229
 230static void __cfg80211_sme_scan_done(struct net_device *dev)
 231{
 232        struct wireless_dev *wdev = dev->ieee80211_ptr;
 233        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
 234        struct cfg80211_bss *bss;
 235
 236        ASSERT_WDEV_LOCK(wdev);
 237
 238        if (wdev->sme_state != CFG80211_SME_CONNECTING)
 239                return;
 240
 241        if (!wdev->conn)
 242                return;
 243
 244        if (wdev->conn->state != CFG80211_CONN_SCANNING &&
 245            wdev->conn->state != CFG80211_CONN_SCAN_AGAIN)
 246                return;
 247
 248        bss = cfg80211_get_conn_bss(wdev);
 249        if (bss) {
 250                cfg80211_put_bss(bss);
 251        } else {
 252                /* not found */
 253                if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)
 254                        schedule_work(&rdev->conn_work);
 255                else
 256                        __cfg80211_connect_result(
 257                                        wdev->netdev,
 258                                        wdev->conn->params.bssid,
 259                                        NULL, 0, NULL, 0,
 260                                        WLAN_STATUS_UNSPECIFIED_FAILURE,
 261                                        false, NULL);
 262        }
 263}
 264
 265void cfg80211_sme_scan_done(struct net_device *dev)
 266{
 267        struct wireless_dev *wdev = dev->ieee80211_ptr;
 268
 269        mutex_lock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx);
 270        wdev_lock(wdev);
 271        __cfg80211_sme_scan_done(dev);
 272        wdev_unlock(wdev);
 273        mutex_unlock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx);
 274}
 275
 276void cfg80211_sme_rx_auth(struct net_device *dev,
 277                          const u8 *buf, size_t len)
 278{
 279        struct wireless_dev *wdev = dev->ieee80211_ptr;
 280        struct wiphy *wiphy = wdev->wiphy;
 281        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 282        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
 283        u16 status_code = le16_to_cpu(mgmt->u.auth.status_code);
 284
 285        ASSERT_WDEV_LOCK(wdev);
 286
 287        /* should only RX auth frames when connecting */
 288        if (wdev->sme_state != CFG80211_SME_CONNECTING)
 289                return;
 290
 291        if (WARN_ON(!wdev->conn))
 292                return;
 293
 294        if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG &&
 295            wdev->conn->auto_auth &&
 296            wdev->conn->params.auth_type != NL80211_AUTHTYPE_NETWORK_EAP) {
 297                /* select automatically between only open, shared, leap */
 298                switch (wdev->conn->params.auth_type) {
 299                case NL80211_AUTHTYPE_OPEN_SYSTEM:
 300                        if (wdev->connect_keys)
 301                                wdev->conn->params.auth_type =
 302                                        NL80211_AUTHTYPE_SHARED_KEY;
 303                        else
 304                                wdev->conn->params.auth_type =
 305                                        NL80211_AUTHTYPE_NETWORK_EAP;
 306                        break;
 307                case NL80211_AUTHTYPE_SHARED_KEY:
 308                        wdev->conn->params.auth_type =
 309                                NL80211_AUTHTYPE_NETWORK_EAP;
 310                        break;
 311                default:
 312                        /* huh? */
 313                        wdev->conn->params.auth_type =
 314                                NL80211_AUTHTYPE_OPEN_SYSTEM;
 315                        break;
 316                }
 317                wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
 318                schedule_work(&rdev->conn_work);
 319        } else if (status_code != WLAN_STATUS_SUCCESS) {
 320                __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
 321                                          status_code, false, NULL);
 322        } else if (wdev->sme_state == CFG80211_SME_CONNECTING &&
 323                 wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
 324                wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
 325                schedule_work(&rdev->conn_work);
 326        }
 327}
 328
 329bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev)
 330{
 331        struct wiphy *wiphy = wdev->wiphy;
 332        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 333
 334        if (WARN_ON(!wdev->conn))
 335                return false;
 336
 337        if (!wdev->conn->prev_bssid_valid)
 338                return false;
 339
 340        /*
 341         * Some stupid APs don't accept reassoc, so we
 342         * need to fall back to trying regular assoc.
 343         */
 344        wdev->conn->prev_bssid_valid = false;
 345        wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
 346        schedule_work(&rdev->conn_work);
 347
 348        return true;
 349}
 350
 351void cfg80211_sme_failed_assoc(struct wireless_dev *wdev)
 352{
 353        struct wiphy *wiphy = wdev->wiphy;
 354        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 355
 356        wdev->conn->state = CFG80211_CONN_DEAUTH_ASSOC_FAIL;
 357        schedule_work(&rdev->conn_work);
 358}
 359
 360void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
 361                               const u8 *req_ie, size_t req_ie_len,
 362                               const u8 *resp_ie, size_t resp_ie_len,
 363                               u16 status, bool wextev,
 364                               struct cfg80211_bss *bss)
 365{
 366        struct wireless_dev *wdev = dev->ieee80211_ptr;
 367        u8 *country_ie;
 368#ifdef CONFIG_WIRELESS_EXT
 369        union iwreq_data wrqu;
 370#endif
 371
 372        ASSERT_WDEV_LOCK(wdev);
 373
 374        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
 375                return;
 376
 377        if (wdev->sme_state != CFG80211_SME_CONNECTING)
 378                return;
 379
 380        nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev,
 381                                    bssid, req_ie, req_ie_len,
 382                                    resp_ie, resp_ie_len,
 383                                    status, GFP_KERNEL);
 384
 385#ifdef CONFIG_WIRELESS_EXT
 386        if (wextev) {
 387                if (req_ie && status == WLAN_STATUS_SUCCESS) {
 388                        memset(&wrqu, 0, sizeof(wrqu));
 389                        wrqu.data.length = req_ie_len;
 390                        wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, req_ie);
 391                }
 392
 393                if (resp_ie && status == WLAN_STATUS_SUCCESS) {
 394                        memset(&wrqu, 0, sizeof(wrqu));
 395                        wrqu.data.length = resp_ie_len;
 396                        wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie);
 397                }
 398
 399                memset(&wrqu, 0, sizeof(wrqu));
 400                wrqu.ap_addr.sa_family = ARPHRD_ETHER;
 401                if (bssid && status == WLAN_STATUS_SUCCESS) {
 402                        memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
 403                        memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN);
 404                        wdev->wext.prev_bssid_valid = true;
 405                }
 406                wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
 407        }
 408#endif
 409
 410        if (wdev->current_bss) {
 411                cfg80211_unhold_bss(wdev->current_bss);
 412                cfg80211_put_bss(&wdev->current_bss->pub);
 413                wdev->current_bss = NULL;
 414        }
 415
 416        if (wdev->conn)
 417                wdev->conn->state = CFG80211_CONN_IDLE;
 418
 419        if (status != WLAN_STATUS_SUCCESS) {
 420                wdev->sme_state = CFG80211_SME_IDLE;
 421                if (wdev->conn)
 422                        kfree(wdev->conn->ie);
 423                kfree(wdev->conn);
 424                wdev->conn = NULL;
 425                kfree(wdev->connect_keys);
 426                wdev->connect_keys = NULL;
 427                wdev->ssid_len = 0;
 428                return;
 429        }
 430
 431        if (!bss)
 432                bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
 433                                       wdev->ssid, wdev->ssid_len,
 434                                       WLAN_CAPABILITY_ESS,
 435                                       WLAN_CAPABILITY_ESS);
 436
 437        if (WARN_ON(!bss))
 438                return;
 439
 440        cfg80211_hold_bss(bss_from_pub(bss));
 441        wdev->current_bss = bss_from_pub(bss);
 442
 443        wdev->sme_state = CFG80211_SME_CONNECTED;
 444        cfg80211_upload_connect_keys(wdev);
 445
 446        country_ie = (u8 *) ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);
 447
 448        if (!country_ie)
 449                return;
 450
 451        /*
 452         * ieee80211_bss_get_ie() ensures we can access:
 453         * - country_ie + 2, the start of the country ie data, and
 454         * - and country_ie[1] which is the IE length
 455         */
 456        regulatory_hint_11d(wdev->wiphy,
 457                            country_ie + 2,
 458                            country_ie[1]);
 459}
 460
 461void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
 462                             const u8 *req_ie, size_t req_ie_len,
 463                             const u8 *resp_ie, size_t resp_ie_len,
 464                             u16 status, gfp_t gfp)
 465{
 466        struct wireless_dev *wdev = dev->ieee80211_ptr;
 467        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
 468        struct cfg80211_event *ev;
 469        unsigned long flags;
 470
 471        CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING);
 472
 473        ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
 474        if (!ev)
 475                return;
 476
 477        ev->type = EVENT_CONNECT_RESULT;
 478        if (bssid)
 479                memcpy(ev->cr.bssid, bssid, ETH_ALEN);
 480        ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev);
 481        ev->cr.req_ie_len = req_ie_len;
 482        memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len);
 483        ev->cr.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len;
 484        ev->cr.resp_ie_len = resp_ie_len;
 485        memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len);
 486        ev->cr.status = status;
 487
 488        spin_lock_irqsave(&wdev->event_lock, flags);
 489        list_add_tail(&ev->list, &wdev->event_list);
 490        spin_unlock_irqrestore(&wdev->event_lock, flags);
 491        schedule_work(&rdev->event_work);
 492}
 493EXPORT_SYMBOL(cfg80211_connect_result);
 494
 495void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
 496                       const u8 *req_ie, size_t req_ie_len,
 497                       const u8 *resp_ie, size_t resp_ie_len)
 498{
 499        struct cfg80211_bss *bss;
 500#ifdef CONFIG_WIRELESS_EXT
 501        union iwreq_data wrqu;
 502#endif
 503
 504        ASSERT_WDEV_LOCK(wdev);
 505
 506        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
 507                return;
 508
 509        if (wdev->sme_state != CFG80211_SME_CONNECTED)
 510                return;
 511
 512        /* internal error -- how did we get to CONNECTED w/o BSS? */
 513        if (WARN_ON(!wdev->current_bss)) {
 514                return;
 515        }
 516
 517        cfg80211_unhold_bss(wdev->current_bss);
 518        cfg80211_put_bss(&wdev->current_bss->pub);
 519        wdev->current_bss = NULL;
 520
 521        bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
 522                               wdev->ssid, wdev->ssid_len,
 523                               WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
 524
 525        if (WARN_ON(!bss))
 526                return;
 527
 528        cfg80211_hold_bss(bss_from_pub(bss));
 529        wdev->current_bss = bss_from_pub(bss);
 530
 531        nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), wdev->netdev, bssid,
 532                            req_ie, req_ie_len, resp_ie, resp_ie_len,
 533                            GFP_KERNEL);
 534
 535#ifdef CONFIG_WIRELESS_EXT
 536        if (req_ie) {
 537                memset(&wrqu, 0, sizeof(wrqu));
 538                wrqu.data.length = req_ie_len;
 539                wireless_send_event(wdev->netdev, IWEVASSOCREQIE,
 540                                    &wrqu, req_ie);
 541        }
 542
 543        if (resp_ie) {
 544                memset(&wrqu, 0, sizeof(wrqu));
 545                wrqu.data.length = resp_ie_len;
 546                wireless_send_event(wdev->netdev, IWEVASSOCRESPIE,
 547                                    &wrqu, resp_ie);
 548        }
 549
 550        memset(&wrqu, 0, sizeof(wrqu));
 551        wrqu.ap_addr.sa_family = ARPHRD_ETHER;
 552        memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
 553        memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN);
 554        wdev->wext.prev_bssid_valid = true;
 555        wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL);
 556#endif
 557}
 558
 559void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
 560                     const u8 *req_ie, size_t req_ie_len,
 561                     const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
 562{
 563        struct wireless_dev *wdev = dev->ieee80211_ptr;
 564        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
 565        struct cfg80211_event *ev;
 566        unsigned long flags;
 567
 568        CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED);
 569
 570        ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
 571        if (!ev)
 572                return;
 573
 574        ev->type = EVENT_ROAMED;
 575        memcpy(ev->rm.bssid, bssid, ETH_ALEN);
 576        ev->rm.req_ie = ((u8 *)ev) + sizeof(*ev);
 577        ev->rm.req_ie_len = req_ie_len;
 578        memcpy((void *)ev->rm.req_ie, req_ie, req_ie_len);
 579        ev->rm.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len;
 580        ev->rm.resp_ie_len = resp_ie_len;
 581        memcpy((void *)ev->rm.resp_ie, resp_ie, resp_ie_len);
 582
 583        spin_lock_irqsave(&wdev->event_lock, flags);
 584        list_add_tail(&ev->list, &wdev->event_list);
 585        spin_unlock_irqrestore(&wdev->event_lock, flags);
 586        schedule_work(&rdev->event_work);
 587}
 588EXPORT_SYMBOL(cfg80211_roamed);
 589
 590void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
 591                             size_t ie_len, u16 reason, bool from_ap)
 592{
 593        struct wireless_dev *wdev = dev->ieee80211_ptr;
 594        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
 595        int i;
 596#ifdef CONFIG_WIRELESS_EXT
 597        union iwreq_data wrqu;
 598#endif
 599
 600        ASSERT_WDEV_LOCK(wdev);
 601
 602        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
 603                return;
 604
 605        if (wdev->sme_state != CFG80211_SME_CONNECTED)
 606                return;
 607
 608        if (wdev->current_bss) {
 609                cfg80211_unhold_bss(wdev->current_bss);
 610                cfg80211_put_bss(&wdev->current_bss->pub);
 611        }
 612
 613        wdev->current_bss = NULL;
 614        wdev->sme_state = CFG80211_SME_IDLE;
 615        wdev->ssid_len = 0;
 616
 617        if (wdev->conn) {
 618                const u8 *bssid;
 619                int ret;
 620
 621                kfree(wdev->conn->ie);
 622                wdev->conn->ie = NULL;
 623                kfree(wdev->conn);
 624                wdev->conn = NULL;
 625
 626                /*
 627                 * If this disconnect was due to a disassoc, we
 628                 * we might still have an auth BSS around. For
 629                 * the userspace SME that's currently expected,
 630                 * but for the kernel SME (nl80211 CONNECT or
 631                 * wireless extensions) we want to clear up all
 632                 * state.
 633                 */
 634                for (i = 0; i < MAX_AUTH_BSSES; i++) {
 635                        if (!wdev->auth_bsses[i])
 636                                continue;
 637                        bssid = wdev->auth_bsses[i]->pub.bssid;
 638                        ret = __cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0,
 639                                                WLAN_REASON_DEAUTH_LEAVING);
 640                        WARN(ret, "deauth failed: %d\n", ret);
 641                }
 642        }
 643
 644        nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
 645
 646        /*
 647         * Delete all the keys ... pairwise keys can't really
 648         * exist any more anyway, but default keys might.
 649         */
 650        if (rdev->ops->del_key)
 651                for (i = 0; i < 6; i++)
 652                        rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
 653
 654#ifdef CONFIG_WIRELESS_EXT
 655        memset(&wrqu, 0, sizeof(wrqu));
 656        wrqu.ap_addr.sa_family = ARPHRD_ETHER;
 657        wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
 658#endif
 659}
 660
 661void cfg80211_disconnected(struct net_device *dev, u16 reason,
 662                           u8 *ie, size_t ie_len, gfp_t gfp)
 663{
 664        struct wireless_dev *wdev = dev->ieee80211_ptr;
 665        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
 666        struct cfg80211_event *ev;
 667        unsigned long flags;
 668
 669        CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED);
 670
 671        ev = kzalloc(sizeof(*ev) + ie_len, gfp);
 672        if (!ev)
 673                return;
 674
 675        ev->type = EVENT_DISCONNECTED;
 676        ev->dc.ie = ((u8 *)ev) + sizeof(*ev);
 677        ev->dc.ie_len = ie_len;
 678        memcpy((void *)ev->dc.ie, ie, ie_len);
 679        ev->dc.reason = reason;
 680
 681        spin_lock_irqsave(&wdev->event_lock, flags);
 682        list_add_tail(&ev->list, &wdev->event_list);
 683        spin_unlock_irqrestore(&wdev->event_lock, flags);
 684        schedule_work(&rdev->event_work);
 685}
 686EXPORT_SYMBOL(cfg80211_disconnected);
 687
 688int __cfg80211_connect(struct cfg80211_registered_device *rdev,
 689                       struct net_device *dev,
 690                       struct cfg80211_connect_params *connect,
 691                       struct cfg80211_cached_keys *connkeys,
 692                       const u8 *prev_bssid)
 693{
 694        struct wireless_dev *wdev = dev->ieee80211_ptr;
 695        struct ieee80211_channel *chan;
 696        struct cfg80211_bss *bss = NULL;
 697        int err;
 698
 699        ASSERT_WDEV_LOCK(wdev);
 700
 701        if (wdev->sme_state != CFG80211_SME_IDLE)
 702                return -EALREADY;
 703
 704        chan = rdev_fixed_channel(rdev, wdev);
 705        if (chan && chan != connect->channel)
 706                return -EBUSY;
 707
 708        if (WARN_ON(wdev->connect_keys)) {
 709                kfree(wdev->connect_keys);
 710                wdev->connect_keys = NULL;
 711        }
 712
 713        if (connkeys && connkeys->def >= 0) {
 714                int idx;
 715                u32 cipher;
 716
 717                idx = connkeys->def;
 718                cipher = connkeys->params[idx].cipher;
 719                /* If given a WEP key we may need it for shared key auth */
 720                if (cipher == WLAN_CIPHER_SUITE_WEP40 ||
 721                    cipher == WLAN_CIPHER_SUITE_WEP104) {
 722                        connect->key_idx = idx;
 723                        connect->key = connkeys->params[idx].key;
 724                        connect->key_len = connkeys->params[idx].key_len;
 725
 726                        /*
 727                         * If ciphers are not set (e.g. when going through
 728                         * iwconfig), we have to set them appropriately here.
 729                         */
 730                        if (connect->crypto.cipher_group == 0)
 731                                connect->crypto.cipher_group = cipher;
 732
 733                        if (connect->crypto.n_ciphers_pairwise == 0) {
 734                                connect->crypto.n_ciphers_pairwise = 1;
 735                                connect->crypto.ciphers_pairwise[0] = cipher;
 736                        }
 737                }
 738        }
 739
 740        if (!rdev->ops->connect) {
 741                if (!rdev->ops->auth || !rdev->ops->assoc)
 742                        return -EOPNOTSUPP;
 743
 744                if (WARN_ON(wdev->conn))
 745                        return -EINPROGRESS;
 746
 747                wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL);
 748                if (!wdev->conn)
 749                        return -ENOMEM;
 750
 751                /*
 752                 * Copy all parameters, and treat explicitly IEs, BSSID, SSID.
 753                 */
 754                memcpy(&wdev->conn->params, connect, sizeof(*connect));
 755                if (connect->bssid) {
 756                        wdev->conn->params.bssid = wdev->conn->bssid;
 757                        memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN);
 758                }
 759
 760                if (connect->ie) {
 761                        wdev->conn->ie = kmemdup(connect->ie, connect->ie_len,
 762                                                GFP_KERNEL);
 763                        wdev->conn->params.ie = wdev->conn->ie;
 764                        if (!wdev->conn->ie) {
 765                                kfree(wdev->conn);
 766                                wdev->conn = NULL;
 767                                return -ENOMEM;
 768                        }
 769                }
 770
 771                if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
 772                        wdev->conn->auto_auth = true;
 773                        /* start with open system ... should mostly work */
 774                        wdev->conn->params.auth_type =
 775                                NL80211_AUTHTYPE_OPEN_SYSTEM;
 776                } else {
 777                        wdev->conn->auto_auth = false;
 778                }
 779
 780                memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
 781                wdev->ssid_len = connect->ssid_len;
 782                wdev->conn->params.ssid = wdev->ssid;
 783                wdev->conn->params.ssid_len = connect->ssid_len;
 784
 785                /* see if we have the bss already */
 786                bss = cfg80211_get_conn_bss(wdev);
 787
 788                wdev->sme_state = CFG80211_SME_CONNECTING;
 789                wdev->connect_keys = connkeys;
 790
 791                if (prev_bssid) {
 792                        memcpy(wdev->conn->prev_bssid, prev_bssid, ETH_ALEN);
 793                        wdev->conn->prev_bssid_valid = true;
 794                }
 795
 796                /* we're good if we have a matching bss struct */
 797                if (bss) {
 798                        wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
 799                        err = cfg80211_conn_do_work(wdev);
 800                        cfg80211_put_bss(bss);
 801                } else {
 802                        /* otherwise we'll need to scan for the AP first */
 803                        err = cfg80211_conn_scan(wdev);
 804                        /*
 805                         * If we can't scan right now, then we need to scan again
 806                         * after the current scan finished, since the parameters
 807                         * changed (unless we find a good AP anyway).
 808                         */
 809                        if (err == -EBUSY) {
 810                                err = 0;
 811                                wdev->conn->state = CFG80211_CONN_SCAN_AGAIN;
 812                        }
 813                }
 814                if (err) {
 815                        kfree(wdev->conn->ie);
 816                        kfree(wdev->conn);
 817                        wdev->conn = NULL;
 818                        wdev->sme_state = CFG80211_SME_IDLE;
 819                        wdev->connect_keys = NULL;
 820                        wdev->ssid_len = 0;
 821                }
 822
 823                return err;
 824        } else {
 825                wdev->sme_state = CFG80211_SME_CONNECTING;
 826                wdev->connect_keys = connkeys;
 827                err = rdev->ops->connect(&rdev->wiphy, dev, connect);
 828                if (err) {
 829                        wdev->connect_keys = NULL;
 830                        wdev->sme_state = CFG80211_SME_IDLE;
 831                        return err;
 832                }
 833
 834                memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
 835                wdev->ssid_len = connect->ssid_len;
 836
 837                return 0;
 838        }
 839}
 840
 841int cfg80211_connect(struct cfg80211_registered_device *rdev,
 842                     struct net_device *dev,
 843                     struct cfg80211_connect_params *connect,
 844                     struct cfg80211_cached_keys *connkeys)
 845{
 846        int err;
 847
 848        mutex_lock(&rdev->devlist_mtx);
 849        wdev_lock(dev->ieee80211_ptr);
 850        err = __cfg80211_connect(rdev, dev, connect, connkeys, NULL);
 851        wdev_unlock(dev->ieee80211_ptr);
 852        mutex_unlock(&rdev->devlist_mtx);
 853
 854        return err;
 855}
 856
 857int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
 858                          struct net_device *dev, u16 reason, bool wextev)
 859{
 860        struct wireless_dev *wdev = dev->ieee80211_ptr;
 861        int err;
 862
 863        ASSERT_WDEV_LOCK(wdev);
 864
 865        if (wdev->sme_state == CFG80211_SME_IDLE)
 866                return -EINVAL;
 867
 868        kfree(wdev->connect_keys);
 869        wdev->connect_keys = NULL;
 870
 871        if (!rdev->ops->disconnect) {
 872                if (!rdev->ops->deauth)
 873                        return -EOPNOTSUPP;
 874
 875                /* was it connected by userspace SME? */
 876                if (!wdev->conn) {
 877                        cfg80211_mlme_down(rdev, dev);
 878                        return 0;
 879                }
 880
 881                if (wdev->sme_state == CFG80211_SME_CONNECTING &&
 882                    (wdev->conn->state == CFG80211_CONN_SCANNING ||
 883                     wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) {
 884                        wdev->sme_state = CFG80211_SME_IDLE;
 885                        kfree(wdev->conn->ie);
 886                        kfree(wdev->conn);
 887                        wdev->conn = NULL;
 888                        wdev->ssid_len = 0;
 889                        return 0;
 890                }
 891
 892                /* wdev->conn->params.bssid must be set if > SCANNING */
 893                err = __cfg80211_mlme_deauth(rdev, dev,
 894                                             wdev->conn->params.bssid,
 895                                             NULL, 0, reason);
 896                if (err)
 897                        return err;
 898        } else {
 899                err = rdev->ops->disconnect(&rdev->wiphy, dev, reason);
 900                if (err)
 901                        return err;
 902        }
 903
 904        if (wdev->sme_state == CFG80211_SME_CONNECTED)
 905                __cfg80211_disconnected(dev, NULL, 0, 0, false);
 906        else if (wdev->sme_state == CFG80211_SME_CONNECTING)
 907                __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0,
 908                                          WLAN_STATUS_UNSPECIFIED_FAILURE,
 909                                          wextev, NULL);
 910
 911        return 0;
 912}
 913
 914int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
 915                        struct net_device *dev,
 916                        u16 reason, bool wextev)
 917{
 918        int err;
 919
 920        wdev_lock(dev->ieee80211_ptr);
 921        err = __cfg80211_disconnect(rdev, dev, reason, wextev);
 922        wdev_unlock(dev->ieee80211_ptr);
 923
 924        return err;
 925}
 926
 927void cfg80211_sme_disassoc(struct net_device *dev, int idx)
 928{
 929        struct wireless_dev *wdev = dev->ieee80211_ptr;
 930        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
 931        u8 bssid[ETH_ALEN];
 932
 933        ASSERT_WDEV_LOCK(wdev);
 934
 935        if (!wdev->conn)
 936                return;
 937
 938        if (wdev->conn->state == CFG80211_CONN_IDLE)
 939                return;
 940
 941        /*
 942         * Ok, so the association was made by this SME -- we don't
 943         * want it any more so deauthenticate too.
 944         */
 945
 946        if (!wdev->auth_bsses[idx])
 947                return;
 948
 949        memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN);
 950        if (__cfg80211_mlme_deauth(rdev, dev, bssid,
 951                                   NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) {
 952                /* whatever -- assume gone anyway */
 953                cfg80211_unhold_bss(wdev->auth_bsses[idx]);
 954                cfg80211_put_bss(&wdev->auth_bsses[idx]->pub);
 955                wdev->auth_bsses[idx] = NULL;
 956        }
 957}
 958