diff options
Diffstat (limited to 'net/wireless/scan.c')
-rw-r--r-- | net/wireless/scan.c | 80 |
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 | */ | ||
433 | enum bss_compare_mode { | ||
434 | BSS_CMP_REGULAR, | ||
435 | BSS_CMP_HIDE_ZLEN, | ||
436 | BSS_CMP_HIDE_NUL, | ||
437 | }; | ||
438 | |||
427 | static int cmp_bss(struct cfg80211_bss *a, | 439 | static 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 | ||
488 | struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, | 509 | struct 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, | |||
584 | static struct cfg80211_internal_bss * | 605 | static struct cfg80211_internal_bss * |
585 | rb_find_bss(struct cfg80211_registered_device *dev, | 606 | rb_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 |