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/slab.h>
   8#include <linux/module.h>
   9#include <linux/netdevice.h>
  10#include <linux/wireless.h>
  11#include <linux/nl80211.h>
  12#include <linux/etherdevice.h>
  13#include <net/arp.h>
  14#include <net/cfg80211.h>
  15#include <net/cfg80211-wext.h>
  16#include <net/iw_handler.h>
  17#include "core.h"
  18#include "nl80211.h"
  19#include "wext-compat.h"
  20
  21#define IEEE80211_SCAN_RESULT_EXPIRE    (30 * HZ)
  22
  23void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
  24{
  25        struct cfg80211_scan_request *request;
  26        struct wireless_dev *wdev;
  27#ifdef CONFIG_CFG80211_WEXT
  28        union iwreq_data wrqu;
  29#endif
  30
  31        ASSERT_RDEV_LOCK(rdev);
  32
  33        request = rdev->scan_req;
  34
  35        if (!request)
  36                return;
  37
  38        wdev = request->wdev;
  39
  40        /*
  41         * This must be before sending the other events!
  42         * Otherwise, wpa_supplicant gets completely confused with
  43         * wext events.
  44         */
  45        if (wdev->netdev)
  46                cfg80211_sme_scan_done(wdev->netdev);
  47
  48        if (request->aborted)
  49                nl80211_send_scan_aborted(rdev, wdev);
  50        else
  51                nl80211_send_scan_done(rdev, wdev);
  52
  53#ifdef CONFIG_CFG80211_WEXT
  54        if (wdev->netdev && !request->aborted) {
  55                memset(&wrqu, 0, sizeof(wrqu));
  56
  57                wireless_send_event(wdev->netdev, SIOCGIWSCAN, &wrqu, NULL);
  58        }
  59#endif
  60
  61        if (wdev->netdev)
  62                dev_put(wdev->netdev);
  63
  64        rdev->scan_req = NULL;
  65
  66        /*
  67         * OK. If this is invoked with "leak" then we can't
  68         * free this ... but we've cleaned it up anyway. The
  69         * driver failed to call the scan_done callback, so
  70         * all bets are off, it might still be trying to use
  71         * the scan request or not ... if it accesses the dev
  72         * in there (it shouldn't anyway) then it may crash.
  73         */
  74        if (!leak)
  75                kfree(request);
  76}
  77
  78void __cfg80211_scan_done(struct work_struct *wk)
  79{
  80        struct cfg80211_registered_device *rdev;
  81
  82        rdev = container_of(wk, struct cfg80211_registered_device,
  83                            scan_done_wk);
  84
  85        cfg80211_lock_rdev(rdev);
  86        ___cfg80211_scan_done(rdev, false);
  87        cfg80211_unlock_rdev(rdev);
  88}
  89
  90void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
  91{
  92        WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
  93
  94        request->aborted = aborted;
  95        queue_work(cfg80211_wq, &wiphy_to_dev(request->wiphy)->scan_done_wk);
  96}
  97EXPORT_SYMBOL(cfg80211_scan_done);
  98
  99void __cfg80211_sched_scan_results(struct work_struct *wk)
 100{
 101        struct cfg80211_registered_device *rdev;
 102
 103        rdev = container_of(wk, struct cfg80211_registered_device,
 104                            sched_scan_results_wk);
 105
 106        mutex_lock(&rdev->sched_scan_mtx);
 107
 108        /* we don't have sched_scan_req anymore if the scan is stopping */
 109        if (rdev->sched_scan_req)
 110                nl80211_send_sched_scan_results(rdev,
 111                                                rdev->sched_scan_req->dev);
 112
 113        mutex_unlock(&rdev->sched_scan_mtx);
 114}
 115
 116void cfg80211_sched_scan_results(struct wiphy *wiphy)
 117{
 118        /* ignore if we're not scanning */
 119        if (wiphy_to_dev(wiphy)->sched_scan_req)
 120                queue_work(cfg80211_wq,
 121                           &wiphy_to_dev(wiphy)->sched_scan_results_wk);
 122}
 123EXPORT_SYMBOL(cfg80211_sched_scan_results);
 124
 125void cfg80211_sched_scan_stopped(struct wiphy *wiphy)
 126{
 127        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 128
 129        mutex_lock(&rdev->sched_scan_mtx);
 130        __cfg80211_stop_sched_scan(rdev, true);
 131        mutex_unlock(&rdev->sched_scan_mtx);
 132}
 133EXPORT_SYMBOL(cfg80211_sched_scan_stopped);
 134
 135int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
 136                               bool driver_initiated)
 137{
 138        struct net_device *dev;
 139
 140        lockdep_assert_held(&rdev->sched_scan_mtx);
 141
 142        if (!rdev->sched_scan_req)
 143                return -ENOENT;
 144
 145        dev = rdev->sched_scan_req->dev;
 146
 147        if (!driver_initiated) {
 148                int err = rdev->ops->sched_scan_stop(&rdev->wiphy, dev);
 149                if (err)
 150                        return err;
 151        }
 152
 153        nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED);
 154
 155        kfree(rdev->sched_scan_req);
 156        rdev->sched_scan_req = NULL;
 157
 158        return 0;
 159}
 160
 161static void bss_release(struct kref *ref)
 162{
 163        struct cfg80211_internal_bss *bss;
 164
 165        bss = container_of(ref, struct cfg80211_internal_bss, ref);
 166        if (bss->pub.free_priv)
 167                bss->pub.free_priv(&bss->pub);
 168
 169        if (bss->beacon_ies_allocated)
 170                kfree(bss->pub.beacon_ies);
 171        if (bss->proberesp_ies_allocated)
 172                kfree(bss->pub.proberesp_ies);
 173
 174        BUG_ON(atomic_read(&bss->hold));
 175
 176        kfree(bss);
 177}
 178
 179/* must hold dev->bss_lock! */
 180void cfg80211_bss_age(struct cfg80211_registered_device *dev,
 181                      unsigned long age_secs)
 182{
 183        struct cfg80211_internal_bss *bss;
 184        unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC);
 185
 186        list_for_each_entry(bss, &dev->bss_list, list) {
 187                bss->ts -= age_jiffies;
 188        }
 189}
 190
 191/* must hold dev->bss_lock! */
 192static void __cfg80211_unlink_bss(struct cfg80211_registered_device *dev,
 193                                  struct cfg80211_internal_bss *bss)
 194{
 195        list_del_init(&bss->list);
 196        rb_erase(&bss->rbn, &dev->bss_tree);
 197        kref_put(&bss->ref, bss_release);
 198}
 199
 200/* must hold dev->bss_lock! */
 201void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
 202{
 203        struct cfg80211_internal_bss *bss, *tmp;
 204        bool expired = false;
 205
 206        list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
 207                if (atomic_read(&bss->hold))
 208                        continue;
 209                if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
 210                        continue;
 211                __cfg80211_unlink_bss(dev, bss);
 212                expired = true;
 213        }
 214
 215        if (expired)
 216                dev->bss_generation++;
 217}
 218
 219const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len)
 220{
 221        while (len > 2 && ies[0] != eid) {
 222                len -= ies[1] + 2;
 223                ies += ies[1] + 2;
 224        }
 225        if (len < 2)
 226                return NULL;
 227        if (len < 2 + ies[1])
 228                return NULL;
 229        return ies;
 230}
 231EXPORT_SYMBOL(cfg80211_find_ie);
 232
 233const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type,
 234                                  const u8 *ies, int len)
 235{
 236        struct ieee80211_vendor_ie *ie;
 237        const u8 *pos = ies, *end = ies + len;
 238        int ie_oui;
 239
 240        while (pos < end) {
 241                pos = cfg80211_find_ie(WLAN_EID_VENDOR_SPECIFIC, pos,
 242                                       end - pos);
 243                if (!pos)
 244                        return NULL;
 245
 246                if (end - pos < sizeof(*ie))
 247                        return NULL;
 248
 249                ie = (struct ieee80211_vendor_ie *)pos;
 250                ie_oui = ie->oui[0] << 16 | ie->oui[1] << 8 | ie->oui[2];
 251                if (ie_oui == oui && ie->oui_type == oui_type)
 252                        return pos;
 253
 254                pos += 2 + ie->len;
 255        }
 256        return NULL;
 257}
 258EXPORT_SYMBOL(cfg80211_find_vendor_ie);
 259
 260static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2)
 261{
 262        const u8 *ie1 = cfg80211_find_ie(num, ies1, len1);
 263        const u8 *ie2 = cfg80211_find_ie(num, ies2, len2);
 264
 265        /* equal if both missing */
 266        if (!ie1 && !ie2)
 267                return 0;
 268        /* sort missing IE before (left of) present IE */
 269        if (!ie1)
 270                return -1;
 271        if (!ie2)
 272                return 1;
 273
 274        /* sort by length first, then by contents */
 275        if (ie1[1] != ie2[1])
 276                return ie2[1] - ie1[1];
 277        return memcmp(ie1 + 2, ie2 + 2, ie1[1]);
 278}
 279
 280static bool is_bss(struct cfg80211_bss *a,
 281                   const u8 *bssid,
 282                   const u8 *ssid, size_t ssid_len)
 283{
 284        const u8 *ssidie;
 285
 286        if (bssid && !ether_addr_equal(a->bssid, bssid))
 287                return false;
 288
 289        if (!ssid)
 290                return true;
 291
 292        ssidie = cfg80211_find_ie(WLAN_EID_SSID,
 293                                  a->information_elements,
 294                                  a->len_information_elements);
 295        if (!ssidie)
 296                return false;
 297        if (ssidie[1] != ssid_len)
 298                return false;
 299        return memcmp(ssidie + 2, ssid, ssid_len) == 0;
 300}
 301
 302static bool is_mesh_bss(struct cfg80211_bss *a)
 303{
 304        const u8 *ie;
 305
 306        if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability))
 307                return false;
 308
 309        ie = cfg80211_find_ie(WLAN_EID_MESH_ID,
 310                              a->information_elements,
 311                              a->len_information_elements);
 312        if (!ie)
 313                return false;
 314
 315        ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG,
 316                              a->information_elements,
 317                              a->len_information_elements);
 318        if (!ie)
 319                return false;
 320
 321        return true;
 322}
 323
 324static bool is_mesh(struct cfg80211_bss *a,
 325                    const u8 *meshid, size_t meshidlen,
 326                    const u8 *meshcfg)
 327{
 328        const u8 *ie;
 329
 330        if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability))
 331                return false;
 332
 333        ie = cfg80211_find_ie(WLAN_EID_MESH_ID,
 334                              a->information_elements,
 335                              a->len_information_elements);
 336        if (!ie)
 337                return false;
 338        if (ie[1] != meshidlen)
 339                return false;
 340        if (memcmp(ie + 2, meshid, meshidlen))
 341                return false;
 342
 343        ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG,
 344                              a->information_elements,
 345                              a->len_information_elements);
 346        if (!ie)
 347                return false;
 348        if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
 349                return false;
 350
 351        /*
 352         * Ignore mesh capability (last two bytes of the IE) when
 353         * comparing since that may differ between stations taking
 354         * part in the same mesh.
 355         */
 356        return memcmp(ie + 2, meshcfg,
 357            sizeof(struct ieee80211_meshconf_ie) - 2) == 0;
 358}
 359
 360static int cmp_bss_core(struct cfg80211_bss *a,
 361                        struct cfg80211_bss *b)
 362{
 363        int r;
 364
 365        if (a->channel != b->channel)
 366                return b->channel->center_freq - a->channel->center_freq;
 367
 368        if (is_mesh_bss(a) && is_mesh_bss(b)) {
 369                r = cmp_ies(WLAN_EID_MESH_ID,
 370                            a->information_elements,
 371                            a->len_information_elements,
 372                            b->information_elements,
 373                            b->len_information_elements);
 374                if (r)
 375                        return r;
 376                return cmp_ies(WLAN_EID_MESH_CONFIG,
 377                               a->information_elements,
 378                               a->len_information_elements,
 379                               b->information_elements,
 380                               b->len_information_elements);
 381        }
 382
 383        /*
 384         * we can't use compare_ether_addr here since we need a < > operator.
 385         * The binary return value of compare_ether_addr isn't enough
 386         */
 387        return memcmp(a->bssid, b->bssid, sizeof(a->bssid));
 388}
 389
 390static int cmp_bss(struct cfg80211_bss *a,
 391                   struct cfg80211_bss *b)
 392{
 393        int r;
 394
 395        r = cmp_bss_core(a, b);
 396        if (r)
 397                return r;
 398
 399        return cmp_ies(WLAN_EID_SSID,
 400                       a->information_elements,
 401                       a->len_information_elements,
 402                       b->information_elements,
 403                       b->len_information_elements);
 404}
 405
 406static int cmp_hidden_bss(struct cfg80211_bss *a,
 407                   struct cfg80211_bss *b)
 408{
 409        const u8 *ie1;
 410        const u8 *ie2;
 411        int i;
 412        int r;
 413
 414        r = cmp_bss_core(a, b);
 415        if (r)
 416                return r;
 417
 418        ie1 = cfg80211_find_ie(WLAN_EID_SSID,
 419                        a->information_elements,
 420                        a->len_information_elements);
 421        ie2 = cfg80211_find_ie(WLAN_EID_SSID,
 422                        b->information_elements,
 423                        b->len_information_elements);
 424
 425        /* Key comparator must use same algorithm in any rb-tree
 426         * search function (order is important), otherwise ordering
 427         * of items in the tree is broken and search gives incorrect
 428         * results. This code uses same order as cmp_ies() does. */
 429
 430        /* sort missing IE before (left of) present IE */
 431        if (!ie1)
 432                return -1;
 433        if (!ie2)
 434                return 1;
 435
 436        /* zero-size SSID is used as an indication of the hidden bss */
 437        if (!ie2[1])
 438                return 0;
 439
 440        /* sort by length first, then by contents */
 441        if (ie1[1] != ie2[1])
 442                return ie2[1] - ie1[1];
 443
 444        /* zeroed SSID ie is another indication of a hidden bss */
 445        for (i = 0; i < ie2[1]; i++)
 446                if (ie2[i + 2])
 447                        return -1;
 448
 449        return 0;
 450}
 451
 452struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
 453                                      struct ieee80211_channel *channel,
 454                                      const u8 *bssid,
 455                                      const u8 *ssid, size_t ssid_len,
 456                                      u16 capa_mask, u16 capa_val)
 457{
 458        struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
 459        struct cfg80211_internal_bss *bss, *res = NULL;
 460        unsigned long now = jiffies;
 461
 462        spin_lock_bh(&dev->bss_lock);
 463
 464        list_for_each_entry(bss, &dev->bss_list, list) {
 465                if ((bss->pub.capability & capa_mask) != capa_val)
 466                        continue;
 467                if (channel && bss->pub.channel != channel)
 468                        continue;
 469                /* Don't get expired BSS structs */
 470                if (time_after(now, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE) &&
 471                    !atomic_read(&bss->hold))
 472                        continue;
 473                if (is_bss(&bss->pub, bssid, ssid, ssid_len)) {
 474                        res = bss;
 475                        kref_get(&res->ref);
 476                        break;
 477                }
 478        }
 479
 480        spin_unlock_bh(&dev->bss_lock);
 481        if (!res)
 482                return NULL;
 483        return &res->pub;
 484}
 485EXPORT_SYMBOL(cfg80211_get_bss);
 486
 487struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy,
 488                                       struct ieee80211_channel *channel,
 489                                       const u8 *meshid, size_t meshidlen,
 490                                       const u8 *meshcfg)
 491{
 492        struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
 493        struct cfg80211_internal_bss *bss, *res = NULL;
 494
 495        spin_lock_bh(&dev->bss_lock);
 496
 497        list_for_each_entry(bss, &dev->bss_list, list) {
 498                if (channel && bss->pub.channel != channel)
 499                        continue;
 500                if (is_mesh(&bss->pub, meshid, meshidlen, meshcfg)) {
 501                        res = bss;
 502                        kref_get(&res->ref);
 503                        break;
 504                }
 505        }
 506
 507        spin_unlock_bh(&dev->bss_lock);
 508        if (!res)
 509                return NULL;
 510        return &res->pub;
 511}
 512EXPORT_SYMBOL(cfg80211_get_mesh);
 513
 514
 515static void rb_insert_bss(struct cfg80211_registered_device *dev,
 516                          struct cfg80211_internal_bss *bss)
 517{
 518        struct rb_node **p = &dev->bss_tree.rb_node;
 519        struct rb_node *parent = NULL;
 520        struct cfg80211_internal_bss *tbss;
 521        int cmp;
 522
 523        while (*p) {
 524                parent = *p;
 525                tbss = rb_entry(parent, struct cfg80211_internal_bss, rbn);
 526
 527                cmp = cmp_bss(&bss->pub, &tbss->pub);
 528
 529                if (WARN_ON(!cmp)) {
 530                        /* will sort of leak this BSS */
 531                        return;
 532                }
 533
 534                if (cmp < 0)
 535                        p = &(*p)->rb_left;
 536                else
 537                        p = &(*p)->rb_right;
 538        }
 539
 540        rb_link_node(&bss->rbn, parent, p);
 541        rb_insert_color(&bss->rbn, &dev->bss_tree);
 542}
 543
 544static struct cfg80211_internal_bss *
 545rb_find_bss(struct cfg80211_registered_device *dev,
 546            struct cfg80211_internal_bss *res)
 547{
 548        struct rb_node *n = dev->bss_tree.rb_node;
 549        struct cfg80211_internal_bss *bss;
 550        int r;
 551
 552        while (n) {
 553                bss = rb_entry(n, struct cfg80211_internal_bss, rbn);
 554                r = cmp_bss(&res->pub, &bss->pub);
 555
 556                if (r == 0)
 557                        return bss;
 558                else if (r < 0)
 559                        n = n->rb_left;
 560                else
 561                        n = n->rb_right;
 562        }
 563
 564        return NULL;
 565}
 566
 567static struct cfg80211_internal_bss *
 568rb_find_hidden_bss(struct cfg80211_registered_device *dev,
 569            struct cfg80211_internal_bss *res)
 570{
 571        struct rb_node *n = dev->bss_tree.rb_node;
 572        struct cfg80211_internal_bss *bss;
 573        int r;
 574
 575        while (n) {
 576                bss = rb_entry(n, struct cfg80211_internal_bss, rbn);
 577                r = cmp_hidden_bss(&res->pub, &bss->pub);
 578
 579                if (r == 0)
 580                        return bss;
 581                else if (r < 0)
 582                        n = n->rb_left;
 583                else
 584                        n = n->rb_right;
 585        }
 586
 587        return NULL;
 588}
 589
 590static void
 591copy_hidden_ies(struct cfg80211_internal_bss *res,
 592                 struct cfg80211_internal_bss *hidden)
 593{
 594        if (unlikely(res->pub.beacon_ies))
 595                return;
 596        if (WARN_ON(!hidden->pub.beacon_ies))
 597                return;
 598
 599        res->pub.beacon_ies = kmalloc(hidden->pub.len_beacon_ies, GFP_ATOMIC);
 600        if (unlikely(!res->pub.beacon_ies))
 601                return;
 602
 603        res->beacon_ies_allocated = true;
 604        res->pub.len_beacon_ies = hidden->pub.len_beacon_ies;
 605        memcpy(res->pub.beacon_ies, hidden->pub.beacon_ies,
 606                        res->pub.len_beacon_ies);
 607}
 608
 609static struct cfg80211_internal_bss *
 610cfg80211_bss_update(struct cfg80211_registered_device *dev,
 611                    struct cfg80211_internal_bss *res)
 612{
 613        struct cfg80211_internal_bss *found = NULL;
 614
 615        /*
 616         * The reference to "res" is donated to this function.
 617         */
 618
 619        if (WARN_ON(!res->pub.channel)) {
 620                kref_put(&res->ref, bss_release);
 621                return NULL;
 622        }
 623
 624        res->ts = jiffies;
 625
 626        spin_lock_bh(&dev->bss_lock);
 627
 628        found = rb_find_bss(dev, res);
 629
 630        if (found) {
 631                found->pub.beacon_interval = res->pub.beacon_interval;
 632                found->pub.tsf = res->pub.tsf;
 633                found->pub.signal = res->pub.signal;
 634                found->pub.capability = res->pub.capability;
 635                found->ts = res->ts;
 636
 637                /* Update IEs */
 638                if (res->pub.proberesp_ies) {
 639                        size_t used = dev->wiphy.bss_priv_size + sizeof(*res);
 640                        size_t ielen = res->pub.len_proberesp_ies;
 641
 642                        if (found->pub.proberesp_ies &&
 643                            !found->proberesp_ies_allocated &&
 644                            ksize(found) >= used + ielen) {
 645                                memcpy(found->pub.proberesp_ies,
 646                                       res->pub.proberesp_ies, ielen);
 647                                found->pub.len_proberesp_ies = ielen;
 648                        } else {
 649                                u8 *ies = found->pub.proberesp_ies;
 650
 651                                if (found->proberesp_ies_allocated)
 652                                        ies = krealloc(ies, ielen, GFP_ATOMIC);
 653                                else
 654                                        ies = kmalloc(ielen, GFP_ATOMIC);
 655
 656                                if (ies) {
 657                                        memcpy(ies, res->pub.proberesp_ies,
 658                                               ielen);
 659                                        found->proberesp_ies_allocated = true;
 660                                        found->pub.proberesp_ies = ies;
 661                                        found->pub.len_proberesp_ies = ielen;
 662                                }
 663                        }
 664
 665                        /* Override possible earlier Beacon frame IEs */
 666                        found->pub.information_elements =
 667                                found->pub.proberesp_ies;
 668                        found->pub.len_information_elements =
 669                                found->pub.len_proberesp_ies;
 670                }
 671                if (res->pub.beacon_ies) {
 672                        size_t used = dev->wiphy.bss_priv_size + sizeof(*res);
 673                        size_t ielen = res->pub.len_beacon_ies;
 674                        bool information_elements_is_beacon_ies =
 675                                (found->pub.information_elements ==
 676                                 found->pub.beacon_ies);
 677
 678                        if (found->pub.beacon_ies &&
 679                            !found->beacon_ies_allocated &&
 680                            ksize(found) >= used + ielen) {
 681                                memcpy(found->pub.beacon_ies,
 682                                       res->pub.beacon_ies, ielen);
 683                                found->pub.len_beacon_ies = ielen;
 684                        } else {
 685                                u8 *ies = found->pub.beacon_ies;
 686
 687                                if (found->beacon_ies_allocated)
 688                                        ies = krealloc(ies, ielen, GFP_ATOMIC);
 689                                else
 690                                        ies = kmalloc(ielen, GFP_ATOMIC);
 691
 692                                if (ies) {
 693                                        memcpy(ies, res->pub.beacon_ies,
 694                                               ielen);
 695                                        found->beacon_ies_allocated = true;
 696                                        found->pub.beacon_ies = ies;
 697                                        found->pub.len_beacon_ies = ielen;
 698                                }
 699                        }
 700
 701                        /* Override IEs if they were from a beacon before */
 702                        if (information_elements_is_beacon_ies) {
 703                                found->pub.information_elements =
 704                                        found->pub.beacon_ies;
 705                                found->pub.len_information_elements =
 706                                        found->pub.len_beacon_ies;
 707                        }
 708                }
 709
 710                kref_put(&res->ref, bss_release);
 711        } else {
 712                struct cfg80211_internal_bss *hidden;
 713
 714                /* First check if the beacon is a probe response from
 715                 * a hidden bss. If so, copy beacon ies (with nullified
 716                 * ssid) into the probe response bss entry (with real ssid).
 717                 * It is required basically for PSM implementation
 718                 * (probe responses do not contain tim ie) */
 719
 720                /* TODO: The code is not trying to update existing probe
 721                 * response bss entries when beacon ies are
 722                 * getting changed. */
 723                hidden = rb_find_hidden_bss(dev, res);
 724                if (hidden)
 725                        copy_hidden_ies(res, hidden);
 726
 727                /* this "consumes" the reference */
 728                list_add_tail(&res->list, &dev->bss_list);
 729                rb_insert_bss(dev, res);
 730                found = res;
 731        }
 732
 733        dev->bss_generation++;
 734        spin_unlock_bh(&dev->bss_lock);
 735
 736        kref_get(&found->ref);
 737        return found;
 738}
 739
 740struct cfg80211_bss*
 741cfg80211_inform_bss(struct wiphy *wiphy,
 742                    struct ieee80211_channel *channel,
 743                    const u8 *bssid, u64 tsf, u16 capability,
 744                    u16 beacon_interval, const u8 *ie, size_t ielen,
 745                    s32 signal, gfp_t gfp)
 746{
 747        struct cfg80211_internal_bss *res;
 748        size_t privsz;
 749
 750        if (WARN_ON(!wiphy))
 751                return NULL;
 752
 753        privsz = wiphy->bss_priv_size;
 754
 755        if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
 756                        (signal < 0 || signal > 100)))
 757                return NULL;
 758
 759        res = kzalloc(sizeof(*res) + privsz + ielen, gfp);
 760        if (!res)
 761                return NULL;
 762
 763        memcpy(res->pub.bssid, bssid, ETH_ALEN);
 764        res->pub.channel = channel;
 765        res->pub.signal = signal;
 766        res->pub.tsf = tsf;
 767        res->pub.beacon_interval = beacon_interval;
 768        res->pub.capability = capability;
 769        /*
 770         * Since we do not know here whether the IEs are from a Beacon or Probe
 771         * Response frame, we need to pick one of the options and only use it
 772         * with the driver that does not provide the full Beacon/Probe Response
 773         * frame. Use Beacon frame pointer to avoid indicating that this should
 774         * override the information_elements pointer should we have received an
 775         * earlier indication of Probe Response data.
 776         *
 777         * The initial buffer for the IEs is allocated with the BSS entry and
 778         * is located after the private area.
 779         */
 780        res->pub.beacon_ies = (u8 *)res + sizeof(*res) + privsz;
 781        memcpy(res->pub.beacon_ies, ie, ielen);
 782        res->pub.len_beacon_ies = ielen;
 783        res->pub.information_elements = res->pub.beacon_ies;
 784        res->pub.len_information_elements = res->pub.len_beacon_ies;
 785
 786        kref_init(&res->ref);
 787
 788        res = cfg80211_bss_update(wiphy_to_dev(wiphy), res);
 789        if (!res)
 790                return NULL;
 791
 792        if (res->pub.capability & WLAN_CAPABILITY_ESS)
 793                regulatory_hint_found_beacon(wiphy, channel, gfp);
 794
 795        /* cfg80211_bss_update gives us a referenced result */
 796        return &res->pub;
 797}
 798EXPORT_SYMBOL(cfg80211_inform_bss);
 799
 800struct cfg80211_bss *
 801cfg80211_inform_bss_frame(struct wiphy *wiphy,
 802                          struct ieee80211_channel *channel,
 803                          struct ieee80211_mgmt *mgmt, size_t len,
 804                          s32 signal, gfp_t gfp)
 805{
 806        struct cfg80211_internal_bss *res;
 807        size_t ielen = len - offsetof(struct ieee80211_mgmt,
 808                                      u.probe_resp.variable);
 809        size_t privsz;
 810
 811        if (WARN_ON(!mgmt))
 812                return NULL;
 813
 814        if (WARN_ON(!wiphy))
 815                return NULL;
 816
 817        if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
 818                    (signal < 0 || signal > 100)))
 819                return NULL;
 820
 821        if (WARN_ON(len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable)))
 822                return NULL;
 823
 824        privsz = wiphy->bss_priv_size;
 825
 826        res = kzalloc(sizeof(*res) + privsz + ielen, gfp);
 827        if (!res)
 828                return NULL;
 829
 830        memcpy(res->pub.bssid, mgmt->bssid, ETH_ALEN);
 831        res->pub.channel = channel;
 832        res->pub.signal = signal;
 833        res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
 834        res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
 835        res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
 836        /*
 837         * The initial buffer for the IEs is allocated with the BSS entry and
 838         * is located after the private area.
 839         */
 840        if (ieee80211_is_probe_resp(mgmt->frame_control)) {
 841                res->pub.proberesp_ies = (u8 *) res + sizeof(*res) + privsz;
 842                memcpy(res->pub.proberesp_ies, mgmt->u.probe_resp.variable,
 843                       ielen);
 844                res->pub.len_proberesp_ies = ielen;
 845                res->pub.information_elements = res->pub.proberesp_ies;
 846                res->pub.len_information_elements = res->pub.len_proberesp_ies;
 847        } else {
 848                res->pub.beacon_ies = (u8 *) res + sizeof(*res) + privsz;
 849                memcpy(res->pub.beacon_ies, mgmt->u.beacon.variable, ielen);
 850                res->pub.len_beacon_ies = ielen;
 851                res->pub.information_elements = res->pub.beacon_ies;
 852                res->pub.len_information_elements = res->pub.len_beacon_ies;
 853        }
 854
 855        kref_init(&res->ref);
 856
 857        res = cfg80211_bss_update(wiphy_to_dev(wiphy), res);
 858        if (!res)
 859                return NULL;
 860
 861        if (res->pub.capability & WLAN_CAPABILITY_ESS)
 862                regulatory_hint_found_beacon(wiphy, channel, gfp);
 863
 864        /* cfg80211_bss_update gives us a referenced result */
 865        return &res->pub;
 866}
 867EXPORT_SYMBOL(cfg80211_inform_bss_frame);
 868
 869void cfg80211_ref_bss(struct cfg80211_bss *pub)
 870{
 871        struct cfg80211_internal_bss *bss;
 872
 873        if (!pub)
 874                return;
 875
 876        bss = container_of(pub, struct cfg80211_internal_bss, pub);
 877        kref_get(&bss->ref);
 878}
 879EXPORT_SYMBOL(cfg80211_ref_bss);
 880
 881void cfg80211_put_bss(struct cfg80211_bss *pub)
 882{
 883        struct cfg80211_internal_bss *bss;
 884
 885        if (!pub)
 886                return;
 887
 888        bss = container_of(pub, struct cfg80211_internal_bss, pub);
 889        kref_put(&bss->ref, bss_release);
 890}
 891EXPORT_SYMBOL(cfg80211_put_bss);
 892
 893void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
 894{
 895        struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
 896        struct cfg80211_internal_bss *bss;
 897
 898        if (WARN_ON(!pub))
 899                return;
 900
 901        bss = container_of(pub, struct cfg80211_internal_bss, pub);
 902
 903        spin_lock_bh(&dev->bss_lock);
 904        if (!list_empty(&bss->list)) {
 905                __cfg80211_unlink_bss(dev, bss);
 906                dev->bss_generation++;
 907        }
 908        spin_unlock_bh(&dev->bss_lock);
 909}
 910EXPORT_SYMBOL(cfg80211_unlink_bss);
 911
 912#ifdef CONFIG_CFG80211_WEXT
 913int cfg80211_wext_siwscan(struct net_device *dev,
 914                          struct iw_request_info *info,
 915                          union iwreq_data *wrqu, char *extra)
 916{
 917        struct cfg80211_registered_device *rdev;
 918        struct wiphy *wiphy;
 919        struct iw_scan_req *wreq = NULL;
 920        struct cfg80211_scan_request *creq = NULL;
 921        int i, err, n_channels = 0;
 922        enum ieee80211_band band;
 923
 924        if (!netif_running(dev))
 925                return -ENETDOWN;
 926
 927        if (wrqu->data.length == sizeof(struct iw_scan_req))
 928                wreq = (struct iw_scan_req *)extra;
 929
 930        rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex);
 931
 932        if (IS_ERR(rdev))
 933                return PTR_ERR(rdev);
 934
 935        if (rdev->scan_req) {
 936                err = -EBUSY;
 937                goto out;
 938        }
 939
 940        wiphy = &rdev->wiphy;
 941
 942        /* Determine number of channels, needed to allocate creq */
 943        if (wreq && wreq->num_channels)
 944                n_channels = wreq->num_channels;
 945        else {
 946                for (band = 0; band < IEEE80211_NUM_BANDS; band++)
 947                        if (wiphy->bands[band])
 948                                n_channels += wiphy->bands[band]->n_channels;
 949        }
 950
 951        creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) +
 952                       n_channels * sizeof(void *),
 953                       GFP_ATOMIC);
 954        if (!creq) {
 955                err = -ENOMEM;
 956                goto out;
 957        }
 958
 959        creq->wiphy = wiphy;
 960        creq->wdev = dev->ieee80211_ptr;
 961        /* SSIDs come after channels */
 962        creq->ssids = (void *)&creq->channels[n_channels];
 963        creq->n_channels = n_channels;
 964        creq->n_ssids = 1;
 965
 966        /* translate "Scan on frequencies" request */
 967        i = 0;
 968        for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
 969                int j;
 970
 971                if (!wiphy->bands[band])
 972                        continue;
 973
 974                for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
 975                        /* ignore disabled channels */
 976                        if (wiphy->bands[band]->channels[j].flags &
 977                                                IEEE80211_CHAN_DISABLED)
 978                                continue;
 979
 980                        /* If we have a wireless request structure and the
 981                         * wireless request specifies frequencies, then search
 982                         * for the matching hardware channel.
 983                         */
 984                        if (wreq && wreq->num_channels) {
 985                                int k;
 986                                int wiphy_freq = wiphy->bands[band]->channels[j].center_freq;
 987                                for (k = 0; k < wreq->num_channels; k++) {
 988                                        int wext_freq = cfg80211_wext_freq(wiphy, &wreq->channel_list[k]);
 989                                        if (wext_freq == wiphy_freq)
 990                                                goto wext_freq_found;
 991                                }
 992                                goto wext_freq_not_found;
 993                        }
 994
 995                wext_freq_found:
 996                        creq->channels[i] = &wiphy->bands[band]->channels[j];
 997                        i++;
 998                wext_freq_not_found: ;
 999                }
