aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2010-01-06 09:19:24 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-01-12 13:51:28 -0500
commit34a6eddbabd704b3c7dae9362234552267573be2 (patch)
tree661184452aa597e4f1034561b3ec9b267ad2e196
parent80a112ffe8dbada25f3780ecc4beebf23451d755 (diff)
cfg80211: Store IEs from both Beacon and Probe Response frames
Store information elements from Beacon and Probe Response frames in separate buffers to allow both sets to be made available through nl80211. This allows user space applications to get access to IEs from Beacon frames even if we have received Probe Response frames from the BSS. Previously, the IEs from Probe Response frames would have overridden the IEs from Beacon frames. This feature is of somewhat limited use since most protocols include the same (or extended) information in Probe Response frames. However, there are couple of exceptions where the IEs from Beacon frames could be of some use: TIM IE is only included in Beacon frames (and it would be needed to figure out the DTIM period used in the BSS) and at least some implementations of Wireless Provisioning Services seem to include the full IE only in Beacon frames). The new BSS attribute for scan results is added to allow both the IE sets to be delivered. This is done in a way that maintains the previously used behavior for applications that are not aware of the new NL80211_BSS_BEACON_IES attribute. Signed-off-by: Jouni Malinen <j@w1.fi> Acked-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-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