aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/nl80211.h10
-rw-r--r--include/net/cfg80211.h12
-rw-r--r--net/wireless/core.h3
-rw-r--r--net/wireless/nl80211.c4
-rw-r--r--net/wireless/scan.c120
5 files changed, 116 insertions, 33 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 7a1c8c145b22..127a73015760 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1378,13 +1378,20 @@ enum nl80211_channel_type {
1378 * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16) 1378 * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
1379 * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16) 1379 * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
1380 * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the 1380 * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
1381 * raw information elements from the probe response/beacon (bin) 1381 * raw information elements from the probe response/beacon (bin);
1382 * if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are
1383 * from a Probe Response frame; otherwise they are from a Beacon frame.
1384 * However, if the driver does not indicate the source of the IEs, these
1385 * IEs may be from either frame subtype.
1382 * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon 1386 * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
1383 * in mBm (100 * dBm) (s32) 1387 * in mBm (100 * dBm) (s32)
1384 * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon 1388 * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
1385 * in unspecified units, scaled to 0..100 (u8) 1389 * in unspecified units, scaled to 0..100 (u8)
1386 * @NL80211_BSS_STATUS: status, if this BSS is "used" 1390 * @NL80211_BSS_STATUS: status, if this BSS is "used"
1387 * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms 1391 * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms
1392 * @NL80211_BSS_BEACON_IES: binary attribute containing the raw information
1393 * elements from a Beacon frame (bin); not present if no Beacon frame has
1394 * yet been received
1388 * @__NL80211_BSS_AFTER_LAST: internal 1395 * @__NL80211_BSS_AFTER_LAST: internal
1389 * @NL80211_BSS_MAX: highest BSS attribute 1396 * @NL80211_BSS_MAX: highest BSS attribute
1390 */ 1397 */
@@ -1400,6 +1407,7 @@ enum nl80211_bss {
1400 NL80211_BSS_SIGNAL_UNSPEC, 1407 NL80211_BSS_SIGNAL_UNSPEC,
1401 NL80211_BSS_STATUS, 1408 NL80211_BSS_STATUS,
1402 NL80211_BSS_SEEN_MS_AGO, 1409 NL80211_BSS_SEEN_MS_AGO,
1410 NL80211_BSS_BEACON_IES,
1403 1411
1404 /* keep last */ 1412 /* keep last */
1405 __NL80211_BSS_AFTER_LAST, 1413 __NL80211_BSS_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 0d734413b5fb..2af52704e670 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -626,8 +626,14 @@ enum cfg80211_signal_type {
626 * @beacon_interval: the beacon interval as from the frame 626 * @beacon_interval: the beacon interval as from the frame
627 * @capability: the capability field in host byte order 627 * @capability: the capability field in host byte order
628 * @information_elements: the information elements (Note that there 628 * @information_elements: the information elements (Note that there
629 * is no guarantee that these are well-formed!) 629 * is no guarantee that these are well-formed!); this is a pointer to
630 * either the beacon_ies or proberesp_ies depending on whether Probe
631 * Response frame has been received
630 * @len_information_elements: total length of the information elements 632 * @len_information_elements: total length of the information elements
633 * @beacon_ies: the information elements from the last Beacon frame
634 * @len_beacon_ies: total length of the beacon_ies
635 * @proberesp_ies: the information elements from the last Probe Response frame
636 * @len_proberesp_ies: total length of the proberesp_ies
631 * @signal: signal strength value (type depends on the wiphy's signal_type) 637 * @signal: signal strength value (type depends on the wiphy's signal_type)
632 * @free_priv: function pointer to free private data 638 * @free_priv: function pointer to free private data
633 * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes 639 * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes
@@ -641,6 +647,10 @@ struct cfg80211_bss {
641 u16 capability; 647 u16 capability;
642 u8 *information_elements; 648 u8 *information_elements;
643 size_t len_information_elements; 649 size_t len_information_elements;
650 u8 *beacon_ies;
651 size_t len_beacon_ies;
652 u8 *proberesp_ies;
653 size_t len_proberesp_ies;
644 654
645 s32 signal; 655 s32 signal;
646 656
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 30ec95f05b52..2d6a6b9c0c43 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -111,7 +111,8 @@ struct cfg80211_internal_bss {
111 unsigned long ts; 111 unsigned long ts;
112 struct kref ref; 112 struct kref ref;
113 atomic_t hold; 113 atomic_t hold;
114 bool ies_allocated; 114 bool beacon_ies_allocated;
115 bool proberesp_ies_allocated;
115 116
116 /* must be last because of priv member */ 117 /* must be last because of priv member */
117 struct cfg80211_bss pub; 118 struct cfg80211_bss pub;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index b804062e0179..4af7991a9ec8 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3163,6 +3163,10 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
3163 NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS, 3163 NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS,
3164 res->len_information_elements, 3164 res->len_information_elements,
3165 res->information_elements); 3165 res->information_elements);
3166 if (res->beacon_ies && res->len_beacon_ies &&
3167 res->beacon_ies != res->information_elements)
3168 NLA_PUT(msg, NL80211_BSS_BEACON_IES,
3169 res->len_beacon_ies, res->beacon_ies);
3166 if (res->tsf) 3170 if (res->tsf)
3167 NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf); 3171 NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf);
3168 if (res->beacon_interval) 3172 if (res->beacon_interval)
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