diff options
author | Simon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de> | 2013-08-28 07:41:29 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-09-26 07:27:13 -0400 |
commit | e6b7cde4d3e155f118b81f1f62f86554c529083a (patch) | |
tree | f7d4b6a41f03d286feb3b1daab02d2e8c8c92bc3 /net/mac80211/mlme.c | |
parent | 774f073461dbee0decee7524d9b930a98a3dc30c (diff) |
mac80211: split off channel switch parsing function
The channel switch parsing function can be re-used for the IBSS code,
put the common part into an extra function.
Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
[also move/rename chandef_downgrade]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 239 |
1 files changed, 16 insertions, 223 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e396a2a97319..9fce0f49cd10 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -145,66 +145,6 @@ static int ecw2cw(int ecw) | |||
145 | return (1 << ecw) - 1; | 145 | return (1 << ecw) - 1; |
146 | } | 146 | } |
147 | 147 | ||
148 | static u32 chandef_downgrade(struct cfg80211_chan_def *c) | ||
149 | { | ||
150 | u32 ret; | ||
151 | int tmp; | ||
152 | |||
153 | switch (c->width) { | ||
154 | case NL80211_CHAN_WIDTH_20: | ||
155 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
156 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
157 | break; | ||
158 | case NL80211_CHAN_WIDTH_40: | ||
159 | c->width = NL80211_CHAN_WIDTH_20; | ||
160 | c->center_freq1 = c->chan->center_freq; | ||
161 | ret = IEEE80211_STA_DISABLE_40MHZ | | ||
162 | IEEE80211_STA_DISABLE_VHT; | ||
163 | break; | ||
164 | case NL80211_CHAN_WIDTH_80: | ||
165 | tmp = (30 + c->chan->center_freq - c->center_freq1)/20; | ||
166 | /* n_P40 */ | ||
167 | tmp /= 2; | ||
168 | /* freq_P40 */ | ||
169 | c->center_freq1 = c->center_freq1 - 20 + 40 * tmp; | ||
170 | c->width = NL80211_CHAN_WIDTH_40; | ||
171 | ret = IEEE80211_STA_DISABLE_VHT; | ||
172 | break; | ||
173 | case NL80211_CHAN_WIDTH_80P80: | ||
174 | c->center_freq2 = 0; | ||
175 | c->width = NL80211_CHAN_WIDTH_80; | ||
176 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
177 | IEEE80211_STA_DISABLE_160MHZ; | ||
178 | break; | ||
179 | case NL80211_CHAN_WIDTH_160: | ||
180 | /* n_P20 */ | ||
181 | tmp = (70 + c->chan->center_freq - c->center_freq1)/20; | ||
182 | /* n_P80 */ | ||
183 | tmp /= 4; | ||
184 | c->center_freq1 = c->center_freq1 - 40 + 80 * tmp; | ||
185 | c->width = NL80211_CHAN_WIDTH_80; | ||
186 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
187 | IEEE80211_STA_DISABLE_160MHZ; | ||
188 | break; | ||
189 | default: | ||
190 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
191 | WARN_ON_ONCE(1); | ||
192 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
193 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
194 | break; | ||
195 | case NL80211_CHAN_WIDTH_5: | ||
196 | case NL80211_CHAN_WIDTH_10: | ||
197 | WARN_ON_ONCE(1); | ||
198 | /* keep c->width */ | ||
199 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
200 | break; | ||
201 | } | ||
202 | |||
203 | WARN_ON_ONCE(!cfg80211_chandef_valid(c)); | ||
204 | |||
205 | return ret; | ||
206 | } | ||
207 | |||
208 | static u32 | 148 | static u32 |
209 | ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | 149 | ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, |
210 | struct ieee80211_supported_band *sband, | 150 | struct ieee80211_supported_band *sband, |
@@ -352,7 +292,7 @@ out: | |||
352 | break; | 292 | break; |
353 | } | 293 | } |
354 | 294 | ||
355 | ret |= chandef_downgrade(chandef); | 295 | ret |= ieee80211_chandef_downgrade(chandef); |
356 | } | 296 | } |
357 | 297 | ||
358 | if (chandef->width != vht_chandef.width && !tracking) | 298 | if (chandef->width != vht_chandef.width && !tracking) |
@@ -406,13 +346,13 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, | |||
406 | */ | 346 | */ |
407 | if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ && | 347 | if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ && |
408 | chandef.width == NL80211_CHAN_WIDTH_80P80) | 348 | chandef.width == NL80211_CHAN_WIDTH_80P80) |
409 | flags |= chandef_downgrade(&chandef); | 349 | flags |= ieee80211_chandef_downgrade(&chandef); |
410 | if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ && | 350 | if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ && |
411 | chandef.width == NL80211_CHAN_WIDTH_160) | 351 | chandef.width == NL80211_CHAN_WIDTH_160) |
412 | flags |= chandef_downgrade(&chandef); | 352 | flags |= ieee80211_chandef_downgrade(&chandef); |
413 | if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ && | 353 | if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ && |
414 | chandef.width > NL80211_CHAN_WIDTH_20) | 354 | chandef.width > NL80211_CHAN_WIDTH_20) |
415 | flags |= chandef_downgrade(&chandef); | 355 | flags |= ieee80211_chandef_downgrade(&chandef); |
416 | 356 | ||
417 | if (cfg80211_chandef_identical(&chandef, &sdata->vif.bss_conf.chandef)) | 357 | if (cfg80211_chandef_identical(&chandef, &sdata->vif.bss_conf.chandef)) |
418 | return 0; | 358 | return 0; |
@@ -999,20 +939,12 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
999 | struct ieee80211_local *local = sdata->local; | 939 | struct ieee80211_local *local = sdata->local; |
1000 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 940 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1001 | struct cfg80211_bss *cbss = ifmgd->associated; | 941 | struct cfg80211_bss *cbss = ifmgd->associated; |
1002 | struct ieee80211_bss *bss; | ||
1003 | struct ieee80211_chanctx *chanctx; | 942 | struct ieee80211_chanctx *chanctx; |
1004 | enum ieee80211_band new_band; | 943 | enum ieee80211_band current_band; |
1005 | int new_freq; | ||
1006 | u8 new_chan_no; | ||
1007 | u8 count; | 944 | u8 count; |
1008 | u8 mode; | 945 | u8 mode; |
1009 | struct ieee80211_channel *new_chan; | ||
1010 | struct cfg80211_chan_def new_chandef = {}; | 946 | struct cfg80211_chan_def new_chandef = {}; |
1011 | struct cfg80211_chan_def new_vht_chandef = {}; | 947 | int res; |
1012 | const struct ieee80211_sec_chan_offs_ie *sec_chan_offs; | ||
1013 | const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie; | ||
1014 | const struct ieee80211_ht_operation *ht_oper; | ||
1015 | int secondary_channel_offset = -1; | ||
1016 | 948 | ||
1017 | sdata_assert_lock(sdata); | 949 | sdata_assert_lock(sdata); |
1018 | 950 | ||
@@ -1026,162 +958,23 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1026 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) | 958 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) |
1027 | return; | 959 | return; |
1028 | 960 | ||
1029 | sec_chan_offs = elems->sec_chan_offs; | 961 | current_band = cbss->channel->band; |
1030 | wide_bw_chansw_ie = elems->wide_bw_chansw_ie; | 962 | res = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, current_band, |
1031 | ht_oper = elems->ht_operation; | 963 | ifmgd->flags, |
1032 | 964 | ifmgd->associated->bssid, &count, | |
1033 | if (ifmgd->flags & (IEEE80211_STA_DISABLE_HT | | 965 | &mode, &new_chandef); |
1034 | IEEE80211_STA_DISABLE_40MHZ)) { | 966 | if (res < 0) |
1035 | sec_chan_offs = NULL; | ||
1036 | wide_bw_chansw_ie = NULL; | ||
1037 | /* only used for bandwidth here */ | ||
1038 | ht_oper = NULL; | ||
1039 | } | ||
1040 | |||
1041 | if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT) | ||
1042 | wide_bw_chansw_ie = NULL; | ||
1043 | |||
1044 | if (elems->ext_chansw_ie) { | ||
1045 | if (!ieee80211_operating_class_to_band( | ||
1046 | elems->ext_chansw_ie->new_operating_class, | ||
1047 | &new_band)) { | ||
1048 | sdata_info(sdata, | ||
1049 | "cannot understand ECSA IE operating class %d, disconnecting\n", | ||
1050 | elems->ext_chansw_ie->new_operating_class); | ||
1051 | ieee80211_queue_work(&local->hw, | ||
1052 | &ifmgd->csa_connection_drop_work); | ||
1053 | } | ||
1054 | new_chan_no = elems->ext_chansw_ie->new_ch_num; | ||
1055 | count = elems->ext_chansw_ie->count; | ||
1056 | mode = elems->ext_chansw_ie->mode; | ||
1057 | } else if (elems->ch_switch_ie) { | ||
1058 | new_band = cbss->channel->band; | ||
1059 | new_chan_no = elems->ch_switch_ie->new_ch_num; | ||
1060 | count = elems->ch_switch_ie->count; | ||
1061 | mode = elems->ch_switch_ie->mode; | ||
1062 | } else { | ||
1063 | /* nothing here we understand */ | ||
1064 | return; | ||
1065 | } | ||
1066 | |||
1067 | bss = (void *)cbss->priv; | ||
1068 | |||
1069 | new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band); | ||
1070 | new_chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); | ||
1071 | if (!new_chan || new_chan->flags & IEEE80211_CHAN_DISABLED) { | ||
1072 | sdata_info(sdata, | ||
1073 | "AP %pM switches to unsupported channel (%d MHz), disconnecting\n", | ||
1074 | ifmgd->associated->bssid, new_freq); | ||
1075 | ieee80211_queue_work(&local->hw, | 967 | ieee80211_queue_work(&local->hw, |
1076 | &ifmgd->csa_connection_drop_work); | 968 | &ifmgd->csa_connection_drop_work); |
969 | if (res) | ||
1077 | return; | 970 | return; |
1078 | } | ||
1079 | |||
1080 | if (!beacon && sec_chan_offs) { | ||
1081 | secondary_channel_offset = sec_chan_offs->sec_chan_offs; | ||
1082 | } else if (beacon && ht_oper) { | ||
1083 | secondary_channel_offset = | ||
1084 | ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET; | ||
1085 | } else if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { | ||
1086 | /* | ||
1087 | * If it's not a beacon, HT is enabled and the IE not present, | ||
1088 | * it's 20 MHz, 802.11-2012 8.5.2.6: | ||
1089 | * This element [the Secondary Channel Offset Element] is | ||
1090 | * present when switching to a 40 MHz channel. It may be | ||
1091 | * present when switching to a 20 MHz channel (in which | ||
1092 | * case the secondary channel offset is set to SCN). | ||
1093 | */ | ||
1094 | secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; | ||
1095 | } | ||
1096 | |||
1097 | switch (secondary_channel_offset) { | ||
1098 | default: | ||
1099 | /* secondary_channel_offset was present but is invalid */ | ||
1100 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: | ||
1101 | cfg80211_chandef_create(&new_chandef, new_chan, | ||
1102 | NL80211_CHAN_HT20); | ||
1103 | break; | ||
1104 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
1105 | cfg80211_chandef_create(&new_chandef, new_chan, | ||
1106 | NL80211_CHAN_HT40PLUS); | ||
1107 | break; | ||
1108 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
1109 | cfg80211_chandef_create(&new_chandef, new_chan, | ||
1110 | NL80211_CHAN_HT40MINUS); | ||
1111 | break; | ||
1112 | case -1: | ||
1113 | cfg80211_chandef_create(&new_chandef, new_chan, | ||
1114 | NL80211_CHAN_NO_HT); | ||
1115 | /* keep width for 5/10 MHz channels */ | ||
1116 | switch (sdata->vif.bss_conf.chandef.width) { | ||
1117 | case NL80211_CHAN_WIDTH_5: | ||
1118 | case NL80211_CHAN_WIDTH_10: | ||
1119 | new_chandef.width = sdata->vif.bss_conf.chandef.width; | ||
1120 | break; | ||
1121 | default: | ||
1122 | break; | ||
1123 | } | ||
1124 | break; | ||
1125 | } | ||
1126 | |||
1127 | if (wide_bw_chansw_ie) { | ||
1128 | new_vht_chandef.chan = new_chan; | ||
1129 | new_vht_chandef.center_freq1 = | ||
1130 | ieee80211_channel_to_frequency( | ||
1131 | wide_bw_chansw_ie->new_center_freq_seg0, | ||
1132 | new_band); | ||
1133 | |||
1134 | switch (wide_bw_chansw_ie->new_channel_width) { | ||
1135 | default: | ||
1136 | /* hmmm, ignore VHT and use HT if present */ | ||
1137 | case IEEE80211_VHT_CHANWIDTH_USE_HT: | ||
1138 | new_vht_chandef.chan = NULL; | ||
1139 | break; | ||
1140 | case IEEE80211_VHT_CHANWIDTH_80MHZ: | ||
1141 | new_vht_chandef.width = NL80211_CHAN_WIDTH_80; | ||
1142 | break; | ||
1143 | case IEEE80211_VHT_CHANWIDTH_160MHZ: | ||
1144 | new_vht_chandef.width = NL80211_CHAN_WIDTH_160; | ||
1145 | break; | ||
1146 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: | ||
1147 | /* field is otherwise reserved */ | ||
1148 | new_vht_chandef.center_freq2 = | ||
1149 | ieee80211_channel_to_frequency( | ||
1150 | wide_bw_chansw_ie->new_center_freq_seg1, | ||
1151 | new_band); | ||
1152 | new_vht_chandef.width = NL80211_CHAN_WIDTH_80P80; | ||
1153 | break; | ||
1154 | } | ||
1155 | if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ && | ||
1156 | new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80) | ||
1157 | chandef_downgrade(&new_vht_chandef); | ||
1158 | if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ && | ||
1159 | new_vht_chandef.width == NL80211_CHAN_WIDTH_160) | ||
1160 | chandef_downgrade(&new_vht_chandef); | ||
1161 | if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ && | ||
1162 | new_vht_chandef.width > NL80211_CHAN_WIDTH_20) | ||
1163 | chandef_downgrade(&new_vht_chandef); | ||
1164 | } | ||
1165 | |||
1166 | /* if VHT data is there validate & use it */ | ||
1167 | if (new_vht_chandef.chan) { | ||
1168 | if (!cfg80211_chandef_compatible(&new_vht_chandef, | ||
1169 | &new_chandef)) { | ||
1170 | sdata_info(sdata, | ||
1171 | "AP %pM CSA has inconsistent channel data, disconnecting\n", | ||
1172 | ifmgd->associated->bssid); | ||
1173 | ieee80211_queue_work(&local->hw, | ||
1174 | &ifmgd->csa_connection_drop_work); | ||
1175 | return; | ||
1176 | } | ||
1177 | new_chandef = new_vht_chandef; | ||
1178 | } | ||
1179 | 971 | ||
1180 | if (!cfg80211_chandef_usable(local->hw.wiphy, &new_chandef, | 972 | if (!cfg80211_chandef_usable(local->hw.wiphy, &new_chandef, |
1181 | IEEE80211_CHAN_DISABLED)) { | 973 | IEEE80211_CHAN_DISABLED)) { |
1182 | sdata_info(sdata, | 974 | sdata_info(sdata, |
1183 | "AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n", | 975 | "AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n", |
1184 | ifmgd->associated->bssid, new_freq, | 976 | ifmgd->associated->bssid, |
977 | new_chandef.chan->center_freq, | ||
1185 | new_chandef.width, new_chandef.center_freq1, | 978 | new_chandef.width, new_chandef.center_freq1, |
1186 | new_chandef.center_freq2); | 979 | new_chandef.center_freq2); |
1187 | ieee80211_queue_work(&local->hw, | 980 | ieee80211_queue_work(&local->hw, |
@@ -3856,7 +3649,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | |||
3856 | return ret; | 3649 | return ret; |
3857 | 3650 | ||
3858 | while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { | 3651 | while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { |
3859 | ifmgd->flags |= chandef_downgrade(&chandef); | 3652 | ifmgd->flags |= ieee80211_chandef_downgrade(&chandef); |
3860 | ret = ieee80211_vif_use_channel(sdata, &chandef, | 3653 | ret = ieee80211_vif_use_channel(sdata, &chandef, |
3861 | IEEE80211_CHANCTX_SHARED); | 3654 | IEEE80211_CHANCTX_SHARED); |
3862 | } | 3655 | } |