aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/scan.c80
1 files changed, 53 insertions, 27 deletions
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index cfc4e1aa8dad..d4fe065eeb11 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -424,9 +424,21 @@ static int cmp_bss_core(struct cfg80211_bss *a, struct cfg80211_bss *b)
424 return memcmp(a->bssid, b->bssid, sizeof(a->bssid)); 424 return memcmp(a->bssid, b->bssid, sizeof(a->bssid));
425} 425}
426 426
427/**
428 * enum bss_compare_mode - BSS compare mode
429 * @BSS_CMP_REGULAR: regular compare mode (for insertion and normal find)
430 * @BSS_CMP_HIDE_ZLEN: find hidden SSID with zero-length mode
431 * @BSS_CMP_HIDE_NUL: find hidden SSID with NUL-ed out mode
432 */
433enum bss_compare_mode {
434 BSS_CMP_REGULAR,
435 BSS_CMP_HIDE_ZLEN,
436 BSS_CMP_HIDE_NUL,
437};
438
427static int cmp_bss(struct cfg80211_bss *a, 439static int cmp_bss(struct cfg80211_bss *a,
428 struct cfg80211_bss *b, 440 struct cfg80211_bss *b,
429 bool hide_ssid) 441 enum bss_compare_mode mode)
430{ 442{
431 const struct cfg80211_bss_ies *a_ies, *b_ies; 443 const struct cfg80211_bss_ies *a_ies, *b_ies;
432 const u8 *ie1; 444 const u8 *ie1;
@@ -462,27 +474,36 @@ static int cmp_bss(struct cfg80211_bss *a,
462 if (!ie2) 474 if (!ie2)
463 return 1; 475 return 1;
464 476
465 /* zero-length SSID is used as an indication of the hidden bss */ 477 switch (mode) {
466 if (hide_ssid && !ie2[1]) 478 case BSS_CMP_HIDE_ZLEN:
467 return 0; 479 /*
468 480 * In ZLEN mode we assume the BSS entry we're
469 /* sort by length first, then by contents */ 481 * looking for has a zero-length SSID. So if
470 if (ie1[1] != ie2[1]) 482 * the one we're looking at right now has that,
471 return ie2[1] - ie1[1]; 483 * return 0. Otherwise, return the difference
472 484 * in length, but since we're looking for the
473 if (!hide_ssid) 485 * 0-length it's really equivalent to returning
486 * the length of the one we're looking at.
487 *
488 * No content comparison is needed as we assume
489 * the content length is zero.
490 */
491 return ie2[1];
492 case BSS_CMP_REGULAR:
493 default:
494 /* sort by length first, then by contents */
495 if (ie1[1] != ie2[1])
496 return ie2[1] - ie1[1];
474 return memcmp(ie1 + 2, ie2 + 2, ie1[1]); 497 return memcmp(ie1 + 2, ie2 + 2, ie1[1]);
475 498 case BSS_CMP_HIDE_NUL:
476 /* 499 if (ie1[1] != ie2[1])
477 * zeroed SSID ie is another indication of a hidden bss; 500 return ie2[1] - ie1[1];
478 * if it isn't zeroed just return the regular sort value 501 /* this is equivalent to memcmp(zeroes, ie2 + 2, len) */
479 * to find the next candidate 502 for (i = 0; i < ie2[1]; i++)
480 */ 503 if (ie2[i + 2])
481 for (i = 0; i < ie2[1]; i++) 504 return -1;
482 if (ie2[i + 2]) 505 return 0;
483 return memcmp(ie1 + 2, ie2 + 2, ie1[1]); 506 }
484
485 return 0;
486} 507}
487 508
488struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, 509struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
@@ -564,7 +585,7 @@ static void rb_insert_bss(struct cfg80211_registered_device *dev,
564 parent = *p; 585 parent = *p;
565 tbss = rb_entry(parent, struct cfg80211_internal_bss, rbn); 586 tbss = rb_entry(parent, struct cfg80211_internal_bss, rbn);
566 587
567 cmp = cmp_bss(&bss->pub, &tbss->pub, false); 588 cmp = cmp_bss(&bss->pub, &tbss->pub, BSS_CMP_REGULAR);
568 589
569 if (WARN_ON(!cmp)) { 590 if (WARN_ON(!cmp)) {
570 /* will sort of leak this BSS */ 591 /* will sort of leak this BSS */
@@ -584,7 +605,7 @@ static void rb_insert_bss(struct cfg80211_registered_device *dev,
584static struct cfg80211_internal_bss * 605static struct cfg80211_internal_bss *
585rb_find_bss(struct cfg80211_registered_device *dev, 606rb_find_bss(struct cfg80211_registered_device *dev,
586 struct cfg80211_internal_bss *res, 607 struct cfg80211_internal_bss *res,
587 bool hidden) 608 enum bss_compare_mode mode)
588{ 609{
589 struct rb_node *n = dev->bss_tree.rb_node; 610 struct rb_node *n = dev->bss_tree.rb_node;
590 struct cfg80211_internal_bss *bss; 611 struct cfg80211_internal_bss *bss;
@@ -592,7 +613,7 @@ rb_find_bss(struct cfg80211_registered_device *dev,
592 613
593 while (n) { 614 while (n) {
594 bss = rb_entry(n, struct cfg80211_internal_bss, rbn); 615 bss = rb_entry(n, struct cfg80211_internal_bss, rbn);
595 r = cmp_bss(&res->pub, &bss->pub, hidden); 616 r = cmp_bss(&res->pub, &bss->pub, mode);
596 617
597 if (r == 0) 618 if (r == 0)
598 return bss; 619 return bss;
@@ -642,7 +663,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
642 return NULL; 663 return NULL;
643 } 664 }
644 665
645 found = rb_find_bss(dev, tmp, false); 666 found = rb_find_bss(dev, tmp, BSS_CMP_REGULAR);
646 667
647 if (found) { 668 if (found) {
648 found->pub.beacon_interval = tmp->pub.beacon_interval; 669 found->pub.beacon_interval = tmp->pub.beacon_interval;
@@ -697,9 +718,14 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
697 /* TODO: The code is not trying to update existing probe 718 /* TODO: The code is not trying to update existing probe
698 * response bss entries when beacon ies are 719 * response bss entries when beacon ies are
699 * getting changed. */ 720 * getting changed. */
700 hidden = rb_find_bss(dev, tmp, true); 721 hidden = rb_find_bss(dev, tmp, BSS_CMP_HIDE_ZLEN);
701 if (hidden) 722 if (hidden) {
702 copy_hidden_ies(tmp, hidden); 723 copy_hidden_ies(tmp, hidden);
724 } else {
725 hidden = rb_find_bss(dev, tmp, BSS_CMP_HIDE_NUL);
726 if (hidden)
727 copy_hidden_ies(tmp, hidden);
728 }
703 729
704 /* 730 /*
705 * create a copy -- the "res" variable that is passed in 731 * create a copy -- the "res" variable that is passed in