aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-03-28 05:44:18 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-04-16 09:29:46 -0400
commitcd64f2a9b4a9eb055e4adc14b559055775b1b62f (patch)
tree5a3dd833390e9b349e16a14aafaebb4f5c0aaca2
parentb2e506bfc4d752b68a0ccaae1e977898263eba4c (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.c96
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,