aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/util.c
diff options
context:
space:
mode:
authorPaul Stewart <pstew@chromium.org>2012-02-23 20:59:53 -0500
committerJohn W. Linville <linville@tuxdriver.com>2012-03-07 13:51:37 -0500
commitfcff4f108dce0692410f390a05565f4b1b84577f (patch)
tree38e7c8cc1b28069b8a1bd518388f7585abc6f916 /net/mac80211/util.c
parenteb9bc6e9a0ac668d2283b8fea1534f8ba31d1692 (diff)
mac80211: Filter duplicate IE ids
mac80211 is lenient with respect to reception of corrupted beacons. Even if the frame is corrupted as a whole, the available IE elements are still passed back and accepted, sometimes replacing legitimate data. It is unknown to what extent this "feature" is made use of, but it is clear that in some cases, this is detrimental. One such case is reported in http://crosbug.com/26832 where an AP corrupts its beacons but not its probe responses. One approach would be to completely reject frames with invaid data (for example, if the last tag extends beyond the end of the enclosing PDU). The enclosed approach is much more conservative: we simply prevent later IEs from overwriting the state from previous ones. This approach hopes that there might be some salient data in the IE stream before the corruption, and seeks to at least prevent that data from being overwritten. This approach will fix the case above. Further, we flag element structures that contain data we think might be corrupted, so that as we fill the mac80211 BSS structure, we try not to replace data from an un-corrupted probe response with that of a corrupted beacon, for example. Short of any statistics gathering in the various forms of AP breakage, it's not possible to ascertain the side effects of more stringent discarding of data. Signed-off-by: Paul Stewart <pstew@chromium.org> Cc: Sam Leffler <sleffler@chromium.org> Cc: Eliad Peller <eliad@wizery.com> Acked-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r--net/mac80211/util.c37
1 files changed, 35 insertions, 2 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 0a5ad95ac8b..32f7a3b3d43 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -572,24 +572,40 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
572 size_t left = len; 572 size_t left = len;
573 u8 *pos = start; 573 u8 *pos = start;
574 bool calc_crc = filter != 0; 574 bool calc_crc = filter != 0;
575 DECLARE_BITMAP(seen_elems, 256);
575 576
577 bitmap_zero(seen_elems, 256);
576 memset(elems, 0, sizeof(*elems)); 578 memset(elems, 0, sizeof(*elems));
577 elems->ie_start = start; 579 elems->ie_start = start;
578 elems->total_len = len; 580 elems->total_len = len;
579 581
580 while (left >= 2) { 582 while (left >= 2) {
581 u8 id, elen; 583 u8 id, elen;
584 bool elem_parse_failed;
582 585
583 id = *pos++; 586 id = *pos++;
584 elen = *pos++; 587 elen = *pos++;
585 left -= 2; 588 left -= 2;
586 589
587 if (elen > left) 590 if (elen > left) {
591 elems->parse_error = true;
588 break; 592 break;
593 }
594
595 if (id != WLAN_EID_VENDOR_SPECIFIC &&
596 id != WLAN_EID_QUIET &&
597 test_bit(id, seen_elems)) {
598 elems->parse_error = true;
599 left -= elen;
600 pos += elen;
601 continue;
602 }
589 603
590 if (calc_crc && id < 64 && (filter & (1ULL << id))) 604 if (calc_crc && id < 64 && (filter & (1ULL << id)))
591 crc = crc32_be(crc, pos - 2, elen + 2); 605 crc = crc32_be(crc, pos - 2, elen + 2);
592 606
607 elem_parse_failed = false;
608
593 switch (id) { 609 switch (id) {
594 case WLAN_EID_SSID: 610 case WLAN_EID_SSID:
595 elems->ssid = pos; 611 elems->ssid = pos;
@@ -615,7 +631,8 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
615 if (elen >= sizeof(struct ieee80211_tim_ie)) { 631 if (elen >= sizeof(struct ieee80211_tim_ie)) {
616 elems->tim = (void *)pos; 632 elems->tim = (void *)pos;
617 elems->tim_len = elen; 633 elems->tim_len = elen;
618 } 634 } else
635 elem_parse_failed = true;
619 break; 636 break;
620 case WLAN_EID_IBSS_PARAMS: 637 case WLAN_EID_IBSS_PARAMS:
621 elems->ibss_params = pos; 638 elems->ibss_params = pos;
@@ -664,10 +681,14 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
664 case WLAN_EID_HT_CAPABILITY: 681 case WLAN_EID_HT_CAPABILITY:
665 if (elen >= sizeof(struct ieee80211_ht_cap)) 682 if (elen >= sizeof(struct ieee80211_ht_cap))
666 elems->ht_cap_elem = (void *)pos; 683 elems->ht_cap_elem = (void *)pos;
684 else
685 elem_parse_failed = true;
667 break; 686 break;
668 case WLAN_EID_HT_INFORMATION: 687 case WLAN_EID_HT_INFORMATION:
669 if (elen >= sizeof(struct ieee80211_ht_info)) 688 if (elen >= sizeof(struct ieee80211_ht_info))
670 elems->ht_info_elem = (void *)pos; 689 elems->ht_info_elem = (void *)pos;
690 else
691 elem_parse_failed = true;
671 break; 692 break;
672 case WLAN_EID_MESH_ID: 693 case WLAN_EID_MESH_ID:
673 elems->mesh_id = pos; 694 elems->mesh_id = pos;
@@ -676,6 +697,8 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
676 case WLAN_EID_MESH_CONFIG: 697 case WLAN_EID_MESH_CONFIG:
677 if (elen >= sizeof(struct ieee80211_meshconf_ie)) 698 if (elen >= sizeof(struct ieee80211_meshconf_ie))
678 elems->mesh_config = (void *)pos; 699 elems->mesh_config = (void *)pos;
700 else
701 elem_parse_failed = true;
679 break; 702 break;
680 case WLAN_EID_PEER_MGMT: 703 case WLAN_EID_PEER_MGMT:
681 elems->peering = pos; 704 elems->peering = pos;
@@ -696,6 +719,8 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
696 case WLAN_EID_RANN: 719 case WLAN_EID_RANN:
697 if (elen >= sizeof(struct ieee80211_rann_ie)) 720 if (elen >= sizeof(struct ieee80211_rann_ie))
698 elems->rann = (void *)pos; 721 elems->rann = (void *)pos;
722 else
723 elem_parse_failed = true;
699 break; 724 break;
700 case WLAN_EID_CHANNEL_SWITCH: 725 case WLAN_EID_CHANNEL_SWITCH:
701 elems->ch_switch_elem = pos; 726 elems->ch_switch_elem = pos;
@@ -724,10 +749,18 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
724 break; 749 break;
725 } 750 }
726 751
752 if (elem_parse_failed)
753 elems->parse_error = true;
754 else
755 set_bit(id, seen_elems);
756
727 left -= elen; 757 left -= elen;
728 pos += elen; 758 pos += elen;
729 } 759 }
730 760
761 if (left != 0)
762 elems->parse_error = true;
763
731 return crc; 764 return crc;
732} 765}
733 766