aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/iwlegacy/4965-mac.c32
-rw-r--r--drivers/net/wireless/iwlegacy/4965.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/devices.c10
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/mac80211.c20
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/rxon.c2
-rw-r--r--drivers/net/wireless/ti/wl12xx/cmd.c2
-rw-r--r--drivers/net/wireless/ti/wl18xx/cmd.c6
-rw-r--r--include/linux/ieee80211.h11
-rw-r--r--include/net/mac80211.h4
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/mlme.c71
-rw-r--r--net/mac80211/trace.h8
-rw-r--r--net/mac80211/util.c8
13 files changed, 125 insertions, 54 deletions
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index c092fcbbe965..cb5882ea5f3a 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -6057,7 +6057,7 @@ il4965_mac_channel_switch(struct ieee80211_hw *hw,
6057 struct il_priv *il = hw->priv; 6057 struct il_priv *il = hw->priv;
6058 const struct il_channel_info *ch_info; 6058 const struct il_channel_info *ch_info;
6059 struct ieee80211_conf *conf = &hw->conf; 6059 struct ieee80211_conf *conf = &hw->conf;
6060 struct ieee80211_channel *channel = ch_switch->channel; 6060 struct ieee80211_channel *channel = ch_switch->chandef.chan;
6061 struct il_ht_config *ht_conf = &il->current_ht_config; 6061 struct il_ht_config *ht_conf = &il->current_ht_config;
6062 u16 ch; 6062 u16 ch;
6063 6063
@@ -6094,23 +6094,21 @@ il4965_mac_channel_switch(struct ieee80211_hw *hw,
6094 il->current_ht_config.smps = conf->smps_mode; 6094 il->current_ht_config.smps = conf->smps_mode;
6095 6095
6096 /* Configure HT40 channels */ 6096 /* Configure HT40 channels */
6097 il->ht.enabled = conf_is_ht(conf); 6097 switch (cfg80211_get_chandef_type(&ch_switch->chandef)) {
6098 if (il->ht.enabled) { 6098 case NL80211_CHAN_NO_HT:
6099 if (conf_is_ht40_minus(conf)) { 6099 case NL80211_CHAN_HT20:
6100 il->ht.extension_chan_offset =
6101 IEEE80211_HT_PARAM_CHA_SEC_BELOW;
6102 il->ht.is_40mhz = true;
6103 } else if (conf_is_ht40_plus(conf)) {
6104 il->ht.extension_chan_offset =
6105 IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
6106 il->ht.is_40mhz = true;
6107 } else {
6108 il->ht.extension_chan_offset =
6109 IEEE80211_HT_PARAM_CHA_SEC_NONE;
6110 il->ht.is_40mhz = false;
6111 }
6112 } else
6113 il->ht.is_40mhz = false; 6100 il->ht.is_40mhz = false;
6101 il->ht.extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
6102 break;
6103 case NL80211_CHAN_HT40MINUS:
6104 il->ht.extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
6105 il->ht.is_40mhz = true;
6106 break;
6107 case NL80211_CHAN_HT40PLUS:
6108 il->ht.extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
6109 il->ht.is_40mhz = true;
6110 break;
6111 }
6114 6112
6115 if ((le16_to_cpu(il->staging.channel) != ch)) 6113 if ((le16_to_cpu(il->staging.channel) != ch))
6116 il->staging.flags = 0; 6114 il->staging.flags = 0;
diff --git a/drivers/net/wireless/iwlegacy/4965.c b/drivers/net/wireless/iwlegacy/4965.c
index 91eb2d07fdb8..777a578294bd 100644
--- a/drivers/net/wireless/iwlegacy/4965.c
+++ b/drivers/net/wireless/iwlegacy/4965.c
@@ -1493,7 +1493,7 @@ il4965_hw_channel_switch(struct il_priv *il,
1493 1493
1494 cmd.band = band; 1494 cmd.band = band;
1495 cmd.expect_beacon = 0; 1495 cmd.expect_beacon = 0;
1496 ch = ch_switch->channel->hw_value; 1496 ch = ch_switch->chandef.chan->hw_value;
1497 cmd.channel = cpu_to_le16(ch); 1497 cmd.channel = cpu_to_le16(ch);
1498 cmd.rxon_flags = il->staging.flags; 1498 cmd.rxon_flags = il->staging.flags;
1499 cmd.rxon_filter_flags = il->staging.filter_flags; 1499 cmd.rxon_filter_flags = il->staging.filter_flags;
diff --git a/drivers/net/wireless/iwlwifi/dvm/devices.c b/drivers/net/wireless/iwlwifi/dvm/devices.c
index 15cca2ef9294..c48907c8ab43 100644
--- a/drivers/net/wireless/iwlwifi/dvm/devices.c
+++ b/drivers/net/wireless/iwlwifi/dvm/devices.c
@@ -379,7 +379,7 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
379 }; 379 };
380 380
381 cmd.band = priv->band == IEEE80211_BAND_2GHZ; 381 cmd.band = priv->band == IEEE80211_BAND_2GHZ;
382 ch = ch_switch->channel->hw_value; 382 ch = ch_switch->chandef.chan->hw_value;
383 IWL_DEBUG_11H(priv, "channel switch from %d to %d\n", 383 IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
384 ctx->active.channel, ch); 384 ctx->active.channel, ch);
385 cmd.channel = cpu_to_le16(ch); 385 cmd.channel = cpu_to_le16(ch);
@@ -414,7 +414,8 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
414 } 414 }
415 IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", 415 IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
416 cmd.switch_time); 416 cmd.switch_time);
417 cmd.expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR; 417 cmd.expect_beacon =
418 ch_switch->chandef.chan->flags & IEEE80211_CHAN_RADAR;
418 419
419 return iwl_dvm_send_cmd(priv, &hcmd); 420 return iwl_dvm_send_cmd(priv, &hcmd);
420} 421}
@@ -540,7 +541,7 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
540 hcmd.data[0] = cmd; 541 hcmd.data[0] = cmd;
541 542
542 cmd->band = priv->band == IEEE80211_BAND_2GHZ; 543 cmd->band = priv->band == IEEE80211_BAND_2GHZ;
543 ch = ch_switch->channel->hw_value; 544 ch = ch_switch->chandef.chan->hw_value;
544 IWL_DEBUG_11H(priv, "channel switch from %u to %u\n", 545 IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
545 ctx->active.channel, ch); 546 ctx->active.channel, ch);
546 cmd->channel = cpu_to_le16(ch); 547 cmd->channel = cpu_to_le16(ch);
@@ -575,7 +576,8 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
575 } 576 }
576 IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", 577 IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
577 cmd->switch_time); 578 cmd->switch_time);
578 cmd->expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR; 579 cmd->expect_beacon =
580 ch_switch->chandef.chan->flags & IEEE80211_CHAN_RADAR;
579 581
580 err = iwl_dvm_send_cmd(priv, &hcmd); 582 err = iwl_dvm_send_cmd(priv, &hcmd);
581 kfree(cmd); 583 kfree(cmd);
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index a7294fa4d7e5..2dc101fe0d24 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -967,7 +967,7 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
967{ 967{
968 struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); 968 struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
969 struct ieee80211_conf *conf = &hw->conf; 969 struct ieee80211_conf *conf = &hw->conf;
970 struct ieee80211_channel *channel = ch_switch->channel; 970 struct ieee80211_channel *channel = ch_switch->chandef.chan;
971 struct iwl_ht_config *ht_conf = &priv->current_ht_config; 971 struct iwl_ht_config *ht_conf = &priv->current_ht_config;
972 /* 972 /*
973 * MULTI-FIXME 973 * MULTI-FIXME
@@ -1005,11 +1005,21 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
1005 priv->current_ht_config.smps = conf->smps_mode; 1005 priv->current_ht_config.smps = conf->smps_mode;
1006 1006
1007 /* Configure HT40 channels */ 1007 /* Configure HT40 channels */
1008 ctx->ht.enabled = conf_is_ht(conf); 1008 switch (cfg80211_get_chandef_type(&ch_switch->chandef)) {
1009 if (ctx->ht.enabled) 1009 case NL80211_CHAN_NO_HT:
1010 iwlagn_config_ht40(conf, ctx); 1010 case NL80211_CHAN_HT20:
1011 else
1012 ctx->ht.is_40mhz = false; 1011 ctx->ht.is_40mhz = false;
1012 ctx->ht.extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
1013 break;
1014 case NL80211_CHAN_HT40MINUS:
1015 ctx->ht.extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
1016 ctx->ht.is_40mhz = true;
1017 break;
1018 case NL80211_CHAN_HT40PLUS:
1019 ctx->ht.extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
1020 ctx->ht.is_40mhz = true;
1021 break;
1022 }
1013 1023
1014 if ((le16_to_cpu(ctx->staging.channel) != ch)) 1024 if ((le16_to_cpu(ctx->staging.channel) != ch))
1015 ctx->staging.flags = 0; 1025 ctx->staging.flags = 0;
diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c
index 085c589e7149..acbb50b5f1e8 100644
--- a/drivers/net/wireless/iwlwifi/dvm/rxon.c
+++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c
@@ -1160,7 +1160,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
1160} 1160}
1161 1161
1162void iwlagn_config_ht40(struct ieee80211_conf *conf, 1162void iwlagn_config_ht40(struct ieee80211_conf *conf,
1163 struct iwl_rxon_context *ctx) 1163 struct iwl_rxon_context *ctx)
1164{ 1164{
1165 if (conf_is_ht40_minus(conf)) { 1165 if (conf_is_ht40_minus(conf)) {
1166 ctx->ht.extension_chan_offset = 1166 ctx->ht.extension_chan_offset =
diff --git a/drivers/net/wireless/ti/wl12xx/cmd.c b/drivers/net/wireless/ti/wl12xx/cmd.c
index 7dc9f965037d..7485dbae8c4b 100644
--- a/drivers/net/wireless/ti/wl12xx/cmd.c
+++ b/drivers/net/wireless/ti/wl12xx/cmd.c
@@ -301,7 +301,7 @@ int wl12xx_cmd_channel_switch(struct wl1271 *wl,
301 } 301 }
302 302
303 cmd->role_id = wlvif->role_id; 303 cmd->role_id = wlvif->role_id;
304 cmd->channel = ch_switch->channel->hw_value; 304 cmd->channel = ch_switch->chandef.chan->hw_value;
305 cmd->switch_time = ch_switch->count; 305 cmd->switch_time = ch_switch->count;
306 cmd->stop_tx = ch_switch->block_tx; 306 cmd->stop_tx = ch_switch->block_tx;
307 307
diff --git a/drivers/net/wireless/ti/wl18xx/cmd.c b/drivers/net/wireless/ti/wl18xx/cmd.c
index 1d1f6cc7a50a..7649c75cd68d 100644
--- a/drivers/net/wireless/ti/wl18xx/cmd.c
+++ b/drivers/net/wireless/ti/wl18xx/cmd.c
@@ -42,11 +42,11 @@ int wl18xx_cmd_channel_switch(struct wl1271 *wl,
42 } 42 }
43 43
44 cmd->role_id = wlvif->role_id; 44 cmd->role_id = wlvif->role_id;
45 cmd->channel = ch_switch->channel->hw_value; 45 cmd->channel = ch_switch->chandef.chan->hw_value;
46 cmd->switch_time = ch_switch->count; 46 cmd->switch_time = ch_switch->count;
47 cmd->stop_tx = ch_switch->block_tx; 47 cmd->stop_tx = ch_switch->block_tx;
48 48
49 switch (ch_switch->channel->band) { 49 switch (ch_switch->chandef.chan->band) {
50 case IEEE80211_BAND_2GHZ: 50 case IEEE80211_BAND_2GHZ:
51 cmd->band = WLCORE_BAND_2_4GHZ; 51 cmd->band = WLCORE_BAND_2_4GHZ;
52 break; 52 break;
@@ -55,7 +55,7 @@ int wl18xx_cmd_channel_switch(struct wl1271 *wl,
55 break; 55 break;
56 default: 56 default:
57 wl1271_error("invalid channel switch band: %d", 57 wl1271_error("invalid channel switch band: %d",
58 ch_switch->channel->band); 58 ch_switch->chandef.chan->band);
59 ret = -EINVAL; 59 ret = -EINVAL;
60 goto out_free; 60 goto out_free;
61 } 61 }
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 2a10acc65a54..95621528436c 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -685,6 +685,16 @@ struct ieee80211_ext_chansw_ie {
685} __packed; 685} __packed;
686 686
687/** 687/**
688 * struct ieee80211_sec_chan_offs_ie - secondary channel offset IE
689 * @sec_chan_offs: secondary channel offset, uses IEEE80211_HT_PARAM_CHA_SEC_*
690 * values here
691 * This structure represents the "Secondary Channel Offset element"
692 */
693struct ieee80211_sec_chan_offs_ie {
694 u8 sec_chan_offs;
695} __packed;
696
697/**
688 * struct ieee80211_tim 698 * struct ieee80211_tim
689 * 699 *
690 * This structure refers to "Traffic Indication Map information element" 700 * This structure refers to "Traffic Indication Map information element"
@@ -1648,6 +1658,7 @@ enum ieee80211_eid {
1648 1658
1649 WLAN_EID_HT_CAPABILITY = 45, 1659 WLAN_EID_HT_CAPABILITY = 45,
1650 WLAN_EID_HT_OPERATION = 61, 1660 WLAN_EID_HT_OPERATION = 61,
1661 WLAN_EID_SECONDARY_CHANNEL_OFFSET = 62,
1651 1662
1652 WLAN_EID_RSN = 48, 1663 WLAN_EID_RSN = 48,
1653 WLAN_EID_MMIE = 76, 1664 WLAN_EID_MMIE = 76,
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 0dde213dd3b6..9ff10b33b711 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1017,13 +1017,13 @@ struct ieee80211_conf {
1017 * the driver passed into mac80211. 1017 * the driver passed into mac80211.
1018 * @block_tx: Indicates whether transmission must be blocked before the 1018 * @block_tx: Indicates whether transmission must be blocked before the
1019 * scheduled channel switch, as indicated by the AP. 1019 * scheduled channel switch, as indicated by the AP.
1020 * @channel: the new channel to switch to 1020 * @chandef: the new channel to switch to
1021 * @count: the number of TBTT's until the channel switch event 1021 * @count: the number of TBTT's until the channel switch event
1022 */ 1022 */
1023struct ieee80211_channel_switch { 1023struct ieee80211_channel_switch {
1024 u64 timestamp; 1024 u64 timestamp;
1025 bool block_tx; 1025 bool block_tx;
1026 struct ieee80211_channel *channel; 1026 struct cfg80211_chan_def chandef;
1027 u8 count; 1027 u8 count;
1028}; 1028};
1029 1029
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 10c3180b165e..8f240c0ec304 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1019,7 +1019,7 @@ struct ieee80211_local {
1019 enum mac80211_scan_state next_scan_state; 1019 enum mac80211_scan_state next_scan_state;
1020 struct delayed_work scan_work; 1020 struct delayed_work scan_work;
1021 struct ieee80211_sub_if_data __rcu *scan_sdata; 1021 struct ieee80211_sub_if_data __rcu *scan_sdata;
1022 struct ieee80211_channel *csa_channel; 1022 struct cfg80211_chan_def csa_chandef;
1023 /* For backward compatibility only -- do not use */ 1023 /* For backward compatibility only -- do not use */
1024 struct cfg80211_chan_def _oper_chandef; 1024 struct cfg80211_chan_def _oper_chandef;
1025 1025
@@ -1183,6 +1183,7 @@ struct ieee802_11_elems {
1183 const u8 *pwr_constr_elem; 1183 const u8 *pwr_constr_elem;
1184 const struct ieee80211_timeout_interval_ie *timeout_int; 1184 const struct ieee80211_timeout_interval_ie *timeout_int;
1185 const u8 *opmode_notif; 1185 const u8 *opmode_notif;
1186 const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
1186 1187
1187 /* length of them, respectively */ 1188 /* length of them, respectively */
1188 u8 ssid_len; 1189 u8 ssid_len;
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
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 8286dcef228b..c215fafd7a2f 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -990,23 +990,23 @@ TRACE_EVENT(drv_channel_switch,
990 990
991 TP_STRUCT__entry( 991 TP_STRUCT__entry(
992 LOCAL_ENTRY 992 LOCAL_ENTRY
993 CHANDEF_ENTRY
993 __field(u64, timestamp) 994 __field(u64, timestamp)
994 __field(bool, block_tx) 995 __field(bool, block_tx)
995 __field(u16, freq)
996 __field(u8, count) 996 __field(u8, count)
997 ), 997 ),
998 998
999 TP_fast_assign( 999 TP_fast_assign(
1000 LOCAL_ASSIGN; 1000 LOCAL_ASSIGN;
1001 CHANDEF_ASSIGN(&ch_switch->chandef)
1001 __entry->timestamp = ch_switch->timestamp; 1002 __entry->timestamp = ch_switch->timestamp;
1002 __entry->block_tx = ch_switch->block_tx; 1003 __entry->block_tx = ch_switch->block_tx;
1003 __entry->freq = ch_switch->channel->center_freq;
1004 __entry->count = ch_switch->count; 1004 __entry->count = ch_switch->count;
1005 ), 1005 ),
1006 1006
1007 TP_printk( 1007 TP_printk(
1008 LOCAL_PR_FMT " new freq:%u count:%d", 1008 LOCAL_PR_FMT " new " CHANDEF_PR_FMT " count:%d",
1009 LOCAL_PR_ARG, __entry->freq, __entry->count 1009 LOCAL_PR_ARG, CHANDEF_PR_ARG, __entry->count
1010 ) 1010 )
1011); 1011);
1012 1012
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index e4a6d559372d..155056c90edf 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -716,6 +716,7 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
716 case WLAN_EID_COUNTRY: 716 case WLAN_EID_COUNTRY:
717 case WLAN_EID_PWR_CONSTRAINT: 717 case WLAN_EID_PWR_CONSTRAINT:
718 case WLAN_EID_TIMEOUT_INTERVAL: 718 case WLAN_EID_TIMEOUT_INTERVAL:
719 case WLAN_EID_SECONDARY_CHANNEL_OFFSET:
719 if (test_bit(id, seen_elems)) { 720 if (test_bit(id, seen_elems)) {
720 elems->parse_error = true; 721 elems->parse_error = true;
721 left -= elen; 722 left -= elen;
@@ -870,6 +871,13 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
870 } 871 }
871 elems->ext_chansw_ie = (void *)pos; 872 elems->ext_chansw_ie = (void *)pos;
872 break; 873 break;
874 case WLAN_EID_SECONDARY_CHANNEL_OFFSET:
875 if (elen != sizeof(struct ieee80211_sec_chan_offs_ie)) {
876 elem_parse_failed = true;
877 break;
878 }
879 elems->sec_chan_offs = (void *)pos;
880 break;
873 case WLAN_EID_COUNTRY: 881 case WLAN_EID_COUNTRY:
874 elems->country_elem = pos; 882 elems->country_elem = pos;
875 elems->country_elem_len = elen; 883 elems->country_elem_len = elen;