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