diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-03-28 05:44:18 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-04-16 09:29:46 -0400 |
commit | cd64f2a9b4a9eb055e4adc14b559055775b1b62f (patch) | |
tree | 5a3dd833390e9b349e16a14aafaebb4f5c0aaca2 | |
parent | b2e506bfc4d752b68a0ccaae1e977898263eba4c (diff) |
mac80211: handle wide bandwidth channel switch
Parse and react to the wide bandwidth channel switch element
in beacons/action frames. Finding the element was done in a
previous patch (it has different positions in beacons/action
frames), now handle it. If there's something wrong with it
simply disconnect.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | net/mac80211/mlme.c | 96 |
1 files changed, 79 insertions, 17 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3e0421265bfe..43023f0db68c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1027,7 +1027,11 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1027 | u8 new_chan_no; | 1027 | u8 new_chan_no; |
1028 | u8 count; | 1028 | u8 count; |
1029 | u8 mode; | 1029 | u8 mode; |
1030 | struct ieee80211_channel *new_chan; | ||
1030 | struct cfg80211_chan_def new_chandef = {}; | 1031 | struct cfg80211_chan_def new_chandef = {}; |
1032 | struct cfg80211_chan_def new_vht_chandef = {}; | ||
1033 | const struct ieee80211_sec_chan_offs_ie *sec_chan_offs; | ||
1034 | const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie; | ||
1031 | int secondary_channel_offset = -1; | 1035 | int secondary_channel_offset = -1; |
1032 | 1036 | ||
1033 | ASSERT_MGD_MTX(ifmgd); | 1037 | ASSERT_MGD_MTX(ifmgd); |
@@ -1042,18 +1046,17 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1042 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) | 1046 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) |
1043 | return; | 1047 | return; |
1044 | 1048 | ||
1045 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { | 1049 | sec_chan_offs = elems->sec_chan_offs; |
1046 | /* if HT is enabled and the IE not present, it's still HT */ | 1050 | wide_bw_chansw_ie = elems->wide_bw_chansw_ie; |
1047 | secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; | 1051 | |
1048 | if (elems->sec_chan_offs) | 1052 | if (ifmgd->flags & (IEEE80211_STA_DISABLE_HT | |
1049 | secondary_channel_offset = | 1053 | IEEE80211_STA_DISABLE_40MHZ)) { |
1050 | elems->sec_chan_offs->sec_chan_offs; | 1054 | sec_chan_offs = NULL; |
1055 | wide_bw_chansw_ie = NULL; | ||
1051 | } | 1056 | } |
1052 | 1057 | ||
1053 | if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ && | 1058 | if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT) |
1054 | (secondary_channel_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE || | 1059 | wide_bw_chansw_ie = NULL; |
1055 | secondary_channel_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)) | ||
1056 | secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; | ||
1057 | 1060 | ||
1058 | if (elems->ext_chansw_ie) { | 1061 | if (elems->ext_chansw_ie) { |
1059 | if (!ieee80211_operating_class_to_band( | 1062 | if (!ieee80211_operating_class_to_band( |
@@ -1081,9 +1084,8 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1081 | bss = (void *)cbss->priv; | 1084 | bss = (void *)cbss->priv; |
1082 | 1085 | ||
1083 | new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band); | 1086 | new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band); |
1084 | new_chandef.chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); | 1087 | new_chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); |
1085 | if (!new_chandef.chan || | 1088 | if (!new_chan || new_chan->flags & IEEE80211_CHAN_DISABLED) { |
1086 | new_chandef.chan->flags & IEEE80211_CHAN_DISABLED) { | ||
1087 | sdata_info(sdata, | 1089 | sdata_info(sdata, |
1088 | "AP %pM switches to unsupported channel (%d MHz), disconnecting\n", | 1090 | "AP %pM switches to unsupported channel (%d MHz), disconnecting\n", |
1089 | ifmgd->associated->bssid, new_freq); | 1091 | ifmgd->associated->bssid, new_freq); |
@@ -1092,27 +1094,87 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1092 | return; | 1094 | return; |
1093 | } | 1095 | } |
1094 | 1096 | ||
1097 | if (sec_chan_offs) { | ||
1098 | secondary_channel_offset = sec_chan_offs->sec_chan_offs; | ||
1099 | } else if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { | ||
1100 | /* if HT is enabled and the IE not present, it's still HT */ | ||
1101 | secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; | ||
1102 | } | ||
1103 | |||
1095 | switch (secondary_channel_offset) { | 1104 | switch (secondary_channel_offset) { |
1096 | default: | 1105 | default: |
1097 | /* secondary_channel_offset was present but is invalid */ | 1106 | /* secondary_channel_offset was present but is invalid */ |
1098 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: | 1107 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: |
1099 | cfg80211_chandef_create(&new_chandef, new_chandef.chan, | 1108 | cfg80211_chandef_create(&new_chandef, new_chan, |
1100 | NL80211_CHAN_HT20); | 1109 | NL80211_CHAN_HT20); |
1101 | break; | 1110 | break; |
1102 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | 1111 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: |
1103 | cfg80211_chandef_create(&new_chandef, new_chandef.chan, | 1112 | cfg80211_chandef_create(&new_chandef, new_chan, |
1104 | NL80211_CHAN_HT40PLUS); | 1113 | NL80211_CHAN_HT40PLUS); |
1105 | break; | 1114 | break; |
1106 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | 1115 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: |
1107 | cfg80211_chandef_create(&new_chandef, new_chandef.chan, | 1116 | cfg80211_chandef_create(&new_chandef, new_chan, |
1108 | NL80211_CHAN_HT40MINUS); | 1117 | NL80211_CHAN_HT40MINUS); |
1109 | break; | 1118 | break; |
1110 | case -1: | 1119 | case -1: |
1111 | cfg80211_chandef_create(&new_chandef, new_chandef.chan, | 1120 | cfg80211_chandef_create(&new_chandef, new_chan, |
1112 | NL80211_CHAN_NO_HT); | 1121 | NL80211_CHAN_NO_HT); |
1113 | break; | 1122 | break; |
1114 | } | 1123 | } |
1115 | 1124 | ||
1125 | if (wide_bw_chansw_ie) { | ||
1126 | new_vht_chandef.chan = new_chan; | ||
1127 | new_vht_chandef.center_freq1 = | ||
1128 | ieee80211_channel_to_frequency( | ||
1129 | wide_bw_chansw_ie->new_center_freq_seg0, | ||
1130 | new_band); | ||
1131 | |||
1132 | switch (wide_bw_chansw_ie->new_channel_width) { | ||
1133 | default: | ||
1134 | /* hmmm, ignore VHT and use HT if present */ | ||
1135 | case IEEE80211_VHT_CHANWIDTH_USE_HT: | ||
1136 | new_vht_chandef.chan = NULL; | ||
1137 | break; | ||
1138 | case IEEE80211_VHT_CHANWIDTH_80MHZ: | ||
1139 | new_vht_chandef.width = NL80211_CHAN_WIDTH_80; | ||
1140 | break; | ||
1141 | case IEEE80211_VHT_CHANWIDTH_160MHZ: | ||
1142 | new_vht_chandef.width = NL80211_CHAN_WIDTH_160; | ||
1143 | break; | ||
1144 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: | ||
1145 | /* field is otherwise reserved */ | ||
1146 | new_vht_chandef.center_freq2 = | ||
1147 | ieee80211_channel_to_frequency( | ||
1148 | wide_bw_chansw_ie->new_center_freq_seg1, | ||
1149 | new_band); | ||
1150 | new_vht_chandef.width = NL80211_CHAN_WIDTH_80P80; | ||
1151 | break; | ||
1152 | } | ||
1153 | if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ && | ||
1154 | new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80) | ||
1155 | chandef_downgrade(&new_vht_chandef); | ||
1156 | if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ && | ||
1157 | new_vht_chandef.width == NL80211_CHAN_WIDTH_160) | ||
1158 | chandef_downgrade(&new_vht_chandef); | ||
1159 | if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ && | ||
1160 | new_vht_chandef.width > NL80211_CHAN_WIDTH_20) | ||
1161 | chandef_downgrade(&new_vht_chandef); | ||
1162 | } | ||
1163 | |||
1164 | /* if VHT data is there validate & use it */ | ||
1165 | if (new_vht_chandef.chan) { | ||
1166 | if (!cfg80211_chandef_compatible(&new_vht_chandef, | ||
1167 | &new_chandef)) { | ||
1168 | sdata_info(sdata, | ||
1169 | "AP %pM CSA has inconsistent channel data, disconnecting\n", | ||
1170 | ifmgd->associated->bssid); | ||
1171 | ieee80211_queue_work(&local->hw, | ||
1172 | &ifmgd->csa_connection_drop_work); | ||
1173 | return; | ||
1174 | } | ||
1175 | new_chandef = new_vht_chandef; | ||
1176 | } | ||
1177 | |||
1116 | if (!cfg80211_chandef_usable(local->hw.wiphy, &new_chandef, | 1178 | if (!cfg80211_chandef_usable(local->hw.wiphy, &new_chandef, |
1117 | IEEE80211_CHAN_DISABLED)) { | 1179 | IEEE80211_CHAN_DISABLED)) { |
1118 | sdata_info(sdata, | 1180 | sdata_info(sdata, |