aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
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
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')
-rw-r--r--net/mac80211/ieee80211_i.h41
-rw-r--r--net/mac80211/mlme.c14
-rw-r--r--net/mac80211/scan.c71
-rw-r--r--net/mac80211/util.c37
4 files changed, 141 insertions, 22 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 24cb1080e238..796b13bfc953 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -105,6 +105,44 @@ struct ieee80211_bss {
105 */ 105 */
106 bool has_erp_value; 106 bool has_erp_value;
107 u8 erp_value; 107 u8 erp_value;
108
109 /* Keep track of the corruption of the last beacon/probe response. */
110 u8 corrupt_data;
111
112 /* Keep track of what bits of information we have valid info for. */
113 u8 valid_data;
114};
115
116/**
117 * enum ieee80211_corrupt_data_flags - BSS data corruption flags
118 * @IEEE80211_BSS_CORRUPT_BEACON: last beacon frame received was corrupted
119 * @IEEE80211_BSS_CORRUPT_PROBE_RESP: last probe response received was corrupted
120 *
121 * These are bss flags that are attached to a bss in the
122 * @corrupt_data field of &struct ieee80211_bss.
123 */
124enum ieee80211_bss_corrupt_data_flags {
125 IEEE80211_BSS_CORRUPT_BEACON = BIT(0),
126 IEEE80211_BSS_CORRUPT_PROBE_RESP = BIT(1)
127};
128
129/**
130 * enum ieee80211_valid_data_flags - BSS valid data flags
131 * @IEEE80211_BSS_VALID_DTIM: DTIM data was gathered from non-corrupt IE
132 * @IEEE80211_BSS_VALID_WMM: WMM/UAPSD data was gathered from non-corrupt IE
133 * @IEEE80211_BSS_VALID_RATES: Supported rates were gathered from non-corrupt IE
134 * @IEEE80211_BSS_VALID_ERP: ERP flag was gathered from non-corrupt IE
135 *
136 * These are bss flags that are attached to a bss in the
137 * @valid_data field of &struct ieee80211_bss. They show which parts
138 * of the data structure were recieved as a result of an un-corrupted
139 * beacon/probe response.
140 */
141enum ieee80211_bss_valid_data_flags {
142 IEEE80211_BSS_VALID_DTIM = BIT(0),
143 IEEE80211_BSS_VALID_WMM = BIT(1),
144 IEEE80211_BSS_VALID_RATES = BIT(2),
145 IEEE80211_BSS_VALID_ERP = BIT(3)
108}; 146};
109 147
110static inline u8 *bss_mesh_cfg(struct ieee80211_bss *bss) 148static inline u8 *bss_mesh_cfg(struct ieee80211_bss *bss)
@@ -1120,6 +1158,9 @@ struct ieee802_11_elems {
1120 u8 quiet_elem_len; 1158 u8 quiet_elem_len;
1121 u8 num_of_quiet_elem; /* can be more the one */ 1159 u8 num_of_quiet_elem; /* can be more the one */
1122 u8 timeout_int_len; 1160 u8 timeout_int_len;
1161
1162 /* whether a parse error occurred while retrieving these elements */
1163 bool parse_error;
1123}; 1164};
1124 1165
1125static inline struct ieee80211_local *hw_to_local( 1166static inline struct ieee80211_local *hw_to_local(
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 92c5eb124d6f..c08924aeac00 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3446,6 +3446,20 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
3446 } 3446 }
3447 run_again(ifmgd, assoc_data->timeout); 3447 run_again(ifmgd, assoc_data->timeout);
3448 3448
3449 if (bss->corrupt_data) {
3450 char *corrupt_type = "data";
3451 if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_BEACON) {
3452 if (bss->corrupt_data &
3453 IEEE80211_BSS_CORRUPT_PROBE_RESP)
3454 corrupt_type = "beacon and probe response";
3455 else
3456 corrupt_type = "beacon";
3457 } else if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_PROBE_RESP)
3458 corrupt_type = "probe response";
3459 printk(KERN_DEBUG "%s: associating with AP with corrupt %s\n",
3460 sdata->name, corrupt_type);
3461 }
3462
3449 err = 0; 3463 err = 0;
3450 goto out; 3464 goto out;
3451 err_clear: 3465 err_clear:
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index a9d7235df7c3..33cd16901378 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -104,16 +104,35 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
104 cbss->free_priv = ieee80211_rx_bss_free; 104 cbss->free_priv = ieee80211_rx_bss_free;
105 bss = (void *)cbss->priv; 105 bss = (void *)cbss->priv;
106 106
107 if (elems->parse_error) {
108 if (beacon)
109 bss->corrupt_data |= IEEE80211_BSS_CORRUPT_BEACON;
110 else
111 bss->corrupt_data |= IEEE80211_BSS_CORRUPT_PROBE_RESP;
112 } else {
113 if (beacon)
114 bss->corrupt_data &= ~IEEE80211_BSS_CORRUPT_BEACON;
115 else
116 bss->corrupt_data &= ~IEEE80211_BSS_CORRUPT_PROBE_RESP;
117 }
118
107 /* save the ERP value so that it is available at association time */ 119 /* save the ERP value so that it is available at association time */
108 if (elems->erp_info && elems->erp_info_len >= 1) { 120 if (elems->erp_info && elems->erp_info_len >= 1 &&
121 (!elems->parse_error ||
122 !(bss->valid_data & IEEE80211_BSS_VALID_ERP))) {
109 bss->erp_value = elems->erp_info[0]; 123 bss->erp_value = elems->erp_info[0];
110 bss->has_erp_value = true; 124 bss->has_erp_value = true;
125 if (!elems->parse_error)
126 bss->valid_data |= IEEE80211_BSS_VALID_ERP;
111 } 127 }
112 128
113 if (elems->tim) { 129 if (elems->tim && (!elems->parse_error ||
130 !(bss->valid_data & IEEE80211_BSS_VALID_DTIM))) {
114 struct ieee80211_tim_ie *tim_ie = 131 struct ieee80211_tim_ie *tim_ie =
115 (struct ieee80211_tim_ie *)elems->tim; 132 (struct ieee80211_tim_ie *)elems->tim;
116 bss->dtim_period = tim_ie->dtim_period; 133 bss->dtim_period = tim_ie->dtim_period;
134 if (!elems->parse_error)
135 bss->valid_data |= IEEE80211_BSS_VALID_DTIM;
117 } 136 }
118 137
119 /* If the beacon had no TIM IE, or it was invalid, use 1 */ 138 /* If the beacon had no TIM IE, or it was invalid, use 1 */
@@ -121,26 +140,38 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
121 bss->dtim_period = 1; 140 bss->dtim_period = 1;
122 141
123 /* replace old supported rates if we get new values */ 142 /* replace old supported rates if we get new values */
124 srlen = 0; 143 if (!elems->parse_error ||
125 if (elems->supp_rates) { 144 !(bss->valid_data & IEEE80211_BSS_VALID_RATES)) {
126 clen = IEEE80211_MAX_SUPP_RATES; 145 srlen = 0;
127 if (clen > elems->supp_rates_len) 146 if (elems->supp_rates) {
128 clen = elems->supp_rates_len; 147 clen = IEEE80211_MAX_SUPP_RATES;
129 memcpy(bss->supp_rates, elems->supp_rates, clen); 148 if (clen > elems->supp_rates_len)
130 srlen += clen; 149 clen = elems->supp_rates_len;
131 } 150 memcpy(bss->supp_rates, elems->supp_rates, clen);
132 if (elems->ext_supp_rates) { 151 srlen += clen;
133 clen = IEEE80211_MAX_SUPP_RATES - srlen; 152 }
134 if (clen > elems->ext_supp_rates_len) 153 if (elems->ext_supp_rates) {
135 clen = elems->ext_supp_rates_len; 154 clen = IEEE80211_MAX_SUPP_RATES - srlen;
136 memcpy(bss->supp_rates + srlen, elems->ext_supp_rates, clen); 155 if (clen > elems->ext_supp_rates_len)
137 srlen += clen; 156 clen = elems->ext_supp_rates_len;
157 memcpy(bss->supp_rates + srlen, elems->ext_supp_rates,
158 clen);
159 srlen += clen;
160 }
161 if (srlen) {
162 bss->supp_rates_len = srlen;
163 if (!elems->parse_error)
164 bss->valid_data |= IEEE80211_BSS_VALID_RATES;
165 }
138 } 166 }
139 if (srlen)
140 bss->supp_rates_len = srlen;
141 167
142 bss->wmm_used = elems->wmm_param || elems->wmm_info; 168 if (!elems->parse_error ||
143 bss->uapsd_supported = is_uapsd_supported(elems); 169 !(bss->valid_data & IEEE80211_BSS_VALID_WMM)) {
170 bss->wmm_used = elems->wmm_param || elems->wmm_info;
171 bss->uapsd_supported = is_uapsd_supported(elems);
172 if (!elems->parse_error)
173 bss->valid_data |= IEEE80211_BSS_VALID_WMM;
174 }
144 175
145 if (!beacon) 176 if (!beacon)
146 bss->last_probe_resp = jiffies; 177 bss->last_probe_resp = jiffies;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 0a5ad95ac8b0..32f7a3b3d43c 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