aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/scan.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/scan.c')
-rw-r--r--net/wireless/scan.c120
1 files changed, 90 insertions, 30 deletions
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 0c2cbbebca95..06b0231ee5e3 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -100,8 +100,10 @@ static void bss_release(struct kref *ref)
100 if (bss->pub.free_priv) 100 if (bss->pub.free_priv)
101 bss->pub.free_priv(&bss->pub); 101 bss->pub.free_priv(&bss->pub);
102 102
103 if (bss->ies_allocated) 103 if (bss->beacon_ies_allocated)
104 kfree(bss->pub.information_elements); 104 kfree(bss->pub.beacon_ies);
105 if (bss->proberesp_ies_allocated)
106 kfree(bss->pub.proberesp_ies);
105 107
106 BUG_ON(atomic_read(&bss->hold)); 108 BUG_ON(atomic_read(&bss->hold));
107 109
@@ -375,8 +377,7 @@ rb_find_bss(struct cfg80211_registered_device *dev,
375 377
376static struct cfg80211_internal_bss * 378static struct cfg80211_internal_bss *
377cfg80211_bss_update(struct cfg80211_registered_device *dev, 379cfg80211_bss_update(struct cfg80211_registered_device *dev,
378 struct cfg80211_internal_bss *res, 380 struct cfg80211_internal_bss *res)
379 bool overwrite)
380{ 381{
381 struct cfg80211_internal_bss *found = NULL; 382 struct cfg80211_internal_bss *found = NULL;
382 const u8 *meshid, *meshcfg; 383 const u8 *meshid, *meshcfg;
@@ -418,28 +419,64 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
418 found->pub.capability = res->pub.capability; 419 found->pub.capability = res->pub.capability;
419 found->ts = res->ts; 420 found->ts = res->ts;
420 421
421 /* overwrite IEs */ 422 /* Update IEs */
422 if (overwrite) { 423 if (res->pub.proberesp_ies) {
423 size_t used = dev->wiphy.bss_priv_size + sizeof(*res); 424 size_t used = dev->wiphy.bss_priv_size + sizeof(*res);
424 size_t ielen = res->pub.len_information_elements; 425 size_t ielen = res->pub.len_proberesp_ies;
426
427 if (found->pub.proberesp_ies &&
428 !found->proberesp_ies_allocated &&
429 ksize(found) >= used + ielen) {
430 memcpy(found->pub.proberesp_ies,
431 res->pub.proberesp_ies, ielen);
432 found->pub.len_proberesp_ies = ielen;
433 } else {
434 u8 *ies = found->pub.proberesp_ies;
435
436 if (found->proberesp_ies_allocated)
437 ies = krealloc(ies, ielen, GFP_ATOMIC);
438 else
439 ies = kmalloc(ielen, GFP_ATOMIC);
440
441 if (ies) {
442 memcpy(ies, res->pub.proberesp_ies,
443 ielen);
444 found->proberesp_ies_allocated = true;
445 found->pub.proberesp_ies = ies;
446 found->pub.len_proberesp_ies = ielen;
447 }
448 }
425 449
426 if (!found->ies_allocated && ksize(found) >= used + ielen) { 450 /* Override possible earlier Beacon frame IEs */
427 memcpy(found->pub.information_elements, 451 found->pub.information_elements =
428 res->pub.information_elements, ielen); 452 found->pub.proberesp_ies;
429 found->pub.len_information_elements = ielen; 453 found->pub.len_information_elements =
454 found->pub.len_proberesp_ies;
455 }
456 if (res->pub.beacon_ies) {
457 size_t used = dev->wiphy.bss_priv_size + sizeof(*res);
458 size_t ielen = res->pub.len_beacon_ies;
459
460 if (found->pub.beacon_ies &&
461 !found->beacon_ies_allocated &&
462 ksize(found) >= used + ielen) {
463 memcpy(found->pub.beacon_ies,
464 res->pub.beacon_ies, ielen);
465 found->pub.len_beacon_ies = ielen;
430 } else { 466 } else {
431 u8 *ies = found->pub.information_elements; 467 u8 *ies = found->pub.beacon_ies;
432 468
433 if (found->ies_allocated) 469 if (found->beacon_ies_allocated)
434 ies = krealloc(ies, ielen, GFP_ATOMIC); 470 ies = krealloc(ies, ielen, GFP_ATOMIC);
435 else 471 else
436 ies = kmalloc(ielen, GFP_ATOMIC); 472 ies = kmalloc(ielen, GFP_ATOMIC);
437 473
438 if (ies) { 474 if (ies) {
439 memcpy(ies, res->pub.information_elements, ielen); 475 memcpy(ies, res->pub.beacon_ies,
440 found->ies_allocated = true; 476 ielen);
441 found->pub.information_elements = ies; 477 found->beacon_ies_allocated = true;
442 found->pub.len_information_elements = ielen; 478 found->pub.beacon_ies = ies;
479 found->pub.len_beacon_ies = ielen;
443 } 480 }
444 } 481 }
445 } 482 }
@@ -489,14 +526,26 @@ cfg80211_inform_bss(struct wiphy *wiphy,
489 res->pub.tsf = timestamp; 526 res->pub.tsf = timestamp;
490 res->pub.beacon_interval = beacon_interval; 527 res->pub.beacon_interval = beacon_interval;
491 res->pub.capability = capability; 528 res->pub.capability = capability;
492 /* point to after the private area */ 529 /*
493 res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz; 530 * Since we do not know here whether the IEs are from a Beacon or Probe
494 memcpy(res->pub.information_elements, ie, ielen); 531 * Response frame, we need to pick one of the options and only use it
495 res->pub.len_information_elements = ielen; 532 * with the driver that does not provide the full Beacon/Probe Response
533 * frame. Use Beacon frame pointer to avoid indicating that this should
534 * override the information_elements pointer should we have received an
535 * earlier indication of Probe Response data.
536 *
537 * The initial buffer for the IEs is allocated with the BSS entry and
538 * is located after the private area.
539 */
540 res->pub.beacon_ies = (u8 *)res + sizeof(*res) + privsz;
541 memcpy(res->pub.beacon_ies, ie, ielen);
542 res->pub.len_beacon_ies = ielen;
543 res->pub.information_elements = res->pub.beacon_ies;
544 res->pub.len_information_elements = res->pub.len_beacon_ies;
496 545
497 kref_init(&res->ref); 546 kref_init(&res->ref);
498 547
499 res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, 0); 548 res = cfg80211_bss_update(wiphy_to_dev(wiphy), res);
500 if (!res) 549 if (!res)
501 return NULL; 550 return NULL;
502 551
@@ -517,7 +566,6 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
517 struct cfg80211_internal_bss *res; 566 struct cfg80211_internal_bss *res;
518 size_t ielen = len - offsetof(struct ieee80211_mgmt, 567 size_t ielen = len - offsetof(struct ieee80211_mgmt,
519 u.probe_resp.variable); 568 u.probe_resp.variable);
520 bool overwrite;
521 size_t privsz = wiphy->bss_priv_size; 569 size_t privsz = wiphy->bss_priv_size;
522 570
523 if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC && 571 if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC &&
@@ -538,16 +586,28 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
538 res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); 586 res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
539 res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); 587 res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
540 res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); 588 res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
541 /* point to after the private area */ 589 /*
542 res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz; 590 * The initial buffer for the IEs is allocated with the BSS entry and
543 memcpy(res->pub.information_elements, mgmt->u.probe_resp.variable, ielen); 591 * is located after the private area.
544 res->pub.len_information_elements = ielen; 592 */
593 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
594 res->pub.proberesp_ies = (u8 *) res + sizeof(*res) + privsz;
595 memcpy(res->pub.proberesp_ies, mgmt->u.probe_resp.variable,
596 ielen);
597 res->pub.len_proberesp_ies = ielen;
598 res->pub.information_elements = res->pub.proberesp_ies;
599 res->pub.len_information_elements = res->pub.len_proberesp_ies;
600 } else {
601 res->pub.beacon_ies = (u8 *) res + sizeof(*res) + privsz;
602 memcpy(res->pub.beacon_ies, mgmt->u.beacon.variable, ielen);
603 res->pub.len_beacon_ies = ielen;
604 res->pub.information_elements = res->pub.beacon_ies;
605 res->pub.len_information_elements = res->pub.len_beacon_ies;
606 }
545 607
546 kref_init(&res->ref); 608 kref_init(&res->ref);
547 609
548 overwrite = ieee80211_is_probe_resp(mgmt->frame_control); 610 res = cfg80211_bss_update(wiphy_to_dev(wiphy), res);
549
550 res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, overwrite);
551 if (!res) 611 if (!res)
552 return NULL; 612 return NULL;
553 613