linux/net/wireless/scan.c
<<
>>
Prefs
   1/*
   2 * cfg80211 scan result handling
   3 *
   4 * Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
   5 */
   6#include <linux/kernel.h>
   7#include <linux/module.h>
   8#include <linux/netdevice.h>
   9#include <linux/wireless.h>
  10#include <linux/nl80211.h>
  11#include <linux/etherdevice.h>
  12#include <net/arp.h>
  13#include <net/cfg80211.h>
  14#include <net/iw_handler.h>
  15#include "core.h"
  16#include "nl80211.h"
  17#include "wext-compat.h"
  18
  19#define IEEE80211_SCAN_RESULT_EXPIRE    (15 * HZ)
  20
  21void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
  22{
  23        struct cfg80211_scan_request *request;
  24        struct net_device *dev;
  25#ifdef CONFIG_WIRELESS_EXT
  26        union iwreq_data wrqu;
  27#endif
  28
  29        ASSERT_RDEV_LOCK(rdev);
  30
  31        request = rdev->scan_req;
  32
  33        if (!request)
  34                return;
  35
  36        dev = request->dev;
  37
  38        /*
  39         * This must be before sending the other events!
  40         * Otherwise, wpa_supplicant gets completely confused with
  41         * wext events.
  42         */
  43        cfg80211_sme_scan_done(dev);
  44
  45        if (request->aborted)
  46                nl80211_send_scan_aborted(rdev, dev);
  47        else
  48                nl80211_send_scan_done(rdev, dev);
  49
  50#ifdef CONFIG_WIRELESS_EXT
  51        if (!request->aborted) {
  52                memset(&wrqu, 0, sizeof(wrqu));
  53
  54                wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
  55        }
  56#endif
  57
  58        dev_put(dev);
  59
  60        rdev->scan_req = NULL;
  61
  62        /*
  63         * OK. If this is invoked with "leak" then we can't
  64         * free this ... but we've cleaned it up anyway. The
  65         * driver failed to call the scan_done callback, so
  66         * all bets are off, it might still be trying to use
  67         * the scan request or not ... if it accesses the dev
  68         * in there (it shouldn't anyway) then it may crash.
  69         */
  70        if (!leak)
  71                kfree(request);
  72}
  73
  74void __cfg80211_scan_done(struct work_struct *wk)
  75{
  76        struct cfg80211_registered_device *rdev;
  77
  78        rdev = container_of(wk, struct cfg80211_registered_device,
  79                            scan_done_wk);
  80
  81        cfg80211_lock_rdev(rdev);
  82        ___cfg80211_scan_done(rdev, false);
  83        cfg80211_unlock_rdev(rdev);
  84}
  85
  86void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
  87{
  88        WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
  89
  90        request->aborted = aborted;
  91        schedule_work(&wiphy_to_dev(request->wiphy)->scan_done_wk);
  92}
  93EXPORT_SYMBOL(cfg80211_scan_done);
  94
  95static void bss_release(struct kref *ref)
  96{
  97        struct cfg80211_internal_bss *bss;
  98
  99        bss = container_of(ref, struct cfg80211_internal_bss, ref);
 100        if (bss->pub.free_priv)
 101                bss->pub.free_priv(&bss->pub);
 102
 103        if (bss->ies_allocated)
 104                kfree(bss->pub.information_elements);
 105
 106        BUG_ON(atomic_read(&bss->hold));
 107
 108        kfree(bss);
 109}
 110
 111/* must hold dev->bss_lock! */
 112void cfg80211_bss_age(struct cfg80211_registered_device *dev,
 113                      unsigned long age_secs)
 114{
 115        struct cfg80211_internal_bss *bss;
 116        unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC);
 117
 118        list_for_each_entry(bss, &dev->bss_list, list) {
 119                bss->ts -= age_jiffies;
 120        }
 121}
 122
 123/* must hold dev->bss_lock! */
 124void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
 125{
 126        struct cfg80211_internal_bss *bss, *tmp;
 127        bool expired = false;
 128
 129        list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
 130                if (atomic_read(&bss->hold))
 131                        continue;
 132                if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
 133                        continue;
 134                list_del(&bss->list);
 135                rb_erase(&bss->rbn, &dev->bss_tree);
 136                kref_put(&bss->ref, bss_release);
 137                expired = true;
 138        }
 139
 140        if (expired)
 141                dev->bss_generation++;
 142}
 143
 144static u8 *find_ie(u8 num, u8 *ies, int len)
 145{
 146        while (len > 2 && ies[0] != num) {
 147                len -= ies[1] + 2;
 148                ies += ies[1] + 2;
 149        }
 150        if (len < 2)
 151                return NULL;
 152        if (len < 2 + ies[1])
 153                return NULL;
 154        return ies;
 155}
 156
 157static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2)
 158{
 159        const u8 *ie1 = find_ie(num, ies1, len1);
 160        const u8 *ie2 = find_ie(num, ies2, len2);
 161        int r;
 162
 163        if (!ie1 && !ie2)
 164                return 0;
 165        if (!ie1 || !ie2)
 166                return -1;
 167
 168        r = memcmp(ie1 + 2, ie2 + 2, min(ie1[1], ie2[1]));
 169        if (r == 0 && ie1[1] != ie2[1])
 170                return ie2[1] - ie1[1];
 171        return r;
 172}
 173
 174static bool is_bss(struct cfg80211_bss *a,
 175                   const u8 *bssid,
 176                   const u8 *ssid, size_t ssid_len)
 177{
 178        const u8 *ssidie;
 179
 180        if (bssid && compare_ether_addr(a->bssid, bssid))
 181                return false;
 182
 183        if (!ssid)
 184                return true;
 185
 186        ssidie = find_ie(WLAN_EID_SSID,
 187                         a->information_elements,
 188                         a->len_information_elements);
 189        if (!ssidie)
 190                return false;
 191        if (ssidie[1] != ssid_len)
 192                return false;
 193        return memcmp(ssidie + 2, ssid, ssid_len) == 0;
 194}
 195
 196static bool is_mesh(struct cfg80211_bss *a,
 197                    const u8 *meshid, size_t meshidlen,
 198                    const u8 *meshcfg)
 199{
 200        const u8 *ie;
 201
 202        if (!is_zero_ether_addr(a->bssid))
 203                return false;
 204
 205        ie = find_ie(WLAN_EID_MESH_ID,
 206                     a->information_elements,
 207                     a->len_information_elements);
 208        if (!ie)
 209                return false;
 210        if (ie[1] != meshidlen)
 211                return false;
 212        if (memcmp(ie + 2, meshid, meshidlen))
 213                return false;
 214
 215        ie = find_ie(WLAN_EID_MESH_CONFIG,
 216                     a->information_elements,
 217                     a->len_information_elements);
 218        if (!ie)
 219                return false;
 220        if (ie[1] != IEEE80211_MESH_CONFIG_LEN)
 221                return false;
 222
 223        /*
 224         * Ignore mesh capability (last two bytes of the IE) when
 225         * comparing since that may differ between stations taking
 226         * part in the same mesh.
 227         */
 228        return memcmp(ie + 2, meshcfg, IEEE80211_MESH_CONFIG_LEN - 2) == 0;
 229}
 230
 231static int cmp_bss(struct cfg80211_bss *a,
 232                   struct cfg80211_bss *b)
 233{
 234        int r;
 235
 236        if (a->channel != b->channel)
 237                return b->channel->center_freq - a->channel->center_freq;
 238
 239        r = memcmp(a->bssid, b->bssid, ETH_ALEN);
 240        if (r)
 241                return r;
 242
 243        if (is_zero_ether_addr(a->bssid)) {
 244                r = cmp_ies(WLAN_EID_MESH_ID,
 245                            a->information_elements,
 246                            a->len_information_elements,
 247                            b->information_elements,
 248                            b->len_information_elements);
 249                if (r)
 250                        return r;
 251                return cmp_ies(WLAN_EID_MESH_CONFIG,
 252                               a->information_elements,
 253                               a->len_information_elements,
 254                               b->information_elements,
 255                               b->len_information_elements);
 256        }
 257
 258        return cmp_ies(WLAN_EID_SSID,
 259                       a->information_elements,
 260                       a->len_information_elements,
 261                       b->information_elements,
 262                       b->len_information_elements);
 263}
 264
 265struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
 266                                      struct ieee80211_channel *channel,
 267                                      const u8 *bssid,
 268                                      const u8 *ssid, size_t ssid_len,
 269                                      u16 capa_mask, u16 capa_val)
 270{
 271        struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
 272        struct cfg80211_internal_bss *bss, *res = NULL;
 273
 274        spin_lock_bh(&dev->bss_lock);
 275
 276        list_for_each_entry(bss, &dev->bss_list, list) {
 277                if ((bss->pub.capability & capa_mask) != capa_val)
 278                        continue;
 279                if (channel && bss->pub.channel != channel)
 280                        continue;
 281                if (is_bss(&bss->pub, bssid, ssid, ssid_len)) {
 282                        res = bss;
 283                        kref_get(&res->ref);
 284                        break;
 285                }
 286        }
 287
 288        spin_unlock_bh(&dev->bss_lock);
 289        if (!res)
 290                return NULL;
 291        return &res->pub;
 292}
 293EXPORT_SYMBOL(cfg80211_get_bss);
 294
 295struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy,
 296                                       struct ieee80211_channel *channel,
 297                                       const u8 *meshid, size_t meshidlen,
 298                                       const u8 *meshcfg)
 299{
 300        struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
 301        struct cfg80211_internal_bss *bss, *res = NULL;
 302
 303        spin_lock_bh(&dev->bss_lock);
 304
 305        list_for_each_entry(bss, &dev->bss_list, list) {
 306                if (channel && bss->pub.channel != channel)
 307                        continue;
 308                if (is_mesh(&bss->pub, meshid, meshidlen, meshcfg)) {
 309                        res = bss;
 310                        kref_get(&res->ref);
 311                        break;
 312                }
 313        }
 314
 315        spin_unlock_bh(&dev->bss_lock);
 316        if (!res)
 317                return NULL;
 318        return &res->pub;
 319}
 320EXPORT_SYMBOL(cfg80211_get_mesh);
 321
 322
 323static void rb_insert_bss(struct cfg80211_registered_device *dev,
 324                          struct cfg80211_internal_bss *bss)
 325{
 326        struct rb_node **p = &dev->bss_tree.rb_node;
 327        struct rb_node *parent = NULL;
 328        struct cfg80211_internal_bss *tbss;
 329        int cmp;
 330
 331        while (*p) {
 332                parent = *p;
 333                tbss = rb_entry(parent, struct cfg80211_internal_bss, rbn);
 334
 335                cmp = cmp_bss(&bss->pub, &tbss->pub);
 336
 337                if (WARN_ON(!cmp)) {
 338                        /* will sort of leak this BSS */
 339                        return;
 340                }
 341
 342                if (cmp < 0)
 343                        p = &(*p)->rb_left;
 344                else
 345                        p = &(*p)->rb_right;
 346        }
 347
 348        rb_link_node(&bss->rbn, parent, p);
 349        rb_insert_color(&bss->rbn, &dev->bss_tree);
 350}
 351
 352static struct cfg80211_internal_bss *
 353rb_find_bss(struct cfg80211_registered_device *dev,
 354            struct cfg80211_internal_bss *res)
 355{
 356        struct rb_node *n = dev->bss_tree.rb_node;
 357        struct cfg80211_internal_bss *bss;
 358        int r;
 359
 360        while (n) {
 361                bss = rb_entry(n, struct cfg80211_internal_bss, rbn);
 362                r = cmp_bss(&res->pub, &bss->pub);
 363
 364                if (r == 0)
 365                        return bss;
 366                else if (r < 0)
 367                        n = n->rb_left;
 368                else
 369                        n = n->rb_right;
 370        }
 371
 372        return NULL;
 373}
 374
 375static struct cfg80211_internal_bss *
 376cfg80211_bss_update(struct cfg80211_registered_device *dev,
 377                    struct cfg80211_internal_bss *res,
 378                    bool overwrite)
 379{
 380        struct cfg80211_internal_bss *found = NULL;
 381        const u8 *meshid, *meshcfg;
 382
 383        /*
 384         * The reference to "res" is donated to this function.
 385         */
 386
 387        if (WARN_ON(!res->pub.channel)) {
 388                kref_put(&res->ref, bss_release);
 389                return NULL;
 390        }
 391
 392        res->ts = jiffies;
 393
 394        if (is_zero_ether_addr(res->pub.bssid)) {
 395                /* must be mesh, verify */
 396                meshid = find_ie(WLAN_EID_MESH_ID, res->pub.information_elements,
 397                                 res->pub.len_information_elements);
 398                meshcfg = find_ie(WLAN_EID_MESH_CONFIG,
 399                                  res->pub.information_elements,
 400                                  res->pub.len_information_elements);
 401                if (!meshid || !meshcfg ||
 402                    meshcfg[1] != IEEE80211_MESH_CONFIG_LEN) {
 403                        /* bogus mesh */
 404                        kref_put(&res->ref, bss_release);
 405                        return NULL;
 406                }
 407        }
 408
 409        spin_lock_bh(&dev->bss_lock);
 410
 411        found = rb_find_bss(dev, res);
 412
 413        if (found) {
 414                found->pub.beacon_interval = res->pub.beacon_interval;
 415                found->pub.tsf = res->pub.tsf;
 416                found->pub.signal = res->pub.signal;
 417                found->pub.capability = res->pub.capability;
 418                found->ts = res->ts;
 419
 420                /* overwrite IEs */
 421                if (overwrite) {
 422                        size_t used = dev->wiphy.bss_priv_size + sizeof(*res);
 423                        size_t ielen = res->pub.len_information_elements;
 424
 425                        if (!found->ies_allocated && ksize(found) >= used + ielen) {
 426                                memcpy(found->pub.information_elements,
 427                                       res->pub.information_elements, ielen);
 428                                found->pub.len_information_elements = ielen;
 429                        } else {
 430                                u8 *ies = found->pub.information_elements;
 431
 432                                if (found->ies_allocated)
 433                                        ies = krealloc(ies, ielen, GFP_ATOMIC);
 434                                else
 435                                        ies = kmalloc(ielen, GFP_ATOMIC);
 436
 437                                if (ies) {
 438                                        memcpy(ies, res->pub.information_elements, ielen);
 439                                        found->ies_allocated = true;
 440                                        found->pub.information_elements = ies;
 441                                        found->pub.len_information_elements = ielen;
 442                                }
 443                        }
 444                }
 445
 446                kref_put(&res->ref, bss_release);
 447        } else {
 448                /* this "consumes" the reference */
 449                list_add_tail(&res->list, &dev->bss_list);
 450                rb_insert_bss(dev, res);
 451                found = res;
 452        }
 453
 454        dev->bss_generation++;
 455        spin_unlock_bh(&dev->bss_lock);
 456
 457        kref_get(&found->ref);
 458        return found;
 459}
 460
 461struct cfg80211_bss*
 462cfg80211_inform_bss(struct wiphy *wiphy,
 463                    struct ieee80211_channel *channel,
 464                    const u8 *bssid,
 465                    u64 timestamp, u16 capability, u16 beacon_interval,
 466                    const u8 *ie, size_t ielen,
 467                    s32 signal, gfp_t gfp)
 468{
 469        struct cfg80211_internal_bss *res;
 470        size_t privsz;
 471
 472        if (WARN_ON(!wiphy))
 473                return NULL;
 474
 475        privsz = wiphy->bss_priv_size;
 476
 477        if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC &&
 478                        (signal < 0 || signal > 100)))
 479                return NULL;
 480
 481        res = kzalloc(sizeof(*res) + privsz + ielen, gfp);
 482        if (!res)
 483                return NULL;
 484
 485        memcpy(res->pub.bssid, bssid, ETH_ALEN);
 486        res->pub.channel = channel;
 487        res->pub.signal = signal;
 488        res->pub.tsf = timestamp;
 489        res->pub.beacon_interval = beacon_interval;
 490        res->pub.capability = capability;
 491        /* point to after the private area */
 492        res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz;
 493        memcpy(res->pub.information_elements, ie, ielen);
 494        res->pub.len_information_elements = ielen;
 495
 496        kref_init(&res->ref);
 497
 498        res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, 0);
 499        if (!res)
 500                return NULL;
 501
 502        if (res->pub.capability & WLAN_CAPABILITY_ESS)
 503                regulatory_hint_found_beacon(wiphy, channel, gfp);
 504
 505        /* cfg80211_bss_update gives us a referenced result */
 506        return &res->pub;
 507}
 508EXPORT_SYMBOL(cfg80211_inform_bss);
 509
 510struct cfg80211_bss *
 511cfg80211_inform_bss_frame(struct wiphy *wiphy,
 512                          struct ieee80211_channel *channel,
 513                          struct ieee80211_mgmt *mgmt, size_t len,
 514                          s32 signal, gfp_t gfp)
 515{
 516        struct cfg80211_internal_bss *res;
 517        size_t ielen = len - offsetof(struct ieee80211_mgmt,
 518                                      u.probe_resp.variable);
 519        bool overwrite;
 520        size_t privsz = wiphy->bss_priv_size;
 521
 522        if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC &&
 523                    (signal < 0 || signal > 100)))
 524                return NULL;
 525
 526        if (WARN_ON(!mgmt || !wiphy ||
 527                    len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable)))
 528                return NULL;
 529
 530        res = kzalloc(sizeof(*res) + privsz + ielen, gfp);
 531        if (!res)
 532                return NULL;
 533
 534        memcpy(res->pub.bssid, mgmt->bssid, ETH_ALEN);
 535        res->pub.channel = channel;
 536        res->pub.signal = signal;
 537        res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
 538        res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
 539        res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
 540        /* point to after the private area */
 541        res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz;
 542        memcpy(res->pub.information_elements, mgmt->u.probe_resp.variable, ielen);
 543        res->pub.len_information_elements = ielen;
 544
 545        kref_init(&res->ref);
 546
 547        overwrite = ieee80211_is_probe_resp(mgmt->frame_control);
 548
 549        res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, overwrite);
 550        if (!res)
 551                return NULL;
 552
 553        if (res->pub.capability & WLAN_CAPABILITY_ESS)
 554                regulatory_hint_found_beacon(wiphy, channel, gfp);
 555
 556        /* cfg80211_bss_update gives us a referenced result */
 557        return &res->pub;
 558}
 559EXPORT_SYMBOL(cfg80211_inform_bss_frame);
 560
 561void cfg80211_put_bss(struct cfg80211_bss *pub)
 562{
 563        struct cfg80211_internal_bss *bss;
 564
 565        if (!pub)
 566                return;
 567
 568        bss = container_of(pub, struct cfg80211_internal_bss, pub);
 569        kref_put(&bss->ref, bss_release);
 570}
 571EXPORT_SYMBOL(cfg80211_put_bss);
 572
 573void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
 574{
 575        struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
 576        struct cfg80211_internal_bss *bss;
 577
 578        if (WARN_ON(!pub))
 579                return;
 580
 581        bss = container_of(pub, struct cfg80211_internal_bss, pub);
 582
 583        spin_lock_bh(&dev->bss_lock);
 584
 585        list_del(&bss->list);
 586        dev->bss_generation++;
 587        rb_erase(&bss->rbn, &dev->bss_tree);
 588
 589        spin_unlock_bh(&dev->bss_lock);
 590
 591        kref_put(&bss->ref, bss_release);
 592}
 593EXPORT_SYMBOL(cfg80211_unlink_bss);
 594
 595#ifdef CONFIG_WIRELESS_EXT
 596int cfg80211_wext_siwscan(struct net_device *dev,
 597                          struct iw_request_info *info,
 598                          union iwreq_data *wrqu, char *extra)
 599{
 600        struct cfg80211_registered_device *rdev;
 601        struct wiphy *wiphy;
 602        struct iw_scan_req *wreq = NULL;
 603        struct cfg80211_scan_request *creq;
 604        int i, err, n_channels = 0;
 605        enum ieee80211_band band;
 606
 607        if (!netif_running(dev))
 608                return -ENETDOWN;
 609
 610        if (wrqu->data.length == sizeof(struct iw_scan_req))
 611                wreq = (struct iw_scan_req *)extra;
 612
 613        rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex);
 614
 615        if (IS_ERR(rdev))
 616                return PTR_ERR(rdev);
 617
 618        if (rdev->scan_req) {
 619                err = -EBUSY;
 620                goto out;
 621        }
 622
 623        wiphy = &rdev->wiphy;
 624
 625        /* Determine number of channels, needed to allocate creq */
 626        if (wreq && wreq->num_channels)
 627                n_channels = wreq->num_channels;
 628        else {
 629                for (band = 0; band < IEEE80211_NUM_BANDS; band++)
 630                        if (wiphy->bands[band])
 631                                n_channels += wiphy->bands[band]->n_channels;
 632        }
 633
 634        creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) +
 635                       n_channels * sizeof(void *),
 636                       GFP_ATOMIC);
 637        if (!creq) {
 638                err = -ENOMEM;
 639                goto out;
 640        }
 641
 642        creq->wiphy = wiphy;
 643        creq->dev = dev;
 644        /* SSIDs come after channels */
 645        creq->ssids = (void *)&creq->channels[n_channels];
 646        creq->n_channels = n_channels;
 647        creq->n_ssids = 1;
 648
 649        /* translate "Scan on frequencies" request */
 650        i = 0;
 651        for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
 652                int j;
 653                if (!wiphy->bands[band])
 654                        continue;
 655                for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
 656
 657                        /* If we have a wireless request structure and the
 658                         * wireless request specifies frequencies, then search
 659                         * for the matching hardware channel.
 660                         */
 661                        if (wreq && wreq->num_channels) {
 662                                int k;
 663                                int wiphy_freq = wiphy->bands[band]->channels[j].center_freq;
 664                                for (k = 0; k < wreq->num_channels; k++) {
 665                                        int wext_freq = cfg80211_wext_freq(wiphy, &wreq->channel_list[k]);
 666                                        if (wext_freq == wiphy_freq)
 667                                                goto wext_freq_found;
 668                                }
 669                                goto wext_freq_not_found;
 670                        }
 671
 672                wext_freq_found:
 673                        creq->channels[i] = &wiphy->bands[band]->channels[j];
 674                        i++;
 675                wext_freq_not_found: ;
 676                }
 677        }
 678        /* No channels found? */
 679        if (!i) {
 680                err = -EINVAL;
 681                goto out;
 682        }
 683
 684        /* Set real number of channels specified in creq->channels[] */
 685        creq->n_channels = i;
 686
 687        /* translate "Scan for SSID" request */
 688        if (wreq) {
 689                if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
 690                        if (wreq->essid_len > IEEE80211_MAX_SSID_LEN)
 691                                return -EINVAL;
 692                        memcpy(creq->ssids[0].ssid, wreq->essid, wreq->essid_len);
 693                        creq->ssids[0].ssid_len = wreq->essid_len;
 694                }
 695                if (wreq->scan_type == IW_SCAN_TYPE_PASSIVE)
 696                        creq->n_ssids = 0;
 697        }
 698
 699        rdev->scan_req = creq;
 700        err = rdev->ops->scan(wiphy, dev, creq);
 701        if (err) {
 702                rdev->scan_req = NULL;
 703                kfree(creq);
 704        } else {
 705                nl80211_send_scan_start(rdev, dev);
 706                dev_hold(dev);
 707        }
 708 out:
 709        cfg80211_unlock_rdev(rdev);
 710        return err;
 711}
 712EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan);
 713
 714static void ieee80211_scan_add_ies(struct iw_request_info *info,
 715                                   struct cfg80211_bss *bss,
 716                                   char **current_ev, char *end_buf)
 717{
 718        u8 *pos, *end, *next;
 719        struct iw_event iwe;
 720
 721        if (!bss->information_elements ||
 722            !bss->len_information_elements)
 723                return;
 724
 725        /*
 726         * If needed, fragment the IEs buffer (at IE boundaries) into short
 727         * enough fragments to fit into IW_GENERIC_IE_MAX octet messages.
 728         */
 729        pos = bss->information_elements;
 730        end = pos + bss->len_information_elements;
 731
 732        while (end - pos > IW_GENERIC_IE_MAX) {
 733                next = pos + 2 + pos[1];
 734                while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX)
 735                        next = next + 2 + next[1];
 736
 737                memset(&iwe, 0, sizeof(iwe));
 738                iwe.cmd = IWEVGENIE;
 739                iwe.u.data.length = next - pos;
 740                *current_ev = iwe_stream_add_point(info, *current_ev,
 741                                                   end_buf, &iwe, pos);
 742
 743                pos = next;
 744        }
 745
 746        if (end > pos) {
 747                memset(&iwe, 0, sizeof(iwe));
 748                iwe.cmd = IWEVGENIE;
 749                iwe.u.data.length = end - pos;
 750                *current_ev = iwe_stream_add_point(info, *current_ev,
 751                                                   end_buf, &iwe, pos);
 752        }
 753}
 754
 755static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
 756{
 757        unsigned long end = jiffies;
 758
 759        if (end >= start)
 760                return jiffies_to_msecs(end - start);
 761
 762        return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1);
 763}
 764
 765static char *
 766ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
 767              struct cfg80211_internal_bss *bss, char *current_ev,
 768              char *end_buf)
 769{
 770        struct iw_event iwe;
 771        u8 *buf, *cfg, *p;
 772        u8 *ie = bss->pub.information_elements;
 773        int rem = bss->pub.len_information_elements, i, sig;
 774        bool ismesh = false;
 775
 776        memset(&iwe, 0, sizeof(iwe));
 777        iwe.cmd = SIOCGIWAP;
 778        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 779        memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN);
 780        current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
 781                                          IW_EV_ADDR_LEN);
 782
 783        memset(&iwe, 0, sizeof(iwe));
 784        iwe.cmd = SIOCGIWFREQ;
 785        iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq);
 786        iwe.u.freq.e = 0;
 787        current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
 788                                          IW_EV_FREQ_LEN);
 789
 790        memset(&iwe, 0, sizeof(iwe));
 791        iwe.cmd = SIOCGIWFREQ;
 792        iwe.u.freq.m = bss->pub.channel->center_freq;
 793        iwe.u.freq.e = 6;
 794        current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
 795                                          IW_EV_FREQ_LEN);
 796
 797        if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) {
 798                memset(&iwe, 0, sizeof(iwe));
 799                iwe.cmd = IWEVQUAL;
 800                iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED |
 801                                     IW_QUAL_NOISE_INVALID |
 802                                     IW_QUAL_QUAL_UPDATED;
 803                switch (wiphy->signal_type) {
 804                case CFG80211_SIGNAL_TYPE_MBM:
 805                        sig = bss->pub.signal / 100;
 806                        iwe.u.qual.level = sig;
 807                        iwe.u.qual.updated |= IW_QUAL_DBM;
 808                        if (sig < -110)         /* rather bad */
 809                                sig = -110;
 810                        else if (sig > -40)     /* perfect */
 811                                sig = -40;
 812                        /* will give a range of 0 .. 70 */
 813                        iwe.u.qual.qual = sig + 110;
 814                        break;
 815                case CFG80211_SIGNAL_TYPE_UNSPEC:
 816                        iwe.u.qual.level = bss->pub.signal;
 817                        /* will give range 0 .. 100 */
 818                        iwe.u.qual.qual = bss->pub.signal;
 819                        break;
 820                default:
 821                        /* not reached */
 822                        break;
 823                }
 824                current_ev = iwe_stream_add_event(info, current_ev, end_buf,
 825                                                  &iwe, IW_EV_QUAL_LEN);
 826        }
 827
 828        memset(&iwe, 0, sizeof(iwe));
 829        iwe.cmd = SIOCGIWENCODE;
 830        if (bss->pub.capability & WLAN_CAPABILITY_PRIVACY)
 831                iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
 832        else
 833                iwe.u.data.flags = IW_ENCODE_DISABLED;
 834        iwe.u.data.length = 0;
 835        current_ev = iwe_stream_add_point(info, current_ev, end_buf,
 836                                          &iwe, "");
 837
 838        while (rem >= 2) {
 839                /* invalid data */
 840                if (ie[1] > rem - 2)
 841                        break;
 842
 843                switch (ie[0]) {
 844                case WLAN_EID_SSID:
 845                        memset(&iwe, 0, sizeof(iwe));
 846                        iwe.cmd = SIOCGIWESSID;
 847                        iwe.u.data.length = ie[1];
 848                        iwe.u.data.flags = 1;
 849                        current_ev = iwe_stream_add_point(info, current_ev, end_buf,
 850                                                          &iwe, ie + 2);
 851                        break;
 852                case WLAN_EID_MESH_ID:
 853                        memset(&iwe, 0, sizeof(iwe));
 854                        iwe.cmd = SIOCGIWESSID;
 855                        iwe.u.data.length = ie[1];
 856                        iwe.u.data.flags = 1;
 857                        current_ev = iwe_stream_add_point(info, current_ev, end_buf,
 858                                                          &iwe, ie + 2);
 859                        break;
 860                case WLAN_EID_MESH_CONFIG:
 861                        ismesh = true;
 862                        if (ie[1] != IEEE80211_MESH_CONFIG_LEN)
 863                                break;
 864                        buf = kmalloc(50, GFP_ATOMIC);
 865                        if (!buf)
 866                                break;
 867                        cfg = ie + 2;
 868                        memset(&iwe, 0, sizeof(iwe));
 869                        iwe.cmd = IWEVCUSTOM;
 870                        sprintf(buf, "Mesh network (version %d)", cfg[0]);
 871                        iwe.u.data.length = strlen(buf);
 872                        current_ev = iwe_stream_add_point(info, current_ev,
 873                                                          end_buf,
 874                                                          &iwe, buf);
 875                        sprintf(buf, "Path Selection Protocol ID: "
 876                                "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
 877                                                        cfg[4]);
 878                        iwe.u.data.length = strlen(buf);
 879                        current_ev = iwe_stream_add_point(info, current_ev,
 880                                                          end_buf,
 881                                                          &iwe, buf);
 882                        sprintf(buf, "Path Selection Metric ID: "
 883                                "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
 884                                                        cfg[8]);
 885                        iwe.u.data.length = strlen(buf);
 886                        current_ev = iwe_stream_add_point(info, current_ev,
 887                                                          end_buf,
 888                                                          &iwe, buf);
 889                        sprintf(buf, "Congestion Control Mode ID: "
 890                                "0x%02X%02X%02X%02X", cfg[9], cfg[10],
 891                                                        cfg[11], cfg[12]);
 892                        iwe.u.data.length = strlen(buf);
 893                        current_ev = iwe_stream_add_point(info, current_ev,
 894                                                          end_buf,
 895                                                          &iwe, buf);
 896                        sprintf(buf, "Channel Precedence: "
 897                                "0x%02X%02X%02X%02X", cfg[13], cfg[14],
 898                                                        cfg[15], cfg[16]);
 899                        iwe.u.data.length = strlen(buf);
 900                        current_ev = iwe_stream_add_point(info, current_ev,
 901                                                          end_buf,
 902                                                          &iwe, buf);
 903                        kfree(buf);
 904                        break;
 905                case WLAN_EID_SUPP_RATES:
 906                case WLAN_EID_EXT_SUPP_RATES:
 907                        /* display all supported rates in readable format */
 908                        p = current_ev + iwe_stream_lcp_len(info);
 909
 910                        memset(&iwe, 0, sizeof(iwe));
 911                        iwe.cmd = SIOCGIWRATE;
 912                        /* Those two flags are ignored... */
 913                        iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
 914
 915                        for (i = 0; i < ie[1]; i++) {
 916                                iwe.u.bitrate.value =
 917                                        ((ie[i + 2] & 0x7f) * 500000);
 918                                p = iwe_stream_add_value(info, current_ev, p,
 919                                                end_buf, &iwe, IW_EV_PARAM_LEN);
 920                        }
 921                        current_ev = p;
 922                        break;
 923                }
 924                rem -= ie[1] + 2;
 925                ie += ie[1] + 2;
 926        }
 927
 928        if (bss->pub.capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)
 929            || ismesh) {
 930                memset(&iwe, 0, sizeof(iwe));
 931                iwe.cmd = SIOCGIWMODE;
 932                if (ismesh)
 933                        iwe.u.mode = IW_MODE_MESH;
 934                else if (bss->pub.capability & WLAN_CAPABILITY_ESS)
 935                        iwe.u.mode = IW_MODE_MASTER;
 936                else
 937                        iwe.u.mode = IW_MODE_ADHOC;
 938                current_ev = iwe_stream_add_event(info, current_ev, end_buf,
 939                                                  &iwe, IW_EV_UINT_LEN);
 940        }
 941
 942        buf = kmalloc(30, GFP_ATOMIC);
 943        if (buf) {
 944                memset(&iwe, 0, sizeof(iwe));
 945                iwe.cmd = IWEVCUSTOM;
 946                sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->pub.tsf));
 947                iwe.u.data.length = strlen(buf);
 948                current_ev = iwe_stream_add_point(info, current_ev, end_buf,
 949                                                  &iwe, buf);
 950                memset(&iwe, 0, sizeof(iwe));
 951                iwe.cmd = IWEVCUSTOM;
 952                sprintf(buf, " Last beacon: %ums ago",
 953                        elapsed_jiffies_msecs(bss->ts));
 954                iwe.u.data.length = strlen(buf);
 955                current_ev = iwe_stream_add_point(info, current_ev,
 956                                                  end_buf, &iwe, buf);
 957                kfree(buf);
 958        }
 959
 960        ieee80211_scan_add_ies(info, &bss->pub, &current_ev, end_buf);
 961
 962        return current_ev;
 963}
 964
 965
 966static int ieee80211_scan_results(struct cfg80211_registered_device *dev,
 967                                  struct iw_request_info *info,
 968                                  char *buf, size_t len)
 969{
 970        char *current_ev = buf;
 971        char *end_buf = buf + len;
 972        struct cfg80211_internal_bss *bss;
 973
 974        spin_lock_bh(&dev->bss_lock);
 975        cfg80211_bss_expire(dev);
 976
 977        list_for_each_entry(bss, &dev->bss_list, list) {
 978                if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
 979                        spin_unlock_bh(&dev->bss_lock);
 980                        return -E2BIG;
 981                }
 982                current_ev = ieee80211_bss(&dev->wiphy, info, bss,
 983                                           current_ev, end_buf);
 984        }
 985        spin_unlock_bh(&dev->bss_lock);
 986        return current_ev - buf;
 987}
 988
 989
 990int cfg80211_wext_giwscan(struct net_device *dev,
 991                          struct iw_request_info *info,
 992                          struct iw_point *data, char *extra)
 993{
 994        struct cfg80211_registered_device *rdev;
 995        int res;
 996
 997        if (!netif_running(dev))
 998                return -ENETDOWN;
 999
1000        rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex);
1001
1002        if (IS_ERR(rdev))
1003                return PTR_ERR(rdev);
1004
1005        if (rdev->scan_req) {
1006                res = -EAGAIN;
1007                goto out;
1008        }
1009
1010        res = ieee80211_scan_results(rdev, info, extra, data->length);
1011        data->length = 0;
1012        if (res >= 0) {
1013                data->length = res;
1014                res = 0;
1015        }
1016
1017 out:
1018        cfg80211_unlock_rdev(rdev);
1019        return res;
1020}
1021EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan);
1022#endif
1023