diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-03-26 09:54:16 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-04-16 09:29:45 -0400 |
commit | b2e506bfc4d752b68a0ccaae1e977898263eba4c (patch) | |
tree | 1d5e3ea97c5a36de64f894d0a7232e861a10f201 /net/mac80211 | |
parent | 1b3a2e494bc793445f576c5476e9767cf7621684 (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.c | 2 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 7 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 4 | ||||
-rw-r--r-- | net/mac80211/mesh_hwmp.c | 2 | ||||
-rw-r--r-- | net/mac80211/mesh_plink.c | 2 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 16 | ||||
-rw-r--r-- | net/mac80211/scan.c | 2 | ||||
-rw-r--r-- | net/mac80211/util.c | 36 |
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 | ||
1493 | u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | 1494 | u32 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); |
1496 | static inline void ieee802_11_parse_elems(u8 *start, size_t len, | 1497 | static 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 | ||
1502 | u32 ieee80211_mandatory_rates(struct ieee80211_local *local, | 1503 | u32 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 | } |
662 | EXPORT_SYMBOL(ieee80211_queue_delayed_work); | 662 | EXPORT_SYMBOL(ieee80211_queue_delayed_work); |
663 | 663 | ||
664 | u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | 664 | u32 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; |