diff options
-rw-r--r-- | drivers/net/wireless/iwlegacy/4965-mac.c | 32 | ||||
-rw-r--r-- | drivers/net/wireless/iwlegacy/4965.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/dvm/devices.c | 10 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/dvm/mac80211.c | 20 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/dvm/rxon.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wl12xx/cmd.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wl18xx/cmd.c | 6 | ||||
-rw-r--r-- | include/linux/ieee80211.h | 11 | ||||
-rw-r--r-- | include/net/mac80211.h | 4 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 71 | ||||
-rw-r--r-- | net/mac80211/trace.h | 8 | ||||
-rw-r--r-- | net/mac80211/util.c | 8 |
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 | ||
1162 | void iwlagn_config_ht40(struct ieee80211_conf *conf, | 1162 | void 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 | */ | ||
693 | struct 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 | */ |
1023 | struct ieee80211_channel_switch { | 1023 | struct 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; |