aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c71
1 files changed, 56 insertions, 15 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index bc6f87edc624..bd581a80e4b7 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -289,6 +289,8 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
289 } else { 289 } else {
290 /* 40 MHz (and 80 MHz) must be supported for VHT */ 290 /* 40 MHz (and 80 MHz) must be supported for VHT */
291 ret = IEEE80211_STA_DISABLE_VHT; 291 ret = IEEE80211_STA_DISABLE_VHT;
292 /* also mark 40 MHz disabled */
293 ret |= IEEE80211_STA_DISABLE_40MHZ;
292 goto out; 294 goto out;
293 } 295 }
294 296
@@ -964,16 +966,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
964 if (!ifmgd->associated) 966 if (!ifmgd->associated)
965 goto out; 967 goto out;
966 968
967 /* 969 local->_oper_chandef = local->csa_chandef;
968 * FIXME: Here we are downgrading to NL80211_CHAN_WIDTH_20_NOHT
969 * and don't adjust our ht/vht settings
970 * This is wrong - we should behave according to the CSA params
971 */
972 local->_oper_chandef.chan = local->csa_channel;
973 local->_oper_chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
974 local->_oper_chandef.center_freq1 =
975 local->_oper_chandef.chan->center_freq;
976 local->_oper_chandef.center_freq2 = 0;
977 970
978 if (!local->ops->channel_switch) { 971 if (!local->ops->channel_switch) {
979 /* call "hw_config" only if doing sw channel switch */ 972 /* call "hw_config" only if doing sw channel switch */
@@ -1028,13 +1021,14 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
1028 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 1021 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
1029 struct cfg80211_bss *cbss = ifmgd->associated; 1022 struct cfg80211_bss *cbss = ifmgd->associated;
1030 struct ieee80211_bss *bss; 1023 struct ieee80211_bss *bss;
1031 struct ieee80211_channel *new_ch;
1032 struct ieee80211_chanctx *chanctx; 1024 struct ieee80211_chanctx *chanctx;
1033 enum ieee80211_band new_band; 1025 enum ieee80211_band new_band;
1034 int new_freq; 1026 int new_freq;
1035 u8 new_chan_no; 1027 u8 new_chan_no;
1036 u8 count; 1028 u8 count;
1037 u8 mode; 1029 u8 mode;
1030 struct cfg80211_chan_def new_chandef = {};
1031 int secondary_channel_offset = -1;
1038 1032
1039 ASSERT_MGD_MTX(ifmgd); 1033 ASSERT_MGD_MTX(ifmgd);
1040 1034
@@ -1048,6 +1042,19 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
1048 if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) 1042 if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED)
1049 return; 1043 return;
1050 1044
1045 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
1046 /* if HT is enabled and the IE not present, it's still HT */
1047 secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
1048 if (elems->sec_chan_offs)
1049 secondary_channel_offset =
1050 elems->sec_chan_offs->sec_chan_offs;
1051 }
1052
1053 if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ &&
1054 (secondary_channel_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE ||
1055 secondary_channel_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW))
1056 secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
1057
1051 if (elems->ext_chansw_ie) { 1058 if (elems->ext_chansw_ie) {
1052 if (!ieee80211_operating_class_to_band( 1059 if (!ieee80211_operating_class_to_band(
1053 elems->ext_chansw_ie->new_operating_class, 1060 elems->ext_chansw_ie->new_operating_class,
@@ -1074,8 +1081,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
1074 bss = (void *)cbss->priv; 1081 bss = (void *)cbss->priv;
1075 1082
1076 new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band); 1083 new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band);
1077 new_ch = ieee80211_get_channel(local->hw.wiphy, new_freq); 1084 new_chandef.chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
1078 if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) { 1085 if (!new_chandef.chan ||
1086 new_chandef.chan->flags & IEEE80211_CHAN_DISABLED) {
1079 sdata_info(sdata, 1087 sdata_info(sdata,
1080 "AP %pM switches to unsupported channel (%d MHz), disconnecting\n", 1088 "AP %pM switches to unsupported channel (%d MHz), disconnecting\n",
1081 ifmgd->associated->bssid, new_freq); 1089 ifmgd->associated->bssid, new_freq);
@@ -1084,6 +1092,39 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
1084 return; 1092 return;
1085 } 1093 }
1086 1094
1095 switch (secondary_channel_offset) {
1096 default:
1097 /* secondary_channel_offset was present but is invalid */
1098 case IEEE80211_HT_PARAM_CHA_SEC_NONE:
1099 cfg80211_chandef_create(&new_chandef, new_chandef.chan,
1100 NL80211_CHAN_HT20);
1101 break;
1102 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
1103 cfg80211_chandef_create(&new_chandef, new_chandef.chan,
1104 NL80211_CHAN_HT40PLUS);
1105 break;
1106 case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
1107 cfg80211_chandef_create(&new_chandef, new_chandef.chan,
1108 NL80211_CHAN_HT40MINUS);
1109 break;
1110 case -1:
1111 cfg80211_chandef_create(&new_chandef, new_chandef.chan,
1112 NL80211_CHAN_NO_HT);
1113 break;
1114 }
1115
1116 if (!cfg80211_chandef_usable(local->hw.wiphy, &new_chandef,
1117 IEEE80211_CHAN_DISABLED)) {
1118 sdata_info(sdata,
1119 "AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
1120 ifmgd->associated->bssid, new_freq,
1121 new_chandef.width, new_chandef.center_freq1,
1122 new_chandef.center_freq2);
1123 ieee80211_queue_work(&local->hw,
1124 &ifmgd->csa_connection_drop_work);
1125 return;
1126 }
1127
1087 ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; 1128 ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
1088 1129
1089 if (local->use_chanctx) { 1130 if (local->use_chanctx) {
@@ -1111,7 +1152,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
1111 } 1152 }
1112 mutex_unlock(&local->chanctx_mtx); 1153 mutex_unlock(&local->chanctx_mtx);
1113 1154
1114 local->csa_channel = new_ch; 1155 local->csa_chandef = new_chandef;
1115 1156
1116 if (mode) 1157 if (mode)
1117 ieee80211_stop_queues_by_reason(&local->hw, 1158 ieee80211_stop_queues_by_reason(&local->hw,
@@ -1123,7 +1164,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
1123 struct ieee80211_channel_switch ch_switch = { 1164 struct ieee80211_channel_switch ch_switch = {
1124 .timestamp = timestamp, 1165 .timestamp = timestamp,
1125 .block_tx = mode, 1166 .block_tx = mode,
1126 .channel = new_ch, 1167 .chandef = new_chandef,
1127 .count = count, 1168 .count = count,
1128 }; 1169 };
1129 1170