aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-03-26 09:54:16 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-04-16 09:29:45 -0400
commitb2e506bfc4d752b68a0ccaae1e977898263eba4c (patch)
tree1d5e3ea97c5a36de64f894d0a7232e861a10f201 /net/mac80211
parent1b3a2e494bc793445f576c5476e9767cf7621684 (diff)
mac80211: parse VHT channel switch IEs
VHT introduces multiple IEs that need to be parsed for a wide bandwidth channel switch. Two are (currently) needed in mac80211: * wide bandwidth channel switch element * channel switch wrapper element The former is contained in the latter for beacons and probe responses, but not for the spectrum management action frames so the IE parser needs a new argument to differentiate them. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/ibss.c2
-rw-r--r--net/mac80211/ieee80211_i.h7
-rw-r--r--net/mac80211/mesh.c4
-rw-r--r--net/mac80211/mesh_hwmp.c2
-rw-r--r--net/mac80211/mesh_plink.c2
-rw-r--r--net/mac80211/mlme.c16
-rw-r--r--net/mac80211/scan.c2
-rw-r--r--net/mac80211/util.c36
8 files changed, 53 insertions, 18 deletions
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index b7bf6d76f1d9..170f9a7fa319 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -914,7 +914,7 @@ void ieee80211_rx_mgmt_probe_beacon(struct ieee80211_sub_if_data *sdata,
914 return; 914 return;
915 915
916 ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, 916 ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
917 &elems); 917 false, &elems);
918 918
919 ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); 919 ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
920} 920}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8f240c0ec304..f4a65a340a52 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1179,6 +1179,7 @@ struct ieee802_11_elems {
1179 const struct ieee80211_rann_ie *rann; 1179 const struct ieee80211_rann_ie *rann;
1180 const struct ieee80211_channel_sw_ie *ch_switch_ie; 1180 const struct ieee80211_channel_sw_ie *ch_switch_ie;
1181 const struct ieee80211_ext_chansw_ie *ext_chansw_ie; 1181 const struct ieee80211_ext_chansw_ie *ext_chansw_ie;
1182 const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
1182 const u8 *country_elem; 1183 const u8 *country_elem;
1183 const u8 *pwr_constr_elem; 1184 const u8 *pwr_constr_elem;
1184 const struct ieee80211_timeout_interval_ie *timeout_int; 1185 const struct ieee80211_timeout_interval_ie *timeout_int;
@@ -1490,13 +1491,13 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
1490 ieee80211_tx_skb_tid(sdata, skb, 7); 1491 ieee80211_tx_skb_tid(sdata, skb, 7);
1491} 1492}
1492 1493
1493u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, 1494u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, bool action,
1494 struct ieee802_11_elems *elems, 1495 struct ieee802_11_elems *elems,
1495 u64 filter, u32 crc); 1496 u64 filter, u32 crc);
1496static inline void ieee802_11_parse_elems(u8 *start, size_t len, 1497static inline void ieee802_11_parse_elems(u8 *start, size_t len, bool action,
1497 struct ieee802_11_elems *elems) 1498 struct ieee802_11_elems *elems)
1498{ 1499{
1499 ieee802_11_parse_elems_crc(start, len, elems, 0, 0); 1500 ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0);
1500} 1501}
1501 1502
1502u32 ieee80211_mandatory_rates(struct ieee80211_local *local, 1503u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 0acc2874d294..4b984765d62d 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -838,7 +838,7 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
838 if (baselen > len) 838 if (baselen > len)
839 return; 839 return;
840 840
841 ieee802_11_parse_elems(pos, len - baselen, &elems); 841 ieee802_11_parse_elems(pos, len - baselen, false, &elems);
842 842
843 /* 802.11-2012 10.1.4.3.2 */ 843 /* 802.11-2012 10.1.4.3.2 */
844 if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) && 844 if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) &&
@@ -899,7 +899,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
899 return; 899 return;
900 900
901 ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, 901 ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
902 &elems); 902 false, &elems);
903 903
904 /* ignore non-mesh or secure / unsecure mismatch */ 904 /* ignore non-mesh or secure / unsecure mismatch */
905 if ((!elems.mesh_id || !elems.mesh_config) || 905 if ((!elems.mesh_id || !elems.mesh_config) ||
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index c82d5e6a24c0..486819cd02cd 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -880,7 +880,7 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
880 880
881 baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt; 881 baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt;
882 ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, 882 ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
883 len - baselen, &elems); 883 len - baselen, false, &elems);
884 884
885 if (elems.preq) { 885 if (elems.preq) {
886 if (elems.preq_len != 37) 886 if (elems.preq_len != 37)
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index cdd41835334d..09bebed99416 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -687,7 +687,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
687 baseaddr += 4; 687 baseaddr += 4;
688 baselen += 4; 688 baselen += 4;
689 } 689 }
690 ieee802_11_parse_elems(baseaddr, len - baselen, &elems); 690 ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems);
691 691
692 if (!elems.peering) { 692 if (!elems.peering) {
693 mpl_dbg(sdata, 693 mpl_dbg(sdata,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index c53aedb47a6a..3e0421265bfe 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2203,7 +2203,7 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
2203 u32 tx_flags = 0; 2203 u32 tx_flags = 0;
2204 2204
2205 pos = mgmt->u.auth.variable; 2205 pos = mgmt->u.auth.variable;
2206 ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); 2206 ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), false, &elems);
2207 if (!elems.challenge) 2207 if (!elems.challenge)
2208 return; 2208 return;
2209 auth_data->expected_transaction = 4; 2209 auth_data->expected_transaction = 4;
@@ -2468,7 +2468,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
2468 } 2468 }
2469 2469
2470 pos = mgmt->u.assoc_resp.variable; 2470 pos = mgmt->u.assoc_resp.variable;
2471 ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); 2471 ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), false, &elems);
2472 2472
2473 if (!elems.supp_rates) { 2473 if (!elems.supp_rates) {
2474 sdata_info(sdata, "no SuppRates element in AssocResp\n"); 2474 sdata_info(sdata, "no SuppRates element in AssocResp\n");
@@ -2637,7 +2637,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
2637 capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); 2637 capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
2638 2638
2639 pos = mgmt->u.assoc_resp.variable; 2639 pos = mgmt->u.assoc_resp.variable;
2640 ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); 2640 ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), false, &elems);
2641 2641
2642 if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && 2642 if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
2643 elems.timeout_int && 2643 elems.timeout_int &&
@@ -2760,7 +2760,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
2760 return; 2760 return;
2761 2761
2762 ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, 2762 ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
2763 &elems); 2763 false, &elems);
2764 2764
2765 ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); 2765 ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
2766 2766
@@ -2843,7 +2843,7 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
2843 if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon && 2843 if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon &&
2844 ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) { 2844 ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) {
2845 ieee802_11_parse_elems(mgmt->u.beacon.variable, 2845 ieee802_11_parse_elems(mgmt->u.beacon.variable,
2846 len - baselen, &elems); 2846 len - baselen, false, &elems);
2847 2847
2848 ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); 2848 ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
2849 ifmgd->assoc_data->have_beacon = true; 2849 ifmgd->assoc_data->have_beacon = true;
@@ -2953,7 +2953,7 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
2953 2953
2954 ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); 2954 ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
2955 ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, 2955 ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable,
2956 len - baselen, &elems, 2956 len - baselen, false, &elems,
2957 care_about_ies, ncrc); 2957 care_about_ies, ncrc);
2958 2958
2959 if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) { 2959 if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) {
@@ -3141,7 +3141,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
3141 3141
3142 ieee802_11_parse_elems( 3142 ieee802_11_parse_elems(
3143 mgmt->u.action.u.chan_switch.variable, 3143 mgmt->u.action.u.chan_switch.variable,
3144 ies_len, &elems); 3144 ies_len, true, &elems);
3145 3145
3146 if (elems.parse_error) 3146 if (elems.parse_error)
3147 break; 3147 break;
@@ -3159,7 +3159,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
3159 3159
3160 ieee802_11_parse_elems( 3160 ieee802_11_parse_elems(
3161 mgmt->u.action.u.ext_chan_switch.variable, 3161 mgmt->u.action.u.ext_chan_switch.variable,
3162 ies_len, &elems); 3162 ies_len, true, &elems);
3163 3163
3164 if (elems.parse_error) 3164 if (elems.parse_error)
3165 break; 3165 break;
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 33fbf1045690..99b103921a4b 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -181,7 +181,7 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
181 if (baselen > skb->len) 181 if (baselen > skb->len)
182 return; 182 return;
183 183
184 ieee802_11_parse_elems(elements, skb->len - baselen, &elems); 184 ieee802_11_parse_elems(elements, skb->len - baselen, false, &elems);
185 185
186 channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq); 186 channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
187 187
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 155056c90edf..3f87fa468b1f 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -661,7 +661,7 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
661} 661}
662EXPORT_SYMBOL(ieee80211_queue_delayed_work); 662EXPORT_SYMBOL(ieee80211_queue_delayed_work);
663 663
664u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, 664u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, bool action,
665 struct ieee802_11_elems *elems, 665 struct ieee802_11_elems *elems,
666 u64 filter, u32 crc) 666 u64 filter, u32 crc)
667{ 667{
@@ -669,6 +669,7 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
669 u8 *pos = start; 669 u8 *pos = start;
670 bool calc_crc = filter != 0; 670 bool calc_crc = filter != 0;
671 DECLARE_BITMAP(seen_elems, 256); 671 DECLARE_BITMAP(seen_elems, 256);
672 const u8 *ie;
672 673
673 bitmap_zero(seen_elems, 256); 674 bitmap_zero(seen_elems, 256);
674 memset(elems, 0, sizeof(*elems)); 675 memset(elems, 0, sizeof(*elems));
@@ -717,6 +718,11 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
717 case WLAN_EID_PWR_CONSTRAINT: 718 case WLAN_EID_PWR_CONSTRAINT:
718 case WLAN_EID_TIMEOUT_INTERVAL: 719 case WLAN_EID_TIMEOUT_INTERVAL:
719 case WLAN_EID_SECONDARY_CHANNEL_OFFSET: 720 case WLAN_EID_SECONDARY_CHANNEL_OFFSET:
721 case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
722 /*
723 * not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible
724 * that if the content gets bigger it might be needed more than once
725 */
720 if (test_bit(id, seen_elems)) { 726 if (test_bit(id, seen_elems)) {
721 elems->parse_error = true; 727 elems->parse_error = true;
722 left -= elen; 728 left -= elen;
@@ -878,6 +884,34 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
878 } 884 }
879 elems->sec_chan_offs = (void *)pos; 885 elems->sec_chan_offs = (void *)pos;
880 break; 886 break;
887 case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
888 if (!action ||
889 elen != sizeof(*elems->wide_bw_chansw_ie)) {
890 elem_parse_failed = true;
891 break;
892 }
893 elems->wide_bw_chansw_ie = (void *)pos;
894 break;
895 case WLAN_EID_CHANNEL_SWITCH_WRAPPER:
896 if (action) {
897 elem_parse_failed = true;
898 break;
899 }
900 /*
901 * This is a bit tricky, but as we only care about
902 * the wide bandwidth channel switch element, so
903 * just parse it out manually.
904 */
905 ie = cfg80211_find_ie(WLAN_EID_WIDE_BW_CHANNEL_SWITCH,
906 pos, elen);
907 if (ie) {
908 if (ie[1] == sizeof(*elems->wide_bw_chansw_ie))
909 elems->wide_bw_chansw_ie =
910 (void *)(ie + 2);
911 else
912 elem_parse_failed = true;
913 }
914 break;
881 case WLAN_EID_COUNTRY: 915 case WLAN_EID_COUNTRY:
882 elems->country_elem = pos; 916 elems->country_elem = pos;
883 elems->country_elem_len = elen; 917 elems->country_elem_len = elen;