1000        }
1001        /* No channels found? */
1002        if (!i) {
1003                err = -EINVAL;
1004                goto out;
1005        }
1006
1007        /* Set real number of channels specified in creq->channels[] */
1008        creq->n_channels = i;
1009
1010        /* translate "Scan for SSID" request */
1011        if (wreq) {
1012                if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
1013                        if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) {
1014                                err = -EINVAL;
1015                                goto out;
1016                        }
1017                        memcpy(creq->ssids[0].ssid, wreq->essid, wreq->essid_len);
1018                        creq->ssids[0].ssid_len = wreq->essid_len;
1019                }
1020                if (wreq->scan_type == IW_SCAN_TYPE_PASSIVE)
1021                        creq->n_ssids = 0;
1022        }
1023
1024        for (i = 0; i < IEEE80211_NUM_BANDS; i++)
1025                if (wiphy->bands[i])
1026                        creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1;
1027
1028        rdev->scan_req = creq;
1029        err = rdev->ops->scan(wiphy, creq);
1030        if (err) {
1031                rdev->scan_req = NULL;
1032                /* creq will be freed below */
1033        } else {
1034                nl80211_send_scan_start(rdev, dev->ieee80211_ptr);
1035                /* creq now owned by driver */
1036                creq = NULL;
1037                dev_hold(dev);
1038        }
1039 out:
1040        kfree(creq);
1041        cfg80211_unlock_rdev(rdev);
1042        return err;
1043}
1044EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan);
1045
1046static void ieee80211_scan_add_ies(struct iw_request_info *info,
1047                                   struct cfg80211_bss *bss,
1048                                   char **current_ev, char *end_buf)
1049{
1050        u8 *pos, *end, *next;
1051        struct iw_event iwe;
1052
1053        if (!bss->information_elements ||
1054            !bss->len_information_elements)
1055                return;
1056
1057        /*
1058         * If needed, fragment the IEs buffer (at IE boundaries) into short
1059         * enough fragments to fit into IW_GENERIC_IE_MAX octet messages.
1060         */
1061        pos = bss->information_elements;
1062        end = pos + bss->len_information_elements;
1063
1064        while (end - pos > IW_GENERIC_IE_MAX) {
1065                next = pos + 2 + pos[1];
1066                while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX)
1067                        next = next + 2 + next[1];
1068
1069                memset(&iwe, 0, sizeof(iwe));
1070                iwe.cmd = IWEVGENIE;
1071                iwe.u.data.length = next - pos;
1072                *current_ev = iwe_stream_add_point(info, *current_ev,
1073                                                   end_buf, &iwe, pos);
1074
1075                pos = next;
1076        }
1077
1078        if (end > pos) {
1079                memset(&iwe, 0, sizeof(iwe));
1080                iwe.cmd = IWEVGENIE;
1081                iwe.u.data.length = end - pos;
1082                *current_ev = iwe_stream_add_point(info, *current_ev,
1083                                                   end_buf, &iwe, pos);
1084        }
1085}
1086
1087static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
1088{
1089        unsigned long end = jiffies;
1090
1091        if (end >= start)
1092                return jiffies_to_msecs(end - start);
1093
1094        return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1);
1095}
1096
1097static char *
1098ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1099              struct cfg80211_internal_bss *bss, char *current_ev,
1100              char *end_buf)
1101{
1102        struct iw_event iwe;
1103        u8 *buf, *cfg, *p;
1104        u8 *ie = bss->pub.information_elements;
1105        int rem = bss->pub.len_information_elements, i, sig;
1106        bool ismesh = false;
1107
1108        memset(&iwe, 0, sizeof(iwe));
1109        iwe.cmd = SIOCGIWAP;
1110        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1111        memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN);
1112        current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1113                                          IW_EV_ADDR_LEN);
1114
1115        memset(&iwe, 0, sizeof(iwe));
1116        iwe.cmd = SIOCGIWFREQ;
1117        iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq);
1118        iwe.u.freq.e = 0;
1119        current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1120                                          IW_EV_FREQ_LEN);
1121
1122        memset(&iwe, 0, sizeof(iwe));
1123        iwe.cmd = SIOCGIWFREQ;
1124        iwe.u.freq.m = bss->pub.channel->center_freq;
1125        iwe.u.freq.e = 6;
1126        current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
1127                                          IW_EV_FREQ_LEN);
1128
1129        if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) {
1130                memset(&iwe, 0, sizeof(iwe));
1131                iwe.cmd = IWEVQUAL;
1132                iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED |
1133                                     IW_QUAL_NOISE_INVALID |
1134                                     IW_QUAL_QUAL_UPDATED;
1135                switch (wiphy->signal_type) {
1136                case CFG80211_SIGNAL_TYPE_MBM:
1137                        sig = bss->pub.signal / 100;
1138                        iwe.u.qual.level = sig;
1139                        iwe.u.qual.updated |= IW_QUAL_DBM;
1140                        if (sig < -110)         /* rather bad */
1141                                sig = -110;
1142                        else if (sig > -40)     /* perfect */
1143                                sig = -40;
1144                        /* will give a range of 0 .. 70 */
1145                        iwe.u.qual.qual = sig + 110;
1146                        break;
1147                case CFG80211_SIGNAL_TYPE_UNSPEC:
1148                        iwe.u.qual.level = bss->pub.signal;
1149                        /* will give range 0 .. 100 */
1150                        iwe.u.qual.qual = bss->pub.signal;
1151                        break;
1152                default:
1153                        /* not reached */
1154                        break;
1155                }
1156                current_ev = iwe_stream_add_event(info, current_ev, end_buf,
1157                                                  &iwe, IW_EV_QUAL_LEN);
1158        }
1159
1160        memset(&iwe, 0, sizeof(iwe));
1161        iwe.cmd = SIOCGIWENCODE;
1162        if (bss->pub.capability & WLAN_CAPABILITY_PRIVACY)
1163                iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1164        else
1165                iwe.u.data.flags = IW_ENCODE_DISABLED;
1166        iwe.u.data.length = 0;
1167        current_ev = iwe_stream_add_point(info, current_ev, end_buf,
1168                                          &iwe, "");
1169
1170        while (rem >= 2) {
1171                /* invalid data */
1172                if (ie[1] > rem - 2)
1173                        break;
1174
1175                switch (ie[0]) {
1176                case WLAN_EID_SSID:
1177                        memset(&iwe, 0, sizeof(iwe));
1178                        iwe.cmd = SIOCGIWESSID;
1179                        iwe.u.data.length = ie[1];
1180                        iwe.u.data.flags = 1;
1181                        current_ev = iwe_stream_add_point(info, current_ev, end_buf,
1182                                                          &iwe, ie + 2);
1183                        break;
1184                case WLAN_EID_MESH_ID:
1185                        memset(&iwe, 0, sizeof(iwe));
1186                        iwe.cmd = SIOCGIWESSID;
1187                        iwe.u.data.length = ie[1];
1188                        iwe.u.data.flags = 1;
1189                        current_ev = iwe_stream_add_point(info, current_ev, end_buf,
1190                                                          &iwe, ie + 2);
1191                        break;
1192                case WLAN_EID_MESH_CONFIG:
1193                        ismesh = true;
1194                        if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
1195                                break;
1196                        buf = kmalloc(50, GFP_ATOMIC);
1197                        if (!buf)
1198                                break;
1199                        cfg = ie + 2;
1200                        memset(&iwe, 0, sizeof(iwe));
1201                        iwe.cmd = IWEVCUSTOM;
1202                        sprintf(buf, "Mesh Network Path Selection Protocol ID: "
1203                                "0x%02X", cfg[0]);
1204                        iwe.u.data.length = strlen(buf);
1205                        current_ev = iwe_stream_add_point(info, current_ev,
1206                                                          end_buf,
1207                                                          &iwe, buf);
1208                        sprintf(buf, "Path Selection Metric ID: 0x%02X",
1209                                cfg[1]);
1210                        iwe.u.data.length = strlen(buf);
1211                        current_ev = iwe_stream_add_point(info, current_ev,
1212                                                          end_buf,
1213                                                          &iwe, buf);
1214                        sprintf(buf, "Congestion Control Mode ID: 0x%02X",
1215                                cfg[2]);
1216                        iwe.u.data.length = strlen(buf);
1217                        current_ev = iwe_stream_add_point(info, current_ev,
1218                                                          end_buf,
1219                                                          &iwe, buf);
1220                        sprintf(buf, "Synchronization ID: 0x%02X", cfg[3]);
1221                        iwe.u.data.length = strlen(buf);
1222                        current_ev = iwe_stream_add_point(info, current_ev,
1223                                                          end_buf,
1224                                                          &iwe, buf);
1225                        sprintf(buf, "Authentication ID: 0x%02X", cfg[4]);
1226                        iwe.u.data.length = strlen(buf);
1227                        current_ev = iwe_stream_add_point(info, current_ev,
1228                                                          end_buf,
1229                                                          &iwe, buf);
1230                        sprintf(buf, "Formation Info: 0x%02X", cfg[5]);
1231                        iwe.u.data.length = strlen(buf);
1232                        current_ev = iwe_stream_add_point(info, current_ev,
1233                                                          end_buf,
1234                                                          &iwe, buf);
1235                        sprintf(buf, "Capabilities: 0x%02X", cfg[6]);
1236                        iwe.u.data.length = strlen(buf);
1237                        current_ev = iwe_stream_add_point(info, current_ev,
1238                                                          end_buf,
1239                                                          &iwe, buf);
1240                        kfree(buf);
1241                        break;
1242                case WLAN_EID_SUPP_RATES:
1243                case WLAN_EID_EXT_SUPP_RATES:
1244                        /* display all supported rates in readable format */
1245                        p = current_ev + iwe_stream_lcp_len(info);
1246
1247                        memset(&iwe, 0, sizeof(iwe));
1248                        iwe.cmd = SIOCGIWRATE;
1249                        /* Those two flags are ignored... */
1250                        iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
1251
1252                        for (i = 0; i < ie[1]; i++) {
1253                                iwe.u.bitrate.value =
1254                                        ((ie[i + 2] & 0x7f) * 500000);
1255                                p = iwe_stream_add_value(info, current_ev, p,
1256                                                end_buf, &iwe, IW_EV_PARAM_LEN);
1257                        }
1258                        current_ev = p;
1259                        break;
1260                }
1261                rem -= ie[1] + 2;
1262                ie += ie[1] + 2;
1263        }
1264
1265        if (bss->pub.capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) ||
1266            ismesh) {
1267                memset(&iwe, 0, sizeof(iwe));
1268                iwe.cmd = SIOCGIWMODE;
1269                if (ismesh)
1270                        iwe.u.mode = IW_MODE_MESH;
1271                else if (bss->pub.capability & WLAN_CAPABILITY_ESS)
1272                        iwe.u.mode = IW_MODE_MASTER;
1273                else
1274                        iwe.u.mode = IW_MODE_ADHOC;
1275                current_ev = iwe_stream_add_event(info, current_ev, end_buf,
1276                                                  &iwe, IW_EV_UINT_LEN);
1277        }
1278
1279        buf = kmalloc(30, GFP_ATOMIC);
1280        if (buf) {
1281                memset(&iwe, 0, sizeof(iwe));
1282                iwe.cmd = IWEVCUSTOM;
1283                sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->pub.tsf));
1284                iwe.u.data.length = strlen(buf);
1285                current_ev = iwe_stream_add_point(info, current_ev, end_buf,
1286                                                  &iwe, buf);
1287                memset(&iwe, 0, sizeof(iwe));
1288                iwe.cmd = IWEVCUSTOM;
1289                sprintf(buf, " Last beacon: %ums ago",
1290                        elapsed_jiffies_msecs(bss->ts));
1291                iwe.u.data.length = strlen(buf);
1292                current_ev = iwe_stream_add_point(info, current_ev,
1293                                                  end_buf, &iwe, buf);
1294                kfree(buf);
1295        }
1296
1297        ieee80211_scan_add_ies(info, &bss->pub, &current_ev, end_buf);
1298
1299        return current_ev;
1300}
1301
1302
1303static int ieee80211_scan_results(struct cfg80211_registered_device *dev,
1304                                  struct iw_request_info *info,
1305                                  char *buf, size_t len)
1306{
1307        char *current_ev = buf;
1308        char *end_buf = buf + len;
1309        struct cfg80211_internal_bss *bss;
1310
1311        spin_lock_bh(&dev->bss_lock);
1312        cfg80211_bss_expire(dev);
1313
1314        list_for_each_entry(bss, &dev->bss_list, list) {
1315                if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
1316                        spin_unlock_bh(&dev->bss_lock);
1317                        return -E2BIG;
1318                }
1319                current_ev = ieee80211_bss(&dev->wiphy, info, bss,
1320                                           current_ev, end_buf);
1321        }
1322        spin_unlock_bh(&dev->bss_lock);
1323        return current_ev - buf;
1324}
1325
1326
1327int cfg80211_wext_giwscan(struct net_device *dev,
1328                          struct iw_request_info *info,
1329                          struct iw_point *data, char *extra)
1330{
1331        struct cfg80211_registered_device *rdev;
1332        int res;
1333
1334        if (!netif_running(dev))
1335                return -ENETDOWN;
1336
1337        rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex);
1338
1339        if (IS_ERR(rdev))
1340                return PTR_ERR(rdev);
1341
1342        if (rdev->scan_req) {
1343                res = -EAGAIN;
1344                goto out;
1345        }
1346
1347        res = ieee80211_scan_results(rdev, info, extra, data->length);
1348        data->length = 0;
1349        if (res >= 0) {
1350                data->length = res;
1351                res = 0;
1352        }
1353
1354 out:
1355        cfg80211_unlock_rdev(rdev);
1356        return res;
1357}
1358EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan);
1359#endif
1360
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.