diff options
| author | John W. Linville <linville@tuxdriver.com> | 2013-04-22 14:58:14 -0400 |
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2013-04-22 14:58:14 -0400 |
| commit | 6475cb05ee17870c7c8d44146dbe09044e6db33d (patch) | |
| tree | 68fc82e4b9c4c4a1b261869add66bef3ee054926 | |
| parent | e563589f7187699b0217854467d857f53b29cc50 (diff) | |
| parent | 1eb32179f0593051e7536378a879f5bdd108416a (diff) | |
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
42 files changed, 1526 insertions, 616 deletions
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 5bc995a48519..431ae6cc5f8f 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 fc3879804622..cab23af0be9e 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c | |||
| @@ -970,7 +970,7 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, | |||
| 970 | { | 970 | { |
| 971 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); | 971 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); |
| 972 | struct ieee80211_conf *conf = &hw->conf; | 972 | struct ieee80211_conf *conf = &hw->conf; |
| 973 | struct ieee80211_channel *channel = ch_switch->channel; | 973 | struct ieee80211_channel *channel = ch_switch->chandef.chan; |
| 974 | struct iwl_ht_config *ht_conf = &priv->current_ht_config; | 974 | struct iwl_ht_config *ht_conf = &priv->current_ht_config; |
| 975 | /* | 975 | /* |
| 976 | * MULTI-FIXME | 976 | * MULTI-FIXME |
| @@ -1008,11 +1008,21 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, | |||
| 1008 | priv->current_ht_config.smps = conf->smps_mode; | 1008 | priv->current_ht_config.smps = conf->smps_mode; |
| 1009 | 1009 | ||
| 1010 | /* Configure HT40 channels */ | 1010 | /* Configure HT40 channels */ |
| 1011 | ctx->ht.enabled = conf_is_ht(conf); | 1011 | switch (cfg80211_get_chandef_type(&ch_switch->chandef)) { |
| 1012 | if (ctx->ht.enabled) | 1012 | case NL80211_CHAN_NO_HT: |
| 1013 | iwlagn_config_ht40(conf, ctx); | 1013 | case NL80211_CHAN_HT20: |
| 1014 | else | ||
| 1015 | ctx->ht.is_40mhz = false; | 1014 | ctx->ht.is_40mhz = false; |
| 1015 | ctx->ht.extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; | ||
| 1016 | break; | ||
| 1017 | case NL80211_CHAN_HT40MINUS: | ||
| 1018 | ctx->ht.extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW; | ||
| 1019 | ctx->ht.is_40mhz = true; | ||
| 1020 | break; | ||
| 1021 | case NL80211_CHAN_HT40PLUS: | ||
| 1022 | ctx->ht.extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; | ||
| 1023 | ctx->ht.is_40mhz = true; | ||
| 1024 | break; | ||
| 1025 | } | ||
| 1016 | 1026 | ||
| 1017 | if ((le16_to_cpu(ctx->staging.channel) != ch)) | 1027 | if ((le16_to_cpu(ctx->staging.channel) != ch)) |
| 1018 | ctx->staging.flags = 0; | 1028 | ctx->staging.flags = 0; |
diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c index 2a349004f18d..707446fa00bd 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/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 70b6ce61fea9..b878a32e7a98 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/if_arp.h> | 25 | #include <linux/if_arp.h> |
| 26 | #include <linux/rtnetlink.h> | 26 | #include <linux/rtnetlink.h> |
| 27 | #include <linux/etherdevice.h> | 27 | #include <linux/etherdevice.h> |
| 28 | #include <linux/platform_device.h> | ||
| 28 | #include <linux/debugfs.h> | 29 | #include <linux/debugfs.h> |
| 29 | #include <linux/module.h> | 30 | #include <linux/module.h> |
| 30 | #include <linux/ktime.h> | 31 | #include <linux/ktime.h> |
| @@ -52,6 +53,10 @@ static bool paged_rx = false; | |||
| 52 | module_param(paged_rx, bool, 0644); | 53 | module_param(paged_rx, bool, 0644); |
| 53 | MODULE_PARM_DESC(paged_rx, "Use paged SKBs for RX instead of linear ones"); | 54 | MODULE_PARM_DESC(paged_rx, "Use paged SKBs for RX instead of linear ones"); |
| 54 | 55 | ||
| 56 | static bool rctbl = false; | ||
| 57 | module_param(rctbl, bool, 0444); | ||
| 58 | MODULE_PARM_DESC(rctbl, "Handle rate control table"); | ||
| 59 | |||
| 55 | /** | 60 | /** |
| 56 | * enum hwsim_regtest - the type of regulatory tests we offer | 61 | * enum hwsim_regtest - the type of regulatory tests we offer |
| 57 | * | 62 | * |
| @@ -717,9 +722,17 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, | |||
| 717 | rx_status.flag |= RX_FLAG_MACTIME_START; | 722 | rx_status.flag |= RX_FLAG_MACTIME_START; |
| 718 | rx_status.freq = chan->center_freq; | 723 | rx_status.freq = chan->center_freq; |
| 719 | rx_status.band = chan->band; | 724 | rx_status.band = chan->band; |
| 720 | rx_status.rate_idx = info->control.rates[0].idx; | 725 | if (info->control.rates[0].flags & IEEE80211_TX_RC_VHT_MCS) { |
| 721 | if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) | 726 | rx_status.rate_idx = |
| 722 | rx_status.flag |= RX_FLAG_HT; | 727 | ieee80211_rate_get_vht_mcs(&info->control.rates[0]); |
| 728 | rx_status.vht_nss = | ||
| 729 | ieee80211_rate_get_vht_nss(&info->control.rates[0]); | ||
| 730 | rx_status.flag |= RX_FLAG_VHT; | ||
| 731 | } else { | ||
| 732 | rx_status.rate_idx = info->control.rates[0].idx; | ||
| 733 | if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) | ||
| 734 | rx_status.flag |= RX_FLAG_HT; | ||
| 735 | } | ||
| 723 | if (info->control.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | 736 | if (info->control.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) |
| 724 | rx_status.flag |= RX_FLAG_40MHZ; | 737 | rx_status.flag |= RX_FLAG_40MHZ; |
| 725 | if (info->control.rates[0].flags & IEEE80211_TX_RC_SHORT_GI) | 738 | if (info->control.rates[0].flags & IEEE80211_TX_RC_SHORT_GI) |
| @@ -886,8 +899,12 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, | |||
| 886 | if (control->sta) | 899 | if (control->sta) |
| 887 | hwsim_check_sta_magic(control->sta); | 900 | hwsim_check_sta_magic(control->sta); |
| 888 | 901 | ||
| 889 | txi->rate_driver_data[0] = channel; | 902 | if (rctbl) |
| 903 | ieee80211_get_tx_rates(txi->control.vif, control->sta, skb, | ||
| 904 | txi->control.rates, | ||
| 905 | ARRAY_SIZE(txi->control.rates)); | ||
| 890 | 906 | ||
| 907 | txi->rate_driver_data[0] = channel; | ||
| 891 | mac80211_hwsim_monitor_rx(hw, skb, channel); | 908 | mac80211_hwsim_monitor_rx(hw, skb, channel); |
| 892 | 909 | ||
| 893 | /* wmediumd mode check */ | 910 | /* wmediumd mode check */ |
| @@ -989,6 +1006,13 @@ static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | |||
| 989 | { | 1006 | { |
| 990 | u32 _pid = ACCESS_ONCE(wmediumd_portid); | 1007 | u32 _pid = ACCESS_ONCE(wmediumd_portid); |
| 991 | 1008 | ||
| 1009 | if (rctbl) { | ||
| 1010 | struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb); | ||
| 1011 | ieee80211_get_tx_rates(txi->control.vif, NULL, skb, | ||
| 1012 | txi->control.rates, | ||
| 1013 | ARRAY_SIZE(txi->control.rates)); | ||
| 1014 | } | ||
| 1015 | |||
| 992 | mac80211_hwsim_monitor_rx(hw, skb, chan); | 1016 | mac80211_hwsim_monitor_rx(hw, skb, chan); |
| 993 | 1017 | ||
| 994 | if (_pid) | 1018 | if (_pid) |
| @@ -1019,6 +1043,11 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, | |||
| 1019 | if (skb == NULL) | 1043 | if (skb == NULL) |
| 1020 | return; | 1044 | return; |
| 1021 | info = IEEE80211_SKB_CB(skb); | 1045 | info = IEEE80211_SKB_CB(skb); |
| 1046 | if (rctbl) | ||
| 1047 | ieee80211_get_tx_rates(vif, NULL, skb, | ||
| 1048 | info->control.rates, | ||
| 1049 | ARRAY_SIZE(info->control.rates)); | ||
| 1050 | |||
| 1022 | txrate = ieee80211_get_tx_rate(hw, info); | 1051 | txrate = ieee80211_get_tx_rate(hw, info); |
| 1023 | 1052 | ||
| 1024 | mgmt = (struct ieee80211_mgmt *) skb->data; | 1053 | mgmt = (struct ieee80211_mgmt *) skb->data; |
| @@ -1687,6 +1716,7 @@ static void mac80211_hwsim_free(void) | |||
| 1687 | debugfs_remove(data->debugfs_ps); | 1716 | debugfs_remove(data->debugfs_ps); |
| 1688 | debugfs_remove(data->debugfs); | 1717 | debugfs_remove(data->debugfs); |
| 1689 | ieee80211_unregister_hw(data->hw); | 1718 | ieee80211_unregister_hw(data->hw); |
| 1719 | device_release_driver(data->dev); | ||
| 1690 | device_unregister(data->dev); | 1720 | device_unregister(data->dev); |
| 1691 | ieee80211_free_hw(data->hw); | 1721 | ieee80211_free_hw(data->hw); |
| 1692 | } | 1722 | } |
| @@ -1695,7 +1725,9 @@ static void mac80211_hwsim_free(void) | |||
| 1695 | 1725 | ||
| 1696 | 1726 | ||
| 1697 | static struct device_driver mac80211_hwsim_driver = { | 1727 | static struct device_driver mac80211_hwsim_driver = { |
| 1698 | .name = "mac80211_hwsim" | 1728 | .name = "mac80211_hwsim", |
| 1729 | .bus = &platform_bus_type, | ||
| 1730 | .owner = THIS_MODULE, | ||
| 1699 | }; | 1731 | }; |
| 1700 | 1732 | ||
| 1701 | static const struct net_device_ops hwsim_netdev_ops = { | 1733 | static const struct net_device_ops hwsim_netdev_ops = { |
| @@ -2187,9 +2219,15 @@ static int __init init_mac80211_hwsim(void) | |||
| 2187 | spin_lock_init(&hwsim_radio_lock); | 2219 | spin_lock_init(&hwsim_radio_lock); |
| 2188 | INIT_LIST_HEAD(&hwsim_radios); | 2220 | INIT_LIST_HEAD(&hwsim_radios); |
| 2189 | 2221 | ||
| 2222 | err = driver_register(&mac80211_hwsim_driver); | ||
| 2223 | if (err) | ||
| 2224 | return err; | ||
| 2225 | |||
| 2190 | hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim"); | 2226 | hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim"); |
| 2191 | if (IS_ERR(hwsim_class)) | 2227 | if (IS_ERR(hwsim_class)) { |
| 2192 | return PTR_ERR(hwsim_class); | 2228 | err = PTR_ERR(hwsim_class); |
| 2229 | goto failed_unregister_driver; | ||
| 2230 | } | ||
| 2193 | 2231 | ||
| 2194 | memset(addr, 0, ETH_ALEN); | 2232 | memset(addr, 0, ETH_ALEN); |
| 2195 | addr[0] = 0x02; | 2233 | addr[0] = 0x02; |
| @@ -2211,12 +2249,20 @@ static int __init init_mac80211_hwsim(void) | |||
| 2211 | "hwsim%d", i); | 2249 | "hwsim%d", i); |
| 2212 | if (IS_ERR(data->dev)) { | 2250 | if (IS_ERR(data->dev)) { |
| 2213 | printk(KERN_DEBUG | 2251 | printk(KERN_DEBUG |
| 2214 | "mac80211_hwsim: device_create " | 2252 | "mac80211_hwsim: device_create failed (%ld)\n", |
| 2215 | "failed (%ld)\n", PTR_ERR(data->dev)); | 2253 | PTR_ERR(data->dev)); |
| 2216 | err = -ENOMEM; | 2254 | err = -ENOMEM; |
| 2217 | goto failed_drvdata; | 2255 | goto failed_drvdata; |
| 2218 | } | 2256 | } |
| 2219 | data->dev->driver = &mac80211_hwsim_driver; | 2257 | data->dev->driver = &mac80211_hwsim_driver; |
| 2258 | err = device_bind_driver(data->dev); | ||
| 2259 | if (err != 0) { | ||
| 2260 | printk(KERN_DEBUG | ||
| 2261 | "mac80211_hwsim: device_bind_driver failed (%d)\n", | ||
| 2262 | err); | ||
| 2263 | goto failed_hw; | ||
| 2264 | } | ||
| 2265 | |||
| 2220 | skb_queue_head_init(&data->pending); | 2266 | skb_queue_head_init(&data->pending); |
| 2221 | 2267 | ||
| 2222 | SET_IEEE80211_DEV(hw, data->dev); | 2268 | SET_IEEE80211_DEV(hw, data->dev); |
| @@ -2259,6 +2305,8 @@ static int __init init_mac80211_hwsim(void) | |||
| 2259 | IEEE80211_HW_AMPDU_AGGREGATION | | 2305 | IEEE80211_HW_AMPDU_AGGREGATION | |
| 2260 | IEEE80211_HW_WANT_MONITOR_VIF | | 2306 | IEEE80211_HW_WANT_MONITOR_VIF | |
| 2261 | IEEE80211_HW_QUEUE_CONTROL; | 2307 | IEEE80211_HW_QUEUE_CONTROL; |
| 2308 | if (rctbl) | ||
| 2309 | hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE; | ||
| 2262 | 2310 | ||
| 2263 | hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | | 2311 | hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | |
| 2264 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; | 2312 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; |
| @@ -2515,6 +2563,8 @@ failed_drvdata: | |||
| 2515 | ieee80211_free_hw(hw); | 2563 | ieee80211_free_hw(hw); |
| 2516 | failed: | 2564 | failed: |
| 2517 | mac80211_hwsim_free(); | 2565 | mac80211_hwsim_free(); |
| 2566 | failed_unregister_driver: | ||
| 2567 | driver_unregister(&mac80211_hwsim_driver); | ||
| 2518 | return err; | 2568 | return err; |
| 2519 | } | 2569 | } |
| 2520 | module_init(init_mac80211_hwsim); | 2570 | module_init(init_mac80211_hwsim); |
| @@ -2527,5 +2577,6 @@ static void __exit exit_mac80211_hwsim(void) | |||
| 2527 | 2577 | ||
| 2528 | mac80211_hwsim_free(); | 2578 | mac80211_hwsim_free(); |
| 2529 | unregister_netdev(hwsim_mon); | 2579 | unregister_netdev(hwsim_mon); |
| 2580 | driver_unregister(&mac80211_hwsim_driver); | ||
| 2530 | } | 2581 | } |
| 2531 | module_exit(exit_mac80211_hwsim); | 2582 | module_exit(exit_mac80211_hwsim); |
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 e46fea8b972e..06b0ed0154a4 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
| @@ -673,6 +673,36 @@ struct ieee80211_channel_sw_ie { | |||
| 673 | } __packed; | 673 | } __packed; |
| 674 | 674 | ||
| 675 | /** | 675 | /** |
| 676 | * struct ieee80211_ext_chansw_ie | ||
| 677 | * | ||
| 678 | * This structure represents the "Extended Channel Switch Announcement element" | ||
| 679 | */ | ||
| 680 | struct ieee80211_ext_chansw_ie { | ||
| 681 | u8 mode; | ||
| 682 | u8 new_operating_class; | ||
| 683 | u8 new_ch_num; | ||
| 684 | u8 count; | ||
| 685 | } __packed; | ||
| 686 | |||
| 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 | /** | ||
| 698 | * struct ieee80211_wide_bw_chansw_ie - wide bandwidth channel switch IE | ||
| 699 | */ | ||
| 700 | struct ieee80211_wide_bw_chansw_ie { | ||
| 701 | u8 new_channel_width; | ||
| 702 | u8 new_center_freq_seg0, new_center_freq_seg1; | ||
| 703 | } __packed; | ||
| 704 | |||
| 705 | /** | ||
| 676 | * struct ieee80211_tim | 706 | * struct ieee80211_tim |
| 677 | * | 707 | * |
| 678 | * This structure refers to "Traffic Indication Map information element" | 708 | * This structure refers to "Traffic Indication Map information element" |
| @@ -840,12 +870,15 @@ struct ieee80211_mgmt { | |||
| 840 | } __packed wme_action; | 870 | } __packed wme_action; |
| 841 | struct{ | 871 | struct{ |
| 842 | u8 action_code; | 872 | u8 action_code; |
| 843 | u8 element_id; | 873 | u8 variable[0]; |
| 844 | u8 length; | ||
| 845 | struct ieee80211_channel_sw_ie sw_elem; | ||
| 846 | } __packed chan_switch; | 874 | } __packed chan_switch; |
| 847 | struct{ | 875 | struct{ |
| 848 | u8 action_code; | 876 | u8 action_code; |
| 877 | struct ieee80211_ext_chansw_ie data; | ||
| 878 | u8 variable[0]; | ||
| 879 | } __packed ext_chan_switch; | ||
| 880 | struct{ | ||
| 881 | u8 action_code; | ||
| 849 | u8 dialog_token; | 882 | u8 dialog_token; |
| 850 | u8 element_id; | 883 | u8 element_id; |
| 851 | u8 length; | 884 | u8 length; |
| @@ -1638,6 +1671,7 @@ enum ieee80211_eid { | |||
| 1638 | 1671 | ||
| 1639 | WLAN_EID_HT_CAPABILITY = 45, | 1672 | WLAN_EID_HT_CAPABILITY = 45, |
| 1640 | WLAN_EID_HT_OPERATION = 61, | 1673 | WLAN_EID_HT_OPERATION = 61, |
| 1674 | WLAN_EID_SECONDARY_CHANNEL_OFFSET = 62, | ||
| 1641 | 1675 | ||
| 1642 | WLAN_EID_RSN = 48, | 1676 | WLAN_EID_RSN = 48, |
| 1643 | WLAN_EID_MMIE = 76, | 1677 | WLAN_EID_MMIE = 76, |
| @@ -1672,6 +1706,8 @@ enum ieee80211_eid { | |||
| 1672 | WLAN_EID_VHT_CAPABILITY = 191, | 1706 | WLAN_EID_VHT_CAPABILITY = 191, |
| 1673 | WLAN_EID_VHT_OPERATION = 192, | 1707 | WLAN_EID_VHT_OPERATION = 192, |
| 1674 | WLAN_EID_OPMODE_NOTIF = 199, | 1708 | WLAN_EID_OPMODE_NOTIF = 199, |
| 1709 | WLAN_EID_WIDE_BW_CHANNEL_SWITCH = 194, | ||
| 1710 | WLAN_EID_CHANNEL_SWITCH_WRAPPER = 196, | ||
| 1675 | 1711 | ||
| 1676 | /* 802.11ad */ | 1712 | /* 802.11ad */ |
| 1677 | WLAN_EID_NON_TX_BSSID_CAP = 83, | 1713 | WLAN_EID_NON_TX_BSSID_CAP = 83, |
| @@ -1795,6 +1831,7 @@ enum ieee80211_key_len { | |||
| 1795 | 1831 | ||
| 1796 | /* Public action codes */ | 1832 | /* Public action codes */ |
| 1797 | enum ieee80211_pub_actioncode { | 1833 | enum ieee80211_pub_actioncode { |
| 1834 | WLAN_PUB_ACTION_EXT_CHANSW_ANN = 4, | ||
| 1798 | WLAN_PUB_ACTION_TDLS_DISCOVER_RES = 14, | 1835 | WLAN_PUB_ACTION_TDLS_DISCOVER_RES = 14, |
| 1799 | }; | 1836 | }; |
| 1800 | 1837 | ||
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 57870b646974..26b5b692c22b 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
| @@ -2002,6 +2002,12 @@ struct cfg80211_update_ft_ies_params { | |||
| 2002 | * @update_ft_ies: Provide updated Fast BSS Transition information to the | 2002 | * @update_ft_ies: Provide updated Fast BSS Transition information to the |
| 2003 | * driver. If the SME is in the driver/firmware, this information can be | 2003 | * driver. If the SME is in the driver/firmware, this information can be |
| 2004 | * used in building Authentication and Reassociation Request frames. | 2004 | * used in building Authentication and Reassociation Request frames. |
| 2005 | * | ||
| 2006 | * @crit_proto_start: Indicates a critical protocol needs more link reliability | ||
| 2007 | * for a given duration (milliseconds). The protocol is provided so the | ||
| 2008 | * driver can take the most appropriate actions. | ||
| 2009 | * @crit_proto_stop: Indicates critical protocol no longer needs increased link | ||
| 2010 | * reliability. This operation can not fail. | ||
| 2005 | */ | 2011 | */ |
| 2006 | struct cfg80211_ops { | 2012 | struct cfg80211_ops { |
| 2007 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); | 2013 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); |
| @@ -2231,6 +2237,12 @@ struct cfg80211_ops { | |||
| 2231 | struct cfg80211_chan_def *chandef); | 2237 | struct cfg80211_chan_def *chandef); |
| 2232 | int (*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev, | 2238 | int (*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev, |
| 2233 | struct cfg80211_update_ft_ies_params *ftie); | 2239 | struct cfg80211_update_ft_ies_params *ftie); |
| 2240 | int (*crit_proto_start)(struct wiphy *wiphy, | ||
| 2241 | struct wireless_dev *wdev, | ||
| 2242 | enum nl80211_crit_proto_id protocol, | ||
| 2243 | u16 duration); | ||
| 2244 | void (*crit_proto_stop)(struct wiphy *wiphy, | ||
| 2245 | struct wireless_dev *wdev); | ||
| 2234 | }; | 2246 | }; |
| 2235 | 2247 | ||
| 2236 | /* | 2248 | /* |
| @@ -4024,6 +4036,17 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy, | |||
| 4024 | void cfg80211_ch_switch_notify(struct net_device *dev, | 4036 | void cfg80211_ch_switch_notify(struct net_device *dev, |
| 4025 | struct cfg80211_chan_def *chandef); | 4037 | struct cfg80211_chan_def *chandef); |
| 4026 | 4038 | ||
| 4039 | /** | ||
| 4040 | * ieee80211_operating_class_to_band - convert operating class to band | ||
| 4041 | * | ||
| 4042 | * @operating_class: the operating class to convert | ||
| 4043 | * @band: band pointer to fill | ||
| 4044 | * | ||
| 4045 | * Returns %true if the conversion was successful, %false otherwise. | ||
| 4046 | */ | ||
| 4047 | bool ieee80211_operating_class_to_band(u8 operating_class, | ||
| 4048 | enum ieee80211_band *band); | ||
| 4049 | |||
| 4027 | /* | 4050 | /* |
| 4028 | * cfg80211_tdls_oper_request - request userspace to perform TDLS operation | 4051 | * cfg80211_tdls_oper_request - request userspace to perform TDLS operation |
| 4029 | * @dev: the device on which the operation is requested | 4052 | * @dev: the device on which the operation is requested |
| @@ -4126,6 +4149,17 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, | |||
| 4126 | struct cfg80211_wowlan_wakeup *wakeup, | 4149 | struct cfg80211_wowlan_wakeup *wakeup, |
| 4127 | gfp_t gfp); | 4150 | gfp_t gfp); |
| 4128 | 4151 | ||
| 4152 | /** | ||
| 4153 | * cfg80211_crit_proto_stopped() - indicate critical protocol stopped by driver. | ||
| 4154 | * | ||
| 4155 | * @wdev: the wireless device for which critical protocol is stopped. | ||
| 4156 | * | ||
| 4157 | * This function can be called by the driver to indicate it has reverted | ||
| 4158 | * operation back to normal. One reason could be that the duration given | ||
| 4159 | * by .crit_proto_start() has expired. | ||
| 4160 | */ | ||
| 4161 | void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp); | ||
| 4162 | |||
| 4129 | /* Logging, debugging and troubleshooting/diagnostic helpers. */ | 4163 | /* Logging, debugging and troubleshooting/diagnostic helpers. */ |
| 4130 | 4164 | ||
| 4131 | /* wiphy_printk helpers, similar to dev_printk */ | 4165 | /* wiphy_printk helpers, similar to dev_printk */ |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 64faf015dd1e..04c2d4670dc6 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
| @@ -128,6 +128,7 @@ enum ieee80211_ac_numbers { | |||
| 128 | * 2^n-1 in the range 1..32767] | 128 | * 2^n-1 in the range 1..32767] |
| 129 | * @cw_max: maximum contention window [like @cw_min] | 129 | * @cw_max: maximum contention window [like @cw_min] |
| 130 | * @txop: maximum burst time in units of 32 usecs, 0 meaning disabled | 130 | * @txop: maximum burst time in units of 32 usecs, 0 meaning disabled |
| 131 | * @acm: is mandatory admission control required for the access category | ||
| 131 | * @uapsd: is U-APSD mode enabled for the queue | 132 | * @uapsd: is U-APSD mode enabled for the queue |
| 132 | */ | 133 | */ |
| 133 | struct ieee80211_tx_queue_params { | 134 | struct ieee80211_tx_queue_params { |
| @@ -135,6 +136,7 @@ struct ieee80211_tx_queue_params { | |||
| 135 | u16 cw_min; | 136 | u16 cw_min; |
| 136 | u16 cw_max; | 137 | u16 cw_max; |
| 137 | u8 aifs; | 138 | u8 aifs; |
| 139 | bool acm; | ||
| 138 | bool uapsd; | 140 | bool uapsd; |
| 139 | }; | 141 | }; |
| 140 | 142 | ||
| @@ -209,7 +211,7 @@ struct ieee80211_chanctx_conf { | |||
| 209 | * @BSS_CHANGED_QOS: QoS for this association was enabled/disabled. Note | 211 | * @BSS_CHANGED_QOS: QoS for this association was enabled/disabled. Note |
| 210 | * that it is only ever disabled for station mode. | 212 | * that it is only ever disabled for station mode. |
| 211 | * @BSS_CHANGED_IDLE: Idle changed for this BSS/interface. | 213 | * @BSS_CHANGED_IDLE: Idle changed for this BSS/interface. |
| 212 | * @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode) | 214 | * @BSS_CHANGED_SSID: SSID changed for this BSS (AP and IBSS mode) |
| 213 | * @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode) | 215 | * @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode) |
| 214 | * @BSS_CHANGED_PS: PS changed for this BSS (STA mode) | 216 | * @BSS_CHANGED_PS: PS changed for this BSS (STA mode) |
| 215 | * @BSS_CHANGED_TXPOWER: TX power setting changed for this interface | 217 | * @BSS_CHANGED_TXPOWER: TX power setting changed for this interface |
| @@ -326,7 +328,7 @@ enum ieee80211_rssi_event { | |||
| 326 | * your driver/device needs to do. | 328 | * your driver/device needs to do. |
| 327 | * @ps: power-save mode (STA only). This flag is NOT affected by | 329 | * @ps: power-save mode (STA only). This flag is NOT affected by |
| 328 | * offchannel/dynamic_ps operations. | 330 | * offchannel/dynamic_ps operations. |
| 329 | * @ssid: The SSID of the current vif. Only valid in AP-mode. | 331 | * @ssid: The SSID of the current vif. Valid in AP and IBSS mode. |
| 330 | * @ssid_len: Length of SSID given in @ssid. | 332 | * @ssid_len: Length of SSID given in @ssid. |
| 331 | * @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode. | 333 | * @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode. |
| 332 | * @txpower: TX power in dBm | 334 | * @txpower: TX power in dBm |
| @@ -561,6 +563,9 @@ enum mac80211_rate_control_flags { | |||
| 561 | /* maximum number of rate stages */ | 563 | /* maximum number of rate stages */ |
| 562 | #define IEEE80211_TX_MAX_RATES 4 | 564 | #define IEEE80211_TX_MAX_RATES 4 |
| 563 | 565 | ||
| 566 | /* maximum number of rate table entries */ | ||
| 567 | #define IEEE80211_TX_RATE_TABLE_SIZE 4 | ||
| 568 | |||
| 564 | /** | 569 | /** |
| 565 | * struct ieee80211_tx_rate - rate selection/status | 570 | * struct ieee80211_tx_rate - rate selection/status |
| 566 | * | 571 | * |
| @@ -601,8 +606,8 @@ static inline void ieee80211_rate_set_vht(struct ieee80211_tx_rate *rate, | |||
| 601 | u8 mcs, u8 nss) | 606 | u8 mcs, u8 nss) |
| 602 | { | 607 | { |
| 603 | WARN_ON(mcs & ~0xF); | 608 | WARN_ON(mcs & ~0xF); |
| 604 | WARN_ON(nss & ~0x7); | 609 | WARN_ON((nss - 1) & ~0x7); |
| 605 | rate->idx = (nss << 4) | mcs; | 610 | rate->idx = ((nss - 1) << 4) | mcs; |
| 606 | } | 611 | } |
| 607 | 612 | ||
| 608 | static inline u8 | 613 | static inline u8 |
| @@ -614,7 +619,7 @@ ieee80211_rate_get_vht_mcs(const struct ieee80211_tx_rate *rate) | |||
| 614 | static inline u8 | 619 | static inline u8 |
| 615 | ieee80211_rate_get_vht_nss(const struct ieee80211_tx_rate *rate) | 620 | ieee80211_rate_get_vht_nss(const struct ieee80211_tx_rate *rate) |
| 616 | { | 621 | { |
| 617 | return rate->idx >> 4; | 622 | return (rate->idx >> 4) + 1; |
| 618 | } | 623 | } |
| 619 | 624 | ||
| 620 | /** | 625 | /** |
| @@ -655,7 +660,11 @@ struct ieee80211_tx_info { | |||
| 655 | struct ieee80211_tx_rate rates[ | 660 | struct ieee80211_tx_rate rates[ |
| 656 | IEEE80211_TX_MAX_RATES]; | 661 | IEEE80211_TX_MAX_RATES]; |
| 657 | s8 rts_cts_rate_idx; | 662 | s8 rts_cts_rate_idx; |
| 658 | /* 3 bytes free */ | 663 | u8 use_rts:1; |
| 664 | u8 use_cts_prot:1; | ||
| 665 | u8 short_preamble:1; | ||
| 666 | u8 skip_table:1; | ||
| 667 | /* 2 bytes free */ | ||
| 659 | }; | 668 | }; |
| 660 | /* only needed before rate control */ | 669 | /* only needed before rate control */ |
| 661 | unsigned long jiffies; | 670 | unsigned long jiffies; |
| @@ -676,6 +685,8 @@ struct ieee80211_tx_info { | |||
| 676 | struct { | 685 | struct { |
| 677 | struct ieee80211_tx_rate driver_rates[ | 686 | struct ieee80211_tx_rate driver_rates[ |
| 678 | IEEE80211_TX_MAX_RATES]; | 687 | IEEE80211_TX_MAX_RATES]; |
| 688 | u8 pad[4]; | ||
| 689 | |||
| 679 | void *rate_driver_data[ | 690 | void *rate_driver_data[ |
| 680 | IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE / sizeof(void *)]; | 691 | IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE / sizeof(void *)]; |
| 681 | }; | 692 | }; |
| @@ -1017,13 +1028,13 @@ struct ieee80211_conf { | |||
| 1017 | * the driver passed into mac80211. | 1028 | * the driver passed into mac80211. |
| 1018 | * @block_tx: Indicates whether transmission must be blocked before the | 1029 | * @block_tx: Indicates whether transmission must be blocked before the |
| 1019 | * scheduled channel switch, as indicated by the AP. | 1030 | * scheduled channel switch, as indicated by the AP. |
| 1020 | * @channel: the new channel to switch to | 1031 | * @chandef: the new channel to switch to |
| 1021 | * @count: the number of TBTT's until the channel switch event | 1032 | * @count: the number of TBTT's until the channel switch event |
| 1022 | */ | 1033 | */ |
| 1023 | struct ieee80211_channel_switch { | 1034 | struct ieee80211_channel_switch { |
| 1024 | u64 timestamp; | 1035 | u64 timestamp; |
| 1025 | bool block_tx; | 1036 | bool block_tx; |
| 1026 | struct ieee80211_channel *channel; | 1037 | struct cfg80211_chan_def chandef; |
| 1027 | u8 count; | 1038 | u8 count; |
| 1028 | }; | 1039 | }; |
| 1029 | 1040 | ||
| @@ -1221,6 +1232,24 @@ enum ieee80211_sta_rx_bandwidth { | |||
| 1221 | }; | 1232 | }; |
| 1222 | 1233 | ||
| 1223 | /** | 1234 | /** |
| 1235 | * struct ieee80211_sta_rates - station rate selection table | ||
| 1236 | * | ||
| 1237 | * @rcu_head: RCU head used for freeing the table on update | ||
| 1238 | * @rates: transmit rates/flags to be used by default. | ||
| 1239 | * Overriding entries per-packet is possible by using cb tx control. | ||
| 1240 | */ | ||
| 1241 | struct ieee80211_sta_rates { | ||
| 1242 | struct rcu_head rcu_head; | ||
| 1243 | struct { | ||
| 1244 | s8 idx; | ||
| 1245 | u8 count; | ||
| 1246 | u8 count_cts; | ||
| 1247 | u8 count_rts; | ||
| 1248 | u16 flags; | ||
| 1249 | } rate[IEEE80211_TX_RATE_TABLE_SIZE]; | ||
| 1250 | }; | ||
| 1251 | |||
| 1252 | /** | ||
| 1224 | * struct ieee80211_sta - station table entry | 1253 | * struct ieee80211_sta - station table entry |
| 1225 | * | 1254 | * |
| 1226 | * A station table entry represents a station we are possibly | 1255 | * A station table entry represents a station we are possibly |
| @@ -1247,6 +1276,7 @@ enum ieee80211_sta_rx_bandwidth { | |||
| 1247 | * notifications and capabilities. The value is only valid after | 1276 | * notifications and capabilities. The value is only valid after |
| 1248 | * the station moves to associated state. | 1277 | * the station moves to associated state. |
| 1249 | * @smps_mode: current SMPS mode (off, static or dynamic) | 1278 | * @smps_mode: current SMPS mode (off, static or dynamic) |
| 1279 | * @tx_rates: rate control selection table | ||
| 1250 | */ | 1280 | */ |
| 1251 | struct ieee80211_sta { | 1281 | struct ieee80211_sta { |
| 1252 | u32 supp_rates[IEEE80211_NUM_BANDS]; | 1282 | u32 supp_rates[IEEE80211_NUM_BANDS]; |
| @@ -1260,6 +1290,7 @@ struct ieee80211_sta { | |||
| 1260 | u8 rx_nss; | 1290 | u8 rx_nss; |
| 1261 | enum ieee80211_sta_rx_bandwidth bandwidth; | 1291 | enum ieee80211_sta_rx_bandwidth bandwidth; |
| 1262 | enum ieee80211_smps_mode smps_mode; | 1292 | enum ieee80211_smps_mode smps_mode; |
| 1293 | struct ieee80211_sta_rates __rcu *rates; | ||
| 1263 | 1294 | ||
| 1264 | /* must be last */ | 1295 | /* must be last */ |
| 1265 | u8 drv_priv[0] __aligned(sizeof(void *)); | 1296 | u8 drv_priv[0] __aligned(sizeof(void *)); |
| @@ -1415,6 +1446,9 @@ struct ieee80211_tx_control { | |||
| 1415 | * for different virtual interfaces. See the doc section on HW queue | 1446 | * for different virtual interfaces. See the doc section on HW queue |
| 1416 | * control for more details. | 1447 | * control for more details. |
| 1417 | * | 1448 | * |
| 1449 | * @IEEE80211_HW_SUPPORTS_RC_TABLE: The driver supports using a rate | ||
| 1450 | * selection table provided by the rate control algorithm. | ||
| 1451 | * | ||
| 1418 | * @IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF: Use the P2P Device address for any | 1452 | * @IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF: Use the P2P Device address for any |
| 1419 | * P2P Interface. This will be honoured even if more than one interface | 1453 | * P2P Interface. This will be honoured even if more than one interface |
| 1420 | * is supported. | 1454 | * is supported. |
| @@ -1447,6 +1481,7 @@ enum ieee80211_hw_flags { | |||
| 1447 | IEEE80211_HW_SUPPORTS_PER_STA_GTK = 1<<21, | 1481 | IEEE80211_HW_SUPPORTS_PER_STA_GTK = 1<<21, |
| 1448 | IEEE80211_HW_AP_LINK_PS = 1<<22, | 1482 | IEEE80211_HW_AP_LINK_PS = 1<<22, |
| 1449 | IEEE80211_HW_TX_AMPDU_SETUP_IN_HW = 1<<23, | 1483 | IEEE80211_HW_TX_AMPDU_SETUP_IN_HW = 1<<23, |
| 1484 | IEEE80211_HW_SUPPORTS_RC_TABLE = 1<<24, | ||
| 1450 | IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF = 1<<25, | 1485 | IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF = 1<<25, |
| 1451 | IEEE80211_HW_TIMING_BEACON_ONLY = 1<<26, | 1486 | IEEE80211_HW_TIMING_BEACON_ONLY = 1<<26, |
| 1452 | }; | 1487 | }; |
| @@ -3133,6 +3168,25 @@ void ieee80211_sta_set_buffered(struct ieee80211_sta *sta, | |||
| 3133 | u8 tid, bool buffered); | 3168 | u8 tid, bool buffered); |
| 3134 | 3169 | ||
| 3135 | /** | 3170 | /** |
| 3171 | * ieee80211_get_tx_rates - get the selected transmit rates for a packet | ||
| 3172 | * | ||
| 3173 | * Call this function in a driver with per-packet rate selection support | ||
| 3174 | * to combine the rate info in the packet tx info with the most recent | ||
| 3175 | * rate selection table for the station entry. | ||
| 3176 | * | ||
| 3177 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||
| 3178 | * @sta: the receiver station to which this packet is sent. | ||
| 3179 | * @skb: the frame to be transmitted. | ||
| 3180 | * @dest: buffer for extracted rate/retry information | ||
| 3181 | * @max_rates: maximum number of rates to fetch | ||
| 3182 | */ | ||
| 3183 | void ieee80211_get_tx_rates(struct ieee80211_vif *vif, | ||
| 3184 | struct ieee80211_sta *sta, | ||
| 3185 | struct sk_buff *skb, | ||
| 3186 | struct ieee80211_tx_rate *dest, | ||
| 3187 | int max_rates); | ||
| 3188 | |||
| 3189 | /** | ||
| 3136 | * ieee80211_tx_status - transmit status callback | 3190 | * ieee80211_tx_status - transmit status callback |
| 3137 | * | 3191 | * |
| 3138 | * Call this function for all transmitted frames after they have been | 3192 | * Call this function for all transmitted frames after they have been |
| @@ -4107,7 +4161,7 @@ void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn); | |||
| 4107 | * (deprecated; this will be removed once drivers get updated to use | 4161 | * (deprecated; this will be removed once drivers get updated to use |
| 4108 | * rate_idx_mask) | 4162 | * rate_idx_mask) |
| 4109 | * @rate_idx_mask: user-requested (legacy) rate mask | 4163 | * @rate_idx_mask: user-requested (legacy) rate mask |
| 4110 | * @rate_idx_mcs_mask: user-requested MCS rate mask | 4164 | * @rate_idx_mcs_mask: user-requested MCS rate mask (NULL if not in use) |
| 4111 | * @bss: whether this frame is sent out in AP or IBSS mode | 4165 | * @bss: whether this frame is sent out in AP or IBSS mode |
| 4112 | */ | 4166 | */ |
| 4113 | struct ieee80211_tx_rate_control { | 4167 | struct ieee80211_tx_rate_control { |
| @@ -4119,7 +4173,7 @@ struct ieee80211_tx_rate_control { | |||
| 4119 | bool rts, short_preamble; | 4173 | bool rts, short_preamble; |
| 4120 | u8 max_rate_idx; | 4174 | u8 max_rate_idx; |
| 4121 | u32 rate_idx_mask; | 4175 | u32 rate_idx_mask; |
| 4122 | u8 rate_idx_mcs_mask[IEEE80211_HT_MCS_MASK_LEN]; | 4176 | u8 *rate_idx_mcs_mask; |
| 4123 | bool bss; | 4177 | bool bss; |
| 4124 | }; | 4178 | }; |
| 4125 | 4179 | ||
| @@ -4208,6 +4262,22 @@ bool rate_usable_index_exists(struct ieee80211_supported_band *sband, | |||
| 4208 | return false; | 4262 | return false; |
| 4209 | } | 4263 | } |
| 4210 | 4264 | ||
| 4265 | /** | ||
| 4266 | * rate_control_set_rates - pass the sta rate selection to mac80211/driver | ||
| 4267 | * | ||
| 4268 | * When not doing a rate control probe to test rates, rate control should pass | ||
| 4269 | * its rate selection to mac80211. If the driver supports receiving a station | ||
| 4270 | * rate table, it will use it to ensure that frames are always sent based on | ||
| 4271 | * the most recent rate control module decision. | ||
| 4272 | * | ||
| 4273 | * @hw: pointer as obtained from ieee80211_alloc_hw() | ||
| 4274 | * @pubsta: &struct ieee80211_sta pointer to the target destination. | ||
| 4275 | * @rates: new tx rate set to be used for this station. | ||
| 4276 | */ | ||
| 4277 | int rate_control_set_rates(struct ieee80211_hw *hw, | ||
| 4278 | struct ieee80211_sta *pubsta, | ||
| 4279 | struct ieee80211_sta_rates *rates); | ||
| 4280 | |||
| 4211 | int ieee80211_rate_control_register(struct rate_control_ops *ops); | 4281 | int ieee80211_rate_control_register(struct rate_control_ops *ops); |
| 4212 | void ieee80211_rate_control_unregister(struct rate_control_ops *ops); | 4282 | void ieee80211_rate_control_unregister(struct rate_control_ops *ops); |
| 4213 | 4283 | ||
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 79da8710448e..d1e48b5e348f 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h | |||
| @@ -639,6 +639,13 @@ | |||
| 639 | * with the relevant Information Elements. This event is used to report | 639 | * with the relevant Information Elements. This event is used to report |
| 640 | * received FT IEs (MDIE, FTIE, RSN IE, TIE, RICIE). | 640 | * received FT IEs (MDIE, FTIE, RSN IE, TIE, RICIE). |
| 641 | * | 641 | * |
| 642 | * @NL80211_CMD_CRIT_PROTOCOL_START: Indicates user-space will start running | ||
| 643 | * a critical protocol that needs more reliability in the connection to | ||
| 644 | * complete. | ||
| 645 | * | ||
| 646 | * @NL80211_CMD_CRIT_PROTOCOL_STOP: Indicates the connection reliability can | ||
| 647 | * return back to normal. | ||
| 648 | * | ||
| 642 | * @NL80211_CMD_MAX: highest used command number | 649 | * @NL80211_CMD_MAX: highest used command number |
| 643 | * @__NL80211_CMD_AFTER_LAST: internal use | 650 | * @__NL80211_CMD_AFTER_LAST: internal use |
| 644 | */ | 651 | */ |
| @@ -798,6 +805,9 @@ enum nl80211_commands { | |||
| 798 | NL80211_CMD_UPDATE_FT_IES, | 805 | NL80211_CMD_UPDATE_FT_IES, |
| 799 | NL80211_CMD_FT_EVENT, | 806 | NL80211_CMD_FT_EVENT, |
| 800 | 807 | ||
| 808 | NL80211_CMD_CRIT_PROTOCOL_START, | ||
| 809 | NL80211_CMD_CRIT_PROTOCOL_STOP, | ||
| 810 | |||
| 801 | /* add new commands above here */ | 811 | /* add new commands above here */ |
| 802 | 812 | ||
| 803 | /* used to define NL80211_CMD_MAX below */ | 813 | /* used to define NL80211_CMD_MAX below */ |
| @@ -1414,6 +1424,11 @@ enum nl80211_commands { | |||
| 1414 | * @NL80211_ATTR_IE_RIC: Resource Information Container Information | 1424 | * @NL80211_ATTR_IE_RIC: Resource Information Container Information |
| 1415 | * Element | 1425 | * Element |
| 1416 | * | 1426 | * |
| 1427 | * @NL80211_ATTR_CRIT_PROT_ID: critical protocol identifier requiring increased | ||
| 1428 | * reliability, see &enum nl80211_crit_proto_id (u16). | ||
| 1429 | * @NL80211_ATTR_MAX_CRIT_PROT_DURATION: duration in milliseconds in which | ||
| 1430 | * the connection should have increased reliability (u16). | ||
| 1431 | * | ||
| 1417 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 1432 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
| 1418 | * @__NL80211_ATTR_AFTER_LAST: internal use | 1433 | * @__NL80211_ATTR_AFTER_LAST: internal use |
| 1419 | */ | 1434 | */ |
| @@ -1709,6 +1724,9 @@ enum nl80211_attrs { | |||
| 1709 | NL80211_ATTR_MDID, | 1724 | NL80211_ATTR_MDID, |
| 1710 | NL80211_ATTR_IE_RIC, | 1725 | NL80211_ATTR_IE_RIC, |
| 1711 | 1726 | ||
| 1727 | NL80211_ATTR_CRIT_PROT_ID, | ||
| 1728 | NL80211_ATTR_MAX_CRIT_PROT_DURATION, | ||
| 1729 | |||
| 1712 | /* add attributes here, update the policy in nl80211.c */ | 1730 | /* add attributes here, update the policy in nl80211.c */ |
| 1713 | 1731 | ||
| 1714 | __NL80211_ATTR_AFTER_LAST, | 1732 | __NL80211_ATTR_AFTER_LAST, |
| @@ -3682,4 +3700,25 @@ enum nl80211_protocol_features { | |||
| 3682 | NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP = 1 << 0, | 3700 | NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP = 1 << 0, |
| 3683 | }; | 3701 | }; |
| 3684 | 3702 | ||
| 3703 | /** | ||
| 3704 | * enum nl80211_crit_proto_id - nl80211 critical protocol identifiers | ||
| 3705 | * | ||
| 3706 | * @NL80211_CRIT_PROTO_UNSPEC: protocol unspecified. | ||
| 3707 | * @NL80211_CRIT_PROTO_DHCP: BOOTP or DHCPv6 protocol. | ||
| 3708 | * @NL80211_CRIT_PROTO_EAPOL: EAPOL protocol. | ||
| 3709 | * @NL80211_CRIT_PROTO_APIPA: APIPA protocol. | ||
| 3710 | * @NUM_NL80211_CRIT_PROTO: must be kept last. | ||
| 3711 | */ | ||
| 3712 | enum nl80211_crit_proto_id { | ||
| 3713 | NL80211_CRIT_PROTO_UNSPEC, | ||
| 3714 | NL80211_CRIT_PROTO_DHCP, | ||
| 3715 | NL80211_CRIT_PROTO_EAPOL, | ||
| 3716 | NL80211_CRIT_PROTO_APIPA, | ||
| 3717 | /* add other protocols before this one */ | ||
| 3718 | NUM_NL80211_CRIT_PROTO | ||
| 3719 | }; | ||
| 3720 | |||
| 3721 | /* maximum duration for critical protocol measures */ | ||
| 3722 | #define NL80211_CRIT_PROTO_MAX_DURATION 5000 /* msec */ | ||
| 3723 | |||
| 3685 | #endif /* __LINUX_NL80211_H */ | 3724 | #endif /* __LINUX_NL80211_H */ |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 764dd9a6a072..1a89c80e6407 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
| @@ -1043,6 +1043,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
| 1043 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | 1043 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) |
| 1044 | sta_info_flush_defer(vlan); | 1044 | sta_info_flush_defer(vlan); |
| 1045 | sta_info_flush_defer(sdata); | 1045 | sta_info_flush_defer(sdata); |
| 1046 | synchronize_net(); | ||
| 1046 | rcu_barrier(); | 1047 | rcu_barrier(); |
| 1047 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { | 1048 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { |
| 1048 | sta_info_flush_cleanup(vlan); | 1049 | sta_info_flush_cleanup(vlan); |
| @@ -1052,6 +1053,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
| 1052 | ieee80211_free_keys(sdata); | 1053 | ieee80211_free_keys(sdata); |
| 1053 | 1054 | ||
| 1054 | sdata->vif.bss_conf.enable_beacon = false; | 1055 | sdata->vif.bss_conf.enable_beacon = false; |
| 1056 | sdata->vif.bss_conf.ssid_len = 0; | ||
| 1055 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); | 1057 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); |
| 1056 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); | 1058 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); |
| 1057 | 1059 | ||
| @@ -2416,9 +2418,22 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
| 2416 | } | 2418 | } |
| 2417 | 2419 | ||
| 2418 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | 2420 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { |
| 2421 | struct ieee80211_supported_band *sband = wiphy->bands[i]; | ||
| 2422 | int j; | ||
| 2423 | |||
| 2419 | sdata->rc_rateidx_mask[i] = mask->control[i].legacy; | 2424 | sdata->rc_rateidx_mask[i] = mask->control[i].legacy; |
| 2420 | memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].mcs, | 2425 | memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].mcs, |
| 2421 | sizeof(mask->control[i].mcs)); | 2426 | sizeof(mask->control[i].mcs)); |
| 2427 | |||
| 2428 | sdata->rc_has_mcs_mask[i] = false; | ||
| 2429 | if (!sband) | ||
| 2430 | continue; | ||
| 2431 | |||
| 2432 | for (j = 0; j < IEEE80211_HT_MCS_MASK_LEN; j++) | ||
| 2433 | if (~sdata->rc_rateidx_mcs_mask[i][j]) { | ||
| 2434 | sdata->rc_has_mcs_mask[i] = true; | ||
| 2435 | break; | ||
| 2436 | } | ||
| 2422 | } | 2437 | } |
| 2423 | 2438 | ||
| 2424 | return 0; | 2439 | return 0; |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 7d0baa89c784..03e8d2e3270e 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
| @@ -57,6 +57,22 @@ ieee80211_find_chanctx(struct ieee80211_local *local, | |||
| 57 | return NULL; | 57 | return NULL; |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | static bool ieee80211_is_radar_required(struct ieee80211_local *local) | ||
| 61 | { | ||
| 62 | struct ieee80211_sub_if_data *sdata; | ||
| 63 | |||
| 64 | rcu_read_lock(); | ||
| 65 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
| 66 | if (sdata->radar_required) { | ||
| 67 | rcu_read_unlock(); | ||
| 68 | return true; | ||
| 69 | } | ||
| 70 | } | ||
| 71 | rcu_read_unlock(); | ||
| 72 | |||
| 73 | return false; | ||
| 74 | } | ||
| 75 | |||
| 60 | static struct ieee80211_chanctx * | 76 | static struct ieee80211_chanctx * |
| 61 | ieee80211_new_chanctx(struct ieee80211_local *local, | 77 | ieee80211_new_chanctx(struct ieee80211_local *local, |
| 62 | const struct cfg80211_chan_def *chandef, | 78 | const struct cfg80211_chan_def *chandef, |
| @@ -76,6 +92,9 @@ ieee80211_new_chanctx(struct ieee80211_local *local, | |||
| 76 | ctx->conf.rx_chains_static = 1; | 92 | ctx->conf.rx_chains_static = 1; |
| 77 | ctx->conf.rx_chains_dynamic = 1; | 93 | ctx->conf.rx_chains_dynamic = 1; |
| 78 | ctx->mode = mode; | 94 | ctx->mode = mode; |
| 95 | ctx->conf.radar_enabled = ieee80211_is_radar_required(local); | ||
| 96 | if (!local->use_chanctx) | ||
| 97 | local->hw.conf.radar_enabled = ctx->conf.radar_enabled; | ||
| 79 | 98 | ||
| 80 | /* acquire mutex to prevent idle from changing */ | 99 | /* acquire mutex to prevent idle from changing */ |
| 81 | mutex_lock(&local->mtx); | 100 | mutex_lock(&local->mtx); |
| @@ -110,6 +129,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local, | |||
| 110 | static void ieee80211_free_chanctx(struct ieee80211_local *local, | 129 | static void ieee80211_free_chanctx(struct ieee80211_local *local, |
| 111 | struct ieee80211_chanctx *ctx) | 130 | struct ieee80211_chanctx *ctx) |
| 112 | { | 131 | { |
| 132 | bool check_single_channel = false; | ||
| 113 | lockdep_assert_held(&local->chanctx_mtx); | 133 | lockdep_assert_held(&local->chanctx_mtx); |
| 114 | 134 | ||
| 115 | WARN_ON_ONCE(ctx->refcount != 0); | 135 | WARN_ON_ONCE(ctx->refcount != 0); |
| @@ -119,6 +139,14 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local, | |||
| 119 | chandef->width = NL80211_CHAN_WIDTH_20_NOHT; | 139 | chandef->width = NL80211_CHAN_WIDTH_20_NOHT; |
| 120 | chandef->center_freq1 = chandef->chan->center_freq; | 140 | chandef->center_freq1 = chandef->chan->center_freq; |
| 121 | chandef->center_freq2 = 0; | 141 | chandef->center_freq2 = 0; |
| 142 | |||
| 143 | /* NOTE: Disabling radar is only valid here for | ||
| 144 | * single channel context. To be sure, check it ... | ||
| 145 | */ | ||
| 146 | if (local->hw.conf.radar_enabled) | ||
| 147 | check_single_channel = true; | ||
| 148 | local->hw.conf.radar_enabled = false; | ||
| 149 | |||
| 122 | ieee80211_hw_config(local, 0); | 150 | ieee80211_hw_config(local, 0); |
| 123 | } else { | 151 | } else { |
| 124 | drv_remove_chanctx(local, ctx); | 152 | drv_remove_chanctx(local, ctx); |
| @@ -127,6 +155,9 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local, | |||
| 127 | list_del_rcu(&ctx->list); | 155 | list_del_rcu(&ctx->list); |
| 128 | kfree_rcu(ctx, rcu_head); | 156 | kfree_rcu(ctx, rcu_head); |
| 129 | 157 | ||
| 158 | /* throw a warning if this wasn't the only channel context. */ | ||
| 159 | WARN_ON(check_single_channel && !list_empty(&local->chanctx_list)); | ||
| 160 | |||
| 130 | mutex_lock(&local->mtx); | 161 | mutex_lock(&local->mtx); |
| 131 | ieee80211_recalc_idle(local); | 162 | ieee80211_recalc_idle(local); |
| 132 | mutex_unlock(&local->mtx); | 163 | mutex_unlock(&local->mtx); |
| @@ -238,19 +269,11 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) | |||
| 238 | void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, | 269 | void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, |
| 239 | struct ieee80211_chanctx *chanctx) | 270 | struct ieee80211_chanctx *chanctx) |
| 240 | { | 271 | { |
| 241 | struct ieee80211_sub_if_data *sdata; | 272 | bool radar_enabled; |
| 242 | bool radar_enabled = false; | ||
| 243 | 273 | ||
| 244 | lockdep_assert_held(&local->chanctx_mtx); | 274 | lockdep_assert_held(&local->chanctx_mtx); |
| 245 | 275 | ||
| 246 | rcu_read_lock(); | 276 | radar_enabled = ieee80211_is_radar_required(local); |
| 247 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
| 248 | if (sdata->radar_required) { | ||
| 249 | radar_enabled = true; | ||
| 250 | break; | ||
| 251 | } | ||
| 252 | } | ||
| 253 | rcu_read_unlock(); | ||
| 254 | 277 | ||
| 255 | if (radar_enabled == chanctx->conf.radar_enabled) | 278 | if (radar_enabled == chanctx->conf.radar_enabled) |
| 256 | return; | 279 | return; |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 2a0b2186d98f..170f9a7fa319 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
| @@ -209,6 +209,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 209 | sdata->vif.bss_conf.enable_beacon = true; | 209 | sdata->vif.bss_conf.enable_beacon = true; |
| 210 | sdata->vif.bss_conf.beacon_int = beacon_int; | 210 | sdata->vif.bss_conf.beacon_int = beacon_int; |
| 211 | sdata->vif.bss_conf.basic_rates = basic_rates; | 211 | sdata->vif.bss_conf.basic_rates = basic_rates; |
| 212 | sdata->vif.bss_conf.ssid_len = ifibss->ssid_len; | ||
| 213 | memcpy(sdata->vif.bss_conf.ssid, ifibss->ssid, ifibss->ssid_len); | ||
| 212 | bss_change = BSS_CHANGED_BEACON_INT; | 214 | bss_change = BSS_CHANGED_BEACON_INT; |
| 213 | bss_change |= ieee80211_reset_erp_info(sdata); | 215 | bss_change |= ieee80211_reset_erp_info(sdata); |
| 214 | bss_change |= BSS_CHANGED_BSSID; | 216 | bss_change |= BSS_CHANGED_BSSID; |
| @@ -217,6 +219,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 217 | bss_change |= BSS_CHANGED_BASIC_RATES; | 219 | bss_change |= BSS_CHANGED_BASIC_RATES; |
| 218 | bss_change |= BSS_CHANGED_HT; | 220 | bss_change |= BSS_CHANGED_HT; |
| 219 | bss_change |= BSS_CHANGED_IBSS; | 221 | bss_change |= BSS_CHANGED_IBSS; |
| 222 | bss_change |= BSS_CHANGED_SSID; | ||
| 220 | 223 | ||
| 221 | /* | 224 | /* |
| 222 | * In 5 GHz/802.11a, we can always use short slot time. | 225 | * In 5 GHz/802.11a, we can always use short slot time. |
| @@ -911,7 +914,7 @@ void ieee80211_rx_mgmt_probe_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 911 | return; | 914 | return; |
| 912 | 915 | ||
| 913 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, | 916 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, |
| 914 | &elems); | 917 | false, &elems); |
| 915 | 918 | ||
| 916 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); | 919 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); |
| 917 | } | 920 | } |
| @@ -1159,6 +1162,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
| 1159 | sdata->vif.bss_conf.ibss_joined = false; | 1162 | sdata->vif.bss_conf.ibss_joined = false; |
| 1160 | sdata->vif.bss_conf.ibss_creator = false; | 1163 | sdata->vif.bss_conf.ibss_creator = false; |
| 1161 | sdata->vif.bss_conf.enable_beacon = false; | 1164 | sdata->vif.bss_conf.enable_beacon = false; |
| 1165 | sdata->vif.bss_conf.ssid_len = 0; | ||
| 1162 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); | 1166 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); |
| 1163 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | | 1167 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | |
| 1164 | BSS_CHANGED_IBSS); | 1168 | BSS_CHANGED_IBSS); |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 135ab463cfd9..158e6eb188d3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
| @@ -156,6 +156,7 @@ struct ieee80211_tx_data { | |||
| 156 | struct ieee80211_sub_if_data *sdata; | 156 | struct ieee80211_sub_if_data *sdata; |
| 157 | struct sta_info *sta; | 157 | struct sta_info *sta; |
| 158 | struct ieee80211_key *key; | 158 | struct ieee80211_key *key; |
| 159 | struct ieee80211_tx_rate rate; | ||
| 159 | 160 | ||
| 160 | unsigned int flags; | 161 | unsigned int flags; |
| 161 | }; | 162 | }; |
| @@ -740,6 +741,8 @@ struct ieee80211_sub_if_data { | |||
| 740 | 741 | ||
| 741 | /* bitmap of allowed (non-MCS) rate indexes for rate control */ | 742 | /* bitmap of allowed (non-MCS) rate indexes for rate control */ |
| 742 | u32 rc_rateidx_mask[IEEE80211_NUM_BANDS]; | 743 | u32 rc_rateidx_mask[IEEE80211_NUM_BANDS]; |
| 744 | |||
| 745 | bool rc_has_mcs_mask[IEEE80211_NUM_BANDS]; | ||
| 743 | u8 rc_rateidx_mcs_mask[IEEE80211_NUM_BANDS][IEEE80211_HT_MCS_MASK_LEN]; | 746 | u8 rc_rateidx_mcs_mask[IEEE80211_NUM_BANDS][IEEE80211_HT_MCS_MASK_LEN]; |
| 744 | 747 | ||
| 745 | union { | 748 | union { |
| @@ -1020,7 +1023,7 @@ struct ieee80211_local { | |||
| 1020 | enum mac80211_scan_state next_scan_state; | 1023 | enum mac80211_scan_state next_scan_state; |
| 1021 | struct delayed_work scan_work; | 1024 | struct delayed_work scan_work; |
| 1022 | struct ieee80211_sub_if_data __rcu *scan_sdata; | 1025 | struct ieee80211_sub_if_data __rcu *scan_sdata; |
| 1023 | struct ieee80211_channel *csa_channel; | 1026 | struct cfg80211_chan_def csa_chandef; |
| 1024 | /* For backward compatibility only -- do not use */ | 1027 | /* For backward compatibility only -- do not use */ |
| 1025 | struct cfg80211_chan_def _oper_chandef; | 1028 | struct cfg80211_chan_def _oper_chandef; |
| 1026 | 1029 | ||
| @@ -1179,10 +1182,13 @@ struct ieee802_11_elems { | |||
| 1179 | const u8 *perr; | 1182 | const u8 *perr; |
| 1180 | const struct ieee80211_rann_ie *rann; | 1183 | const struct ieee80211_rann_ie *rann; |
| 1181 | const struct ieee80211_channel_sw_ie *ch_switch_ie; | 1184 | const struct ieee80211_channel_sw_ie *ch_switch_ie; |
| 1185 | const struct ieee80211_ext_chansw_ie *ext_chansw_ie; | ||
| 1186 | const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie; | ||
| 1182 | const u8 *country_elem; | 1187 | const u8 *country_elem; |
| 1183 | const u8 *pwr_constr_elem; | 1188 | const u8 *pwr_constr_elem; |
| 1184 | const struct ieee80211_timeout_interval_ie *timeout_int; | 1189 | const struct ieee80211_timeout_interval_ie *timeout_int; |
| 1185 | const u8 *opmode_notif; | 1190 | const u8 *opmode_notif; |
| 1191 | const struct ieee80211_sec_chan_offs_ie *sec_chan_offs; | ||
| 1186 | 1192 | ||
| 1187 | /* length of them, respectively */ | 1193 | /* length of them, respectively */ |
| 1188 | u8 ssid_len; | 1194 | u8 ssid_len; |
| @@ -1253,10 +1259,6 @@ void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata); | |||
| 1253 | int ieee80211_max_network_latency(struct notifier_block *nb, | 1259 | int ieee80211_max_network_latency(struct notifier_block *nb, |
| 1254 | unsigned long data, void *dummy); | 1260 | unsigned long data, void *dummy); |
| 1255 | int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata); | 1261 | int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata); |
| 1256 | void | ||
| 1257 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | ||
| 1258 | const struct ieee80211_channel_sw_ie *sw_elem, | ||
| 1259 | struct ieee80211_bss *bss, u64 timestamp); | ||
| 1260 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata); | 1262 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata); |
| 1261 | void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | 1263 | void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
| 1262 | struct sk_buff *skb); | 1264 | struct sk_buff *skb); |
| @@ -1494,13 +1496,13 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, | |||
| 1494 | ieee80211_tx_skb_tid(sdata, skb, 7); | 1496 | ieee80211_tx_skb_tid(sdata, skb, 7); |
| 1495 | } | 1497 | } |
| 1496 | 1498 | ||
| 1497 | u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | 1499 | u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, bool action, |
| 1498 | struct ieee802_11_elems *elems, | 1500 | struct ieee802_11_elems *elems, |
| 1499 | u64 filter, u32 crc); | 1501 | u64 filter, u32 crc); |
| 1500 | static inline void ieee802_11_parse_elems(u8 *start, size_t len, | 1502 | static inline void ieee802_11_parse_elems(u8 *start, size_t len, bool action, |
| 1501 | struct ieee802_11_elems *elems) | 1503 | struct ieee802_11_elems *elems) |
| 1502 | { | 1504 | { |
| 1503 | ieee802_11_parse_elems_crc(start, len, elems, 0, 0); | 1505 | ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0); |
| 1504 | } | 1506 | } |
| 1505 | 1507 | ||
| 1506 | u32 ieee80211_mandatory_rates(struct ieee80211_local *local, | 1508 | u32 ieee80211_mandatory_rates(struct ieee80211_local *local, |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 146b1320af4e..9daa64ee337e 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
| @@ -839,11 +839,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
| 839 | * | 839 | * |
| 840 | * sta_info_flush_cleanup() requires rcu_barrier() | 840 | * sta_info_flush_cleanup() requires rcu_barrier() |
| 841 | * first to wait for the station call_rcu() calls | 841 | * first to wait for the station call_rcu() calls |
| 842 | * to complete, here we need at least sychronize_rcu() | 842 | * to complete, and we also need synchronize_rcu() |
| 843 | * it to wait for the RX path in case it is using the | 843 | * to wait for the RX path in case it is using the |
| 844 | * interface and enqueuing frames at this very time on | 844 | * interface and enqueuing frames at this very time on |
| 845 | * another CPU. | 845 | * another CPU. |
| 846 | */ | 846 | */ |
| 847 | synchronize_rcu(); | ||
| 847 | rcu_barrier(); | 848 | rcu_barrier(); |
| 848 | sta_info_flush_cleanup(sdata); | 849 | sta_info_flush_cleanup(sdata); |
| 849 | 850 | ||
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 52136fd5ba97..8a7bfc47d577 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
| @@ -668,6 +668,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 668 | int channels, max_bitrates; | 668 | int channels, max_bitrates; |
| 669 | bool supp_ht, supp_vht; | 669 | bool supp_ht, supp_vht; |
| 670 | netdev_features_t feature_whitelist; | 670 | netdev_features_t feature_whitelist; |
| 671 | struct cfg80211_chan_def dflt_chandef = {}; | ||
| 671 | static const u32 cipher_suites[] = { | 672 | static const u32 cipher_suites[] = { |
| 672 | /* keep WEP first, it may be removed below */ | 673 | /* keep WEP first, it may be removed below */ |
| 673 | WLAN_CIPHER_SUITE_WEP40, | 674 | WLAN_CIPHER_SUITE_WEP40, |
| @@ -745,19 +746,19 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 745 | sband = local->hw.wiphy->bands[band]; | 746 | sband = local->hw.wiphy->bands[band]; |
| 746 | if (!sband) | 747 | if (!sband) |
| 747 | continue; | 748 | continue; |
| 748 | if (!local->use_chanctx && !local->_oper_chandef.chan) { | 749 | |
| 750 | if (!dflt_chandef.chan) { | ||
| 751 | cfg80211_chandef_create(&dflt_chandef, | ||
| 752 | &sband->channels[0], | ||
| 753 | NL80211_CHAN_NO_HT); | ||
| 749 | /* init channel we're on */ | 754 | /* init channel we're on */ |
| 750 | struct cfg80211_chan_def chandef = { | 755 | if (!local->use_chanctx && !local->_oper_chandef.chan) { |
| 751 | .chan = &sband->channels[0], | 756 | local->hw.conf.chandef = dflt_chandef; |
| 752 | .width = NL80211_CHAN_NO_HT, | 757 | local->_oper_chandef = dflt_chandef; |
| 753 | .center_freq1 = sband->channels[0].center_freq, | 758 | } |
| 754 | .center_freq2 = 0 | 759 | local->monitor_chandef = dflt_chandef; |
| 755 | }; | ||
| 756 | local->hw.conf.chandef = local->_oper_chandef = chandef; | ||
| 757 | } | 760 | } |
| 758 | cfg80211_chandef_create(&local->monitor_chandef, | 761 | |
| 759 | &sband->channels[0], | ||
| 760 | NL80211_CHAN_NO_HT); | ||
| 761 | channels += sband->n_channels; | 762 | channels += sband->n_channels; |
| 762 | 763 | ||
| 763 | if (max_bitrates < sband->n_bitrates) | 764 | if (max_bitrates < sband->n_bitrates) |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index fd1024ef393b..6952760881c8 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
| @@ -838,7 +838,7 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata, | |||
| 838 | if (baselen > len) | 838 | if (baselen > len) |
| 839 | return; | 839 | return; |
| 840 | 840 | ||
| 841 | ieee802_11_parse_elems(pos, len - baselen, &elems); | 841 | ieee802_11_parse_elems(pos, len - baselen, false, &elems); |
| 842 | 842 | ||
| 843 | /* 802.11-2012 10.1.4.3.2 */ | 843 | /* 802.11-2012 10.1.4.3.2 */ |
| 844 | if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) && | 844 | if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) && |
| @@ -899,7 +899,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
| 899 | return; | 899 | return; |
| 900 | 900 | ||
| 901 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, | 901 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, |
| 902 | &elems); | 902 | false, &elems); |
| 903 | 903 | ||
| 904 | /* ignore non-mesh or secure / unsecure mismatch */ | 904 | /* ignore non-mesh or secure / unsecure mismatch */ |
| 905 | if ((!elems.mesh_id || !elems.mesh_config) || | 905 | if ((!elems.mesh_id || !elems.mesh_config) || |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index c82d5e6a24c0..486819cd02cd 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
| @@ -880,7 +880,7 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, | |||
| 880 | 880 | ||
| 881 | baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt; | 881 | baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt; |
| 882 | ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, | 882 | ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, |
| 883 | len - baselen, &elems); | 883 | len - baselen, false, &elems); |
| 884 | 884 | ||
| 885 | if (elems.preq) { | 885 | if (elems.preq) { |
| 886 | if (elems.preq_len != 37) | 886 | if (elems.preq_len != 37) |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 937e06fe8f2a..09bebed99416 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
| @@ -544,8 +544,8 @@ static void mesh_plink_timer(unsigned long data) | |||
| 544 | return; | 544 | return; |
| 545 | } | 545 | } |
| 546 | mpl_dbg(sta->sdata, | 546 | mpl_dbg(sta->sdata, |
| 547 | "Mesh plink timer for %pM fired on state %d\n", | 547 | "Mesh plink timer for %pM fired on state %s\n", |
| 548 | sta->sta.addr, sta->plink_state); | 548 | sta->sta.addr, mplstates[sta->plink_state]); |
| 549 | reason = 0; | 549 | reason = 0; |
| 550 | llid = sta->llid; | 550 | llid = sta->llid; |
| 551 | plid = sta->plid; | 551 | plid = sta->plid; |
| @@ -687,7 +687,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | |||
| 687 | baseaddr += 4; | 687 | baseaddr += 4; |
| 688 | baselen += 4; | 688 | baselen += 4; |
| 689 | } | 689 | } |
| 690 | ieee802_11_parse_elems(baseaddr, len - baselen, &elems); | 690 | ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems); |
| 691 | 691 | ||
| 692 | if (!elems.peering) { | 692 | if (!elems.peering) { |
| 693 | mpl_dbg(sdata, | 693 | mpl_dbg(sdata, |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 9c4968938472..13bb81402e1f 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 | ||
| @@ -303,12 +305,6 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | |||
| 303 | channel->band); | 305 | channel->band); |
| 304 | vht_chandef.center_freq2 = 0; | 306 | vht_chandef.center_freq2 = 0; |
| 305 | 307 | ||
| 306 | if (vht_oper->center_freq_seg2_idx) | ||
| 307 | vht_chandef.center_freq2 = | ||
| 308 | ieee80211_channel_to_frequency( | ||
| 309 | vht_oper->center_freq_seg2_idx, | ||
| 310 | channel->band); | ||
| 311 | |||
| 312 | switch (vht_oper->chan_width) { | 308 | switch (vht_oper->chan_width) { |
| 313 | case IEEE80211_VHT_CHANWIDTH_USE_HT: | 309 | case IEEE80211_VHT_CHANWIDTH_USE_HT: |
| 314 | vht_chandef.width = chandef->width; | 310 | vht_chandef.width = chandef->width; |
| @@ -321,6 +317,10 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | |||
| 321 | break; | 317 | break; |
| 322 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: | 318 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: |
| 323 | vht_chandef.width = NL80211_CHAN_WIDTH_80P80; | 319 | vht_chandef.width = NL80211_CHAN_WIDTH_80P80; |
| 320 | vht_chandef.center_freq2 = | ||
| 321 | ieee80211_channel_to_frequency( | ||
| 322 | vht_oper->center_freq_seg2_idx, | ||
| 323 | channel->band); | ||
| 324 | break; | 324 | break; |
| 325 | default: | 325 | default: |
| 326 | if (verbose) | 326 | if (verbose) |
| @@ -604,7 +604,6 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, | |||
| 604 | u8 *pos; | 604 | u8 *pos; |
| 605 | u32 cap; | 605 | u32 cap; |
| 606 | struct ieee80211_sta_vht_cap vht_cap; | 606 | struct ieee80211_sta_vht_cap vht_cap; |
| 607 | int i; | ||
| 608 | 607 | ||
| 609 | BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap)); | 608 | BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap)); |
| 610 | 609 | ||
| @@ -632,37 +631,6 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, | |||
| 632 | cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE))) | 631 | cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE))) |
| 633 | cap &= ~IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; | 632 | cap &= ~IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; |
| 634 | 633 | ||
| 635 | if (!(ap_vht_cap->vht_cap_info & | ||
| 636 | cpu_to_le32(IEEE80211_VHT_CAP_TXSTBC))) | ||
| 637 | cap &= ~(IEEE80211_VHT_CAP_RXSTBC_1 | | ||
| 638 | IEEE80211_VHT_CAP_RXSTBC_3 | | ||
| 639 | IEEE80211_VHT_CAP_RXSTBC_4); | ||
| 640 | |||
| 641 | for (i = 0; i < 8; i++) { | ||
| 642 | int shift = i * 2; | ||
| 643 | u16 mask = IEEE80211_VHT_MCS_NOT_SUPPORTED << shift; | ||
| 644 | u16 ap_mcs, our_mcs; | ||
| 645 | |||
| 646 | ap_mcs = (le16_to_cpu(ap_vht_cap->supp_mcs.tx_mcs_map) & | ||
| 647 | mask) >> shift; | ||
| 648 | our_mcs = (le16_to_cpu(vht_cap.vht_mcs.rx_mcs_map) & | ||
| 649 | mask) >> shift; | ||
| 650 | |||
| 651 | if (our_mcs == IEEE80211_VHT_MCS_NOT_SUPPORTED) | ||
| 652 | continue; | ||
| 653 | |||
| 654 | switch (ap_mcs) { | ||
| 655 | default: | ||
| 656 | if (our_mcs <= ap_mcs) | ||
| 657 | break; | ||
| 658 | /* fall through */ | ||
| 659 | case IEEE80211_VHT_MCS_NOT_SUPPORTED: | ||
| 660 | vht_cap.vht_mcs.rx_mcs_map &= cpu_to_le16(~mask); | ||
| 661 | vht_cap.vht_mcs.rx_mcs_map |= | ||
| 662 | cpu_to_le16(ap_mcs << shift); | ||
| 663 | } | ||
| 664 | } | ||
| 665 | |||
| 666 | /* reserve and fill IE */ | 634 | /* reserve and fill IE */ |
| 667 | pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); | 635 | pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); |
| 668 | ieee80211_ie_build_vht_cap(pos, &vht_cap, cap); | 636 | ieee80211_ie_build_vht_cap(pos, &vht_cap, cap); |
| @@ -998,16 +966,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
| 998 | if (!ifmgd->associated) | 966 | if (!ifmgd->associated) |
| 999 | goto out; | 967 | goto out; |
| 1000 | 968 | ||
| 1001 | /* | 969 | local->_oper_chandef = local->csa_chandef; |
| 1002 | * FIXME: Here we are downgrading to NL80211_CHAN_WIDTH_20_NOHT | ||
| 1003 | * and don't adjust our ht/vht settings | ||
| 1004 | * This is wrong - we should behave according to the CSA params | ||
| 1005 | */ | ||
| 1006 | local->_oper_chandef.chan = local->csa_channel; | ||
| 1007 | local->_oper_chandef.width = NL80211_CHAN_WIDTH_20_NOHT; | ||
| 1008 | local->_oper_chandef.center_freq1 = | ||
| 1009 | local->_oper_chandef.chan->center_freq; | ||
| 1010 | local->_oper_chandef.center_freq2 = 0; | ||
| 1011 | 970 | ||
| 1012 | if (!local->ops->channel_switch) { | 971 | if (!local->ops->channel_switch) { |
| 1013 | /* call "hw_config" only if doing sw channel switch */ | 972 | /* call "hw_config" only if doing sw channel switch */ |
| @@ -1054,56 +1013,193 @@ static void ieee80211_chswitch_timer(unsigned long data) | |||
| 1054 | ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.chswitch_work); | 1013 | ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.chswitch_work); |
| 1055 | } | 1014 | } |
| 1056 | 1015 | ||
| 1057 | void | 1016 | static void |
| 1058 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | 1017 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, |
| 1059 | const struct ieee80211_channel_sw_ie *sw_elem, | 1018 | u64 timestamp, struct ieee802_11_elems *elems) |
| 1060 | struct ieee80211_bss *bss, u64 timestamp) | ||
| 1061 | { | 1019 | { |
| 1062 | struct cfg80211_bss *cbss = | 1020 | struct ieee80211_local *local = sdata->local; |
| 1063 | container_of((void *)bss, struct cfg80211_bss, priv); | ||
| 1064 | struct ieee80211_channel *new_ch; | ||
| 1065 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1021 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 1066 | int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num, | 1022 | struct cfg80211_bss *cbss = ifmgd->associated; |
| 1067 | cbss->channel->band); | 1023 | struct ieee80211_bss *bss; |
| 1068 | struct ieee80211_chanctx *chanctx; | 1024 | struct ieee80211_chanctx *chanctx; |
| 1025 | enum ieee80211_band new_band; | ||
| 1026 | int new_freq; | ||
| 1027 | u8 new_chan_no; | ||
| 1028 | u8 count; | ||
| 1029 | u8 mode; | ||
| 1030 | struct ieee80211_channel *new_chan; | ||
| 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; | ||
| 1035 | int secondary_channel_offset = -1; | ||
| 1069 | 1036 | ||
| 1070 | ASSERT_MGD_MTX(ifmgd); | 1037 | ASSERT_MGD_MTX(ifmgd); |
| 1071 | 1038 | ||
| 1072 | if (!ifmgd->associated) | 1039 | if (!cbss) |
| 1073 | return; | 1040 | return; |
| 1074 | 1041 | ||
| 1075 | if (sdata->local->scanning) | 1042 | if (local->scanning) |
| 1076 | return; | 1043 | return; |
| 1077 | 1044 | ||
| 1078 | /* Disregard subsequent beacons if we are already running a timer | 1045 | /* disregard subsequent announcements if we are already processing */ |
| 1079 | processing a CSA */ | ||
| 1080 | |||
| 1081 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) | 1046 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) |
| 1082 | return; | 1047 | return; |
| 1083 | 1048 | ||
| 1084 | new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); | 1049 | sec_chan_offs = elems->sec_chan_offs; |
| 1085 | if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) { | 1050 | wide_bw_chansw_ie = elems->wide_bw_chansw_ie; |
| 1051 | |||
| 1052 | if (ifmgd->flags & (IEEE80211_STA_DISABLE_HT | | ||
| 1053 | IEEE80211_STA_DISABLE_40MHZ)) { | ||
| 1054 | sec_chan_offs = NULL; | ||
| 1055 | wide_bw_chansw_ie = NULL; | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT) | ||
| 1059 | wide_bw_chansw_ie = NULL; | ||
| 1060 | |||
| 1061 | if (elems->ext_chansw_ie) { | ||
| 1062 | if (!ieee80211_operating_class_to_band( | ||
| 1063 | elems->ext_chansw_ie->new_operating_class, | ||
| 1064 | &new_band)) { | ||
| 1065 | sdata_info(sdata, | ||
| 1066 | "cannot understand ECSA IE operating class %d, disconnecting\n", | ||
| 1067 | elems->ext_chansw_ie->new_operating_class); | ||
| 1068 | ieee80211_queue_work(&local->hw, | ||
| 1069 | &ifmgd->csa_connection_drop_work); | ||
| 1070 | } | ||
| 1071 | new_chan_no = elems->ext_chansw_ie->new_ch_num; | ||
| 1072 | count = elems->ext_chansw_ie->count; | ||
| 1073 | mode = elems->ext_chansw_ie->mode; | ||
| 1074 | } else if (elems->ch_switch_ie) { | ||
| 1075 | new_band = cbss->channel->band; | ||
| 1076 | new_chan_no = elems->ch_switch_ie->new_ch_num; | ||
| 1077 | count = elems->ch_switch_ie->count; | ||
| 1078 | mode = elems->ch_switch_ie->mode; | ||
| 1079 | } else { | ||
| 1080 | /* nothing here we understand */ | ||
| 1081 | return; | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | bss = (void *)cbss->priv; | ||
| 1085 | |||
| 1086 | new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band); | ||
| 1087 | new_chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); | ||
| 1088 | if (!new_chan || new_chan->flags & IEEE80211_CHAN_DISABLED) { | ||
| 1086 | sdata_info(sdata, | 1089 | sdata_info(sdata, |
| 1087 | "AP %pM switches to unsupported channel (%d MHz), disconnecting\n", | 1090 | "AP %pM switches to unsupported channel (%d MHz), disconnecting\n", |
| 1088 | ifmgd->associated->bssid, new_freq); | 1091 | ifmgd->associated->bssid, new_freq); |
| 1089 | ieee80211_queue_work(&sdata->local->hw, | 1092 | ieee80211_queue_work(&local->hw, |
| 1093 | &ifmgd->csa_connection_drop_work); | ||
| 1094 | return; | ||
| 1095 | } | ||
| 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 | |||
| 1104 | switch (secondary_channel_offset) { | ||
| 1105 | default: | ||
| 1106 | /* secondary_channel_offset was present but is invalid */ | ||
| 1107 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: | ||
| 1108 | cfg80211_chandef_create(&new_chandef, new_chan, | ||
| 1109 | NL80211_CHAN_HT20); | ||
| 1110 | break; | ||
| 1111 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
| 1112 | cfg80211_chandef_create(&new_chandef, new_chan, | ||
| 1113 | NL80211_CHAN_HT40PLUS); | ||
| 1114 | break; | ||
| 1115 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
| 1116 | cfg80211_chandef_create(&new_chandef, new_chan, | ||
| 1117 | NL80211_CHAN_HT40MINUS); | ||
| 1118 | break; | ||
| 1119 | case -1: | ||
| 1120 | cfg80211_chandef_create(&new_chandef, new_chan, | ||
| 1121 | NL80211_CHAN_NO_HT); | ||
| 1122 | break; | ||
| 1123 | } | ||
| 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 | |||
| 1178 | if (!cfg80211_chandef_usable(local->hw.wiphy, &new_chandef, | ||
| 1179 | IEEE80211_CHAN_DISABLED)) { | ||
| 1180 | sdata_info(sdata, | ||
| 1181 | "AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n", | ||
| 1182 | ifmgd->associated->bssid, new_freq, | ||
| 1183 | new_chandef.width, new_chandef.center_freq1, | ||
| 1184 | new_chandef.center_freq2); | ||
| 1185 | ieee80211_queue_work(&local->hw, | ||
| 1090 | &ifmgd->csa_connection_drop_work); | 1186 | &ifmgd->csa_connection_drop_work); |
| 1091 | return; | 1187 | return; |
| 1092 | } | 1188 | } |
| 1093 | 1189 | ||
| 1094 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | 1190 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; |
| 1095 | 1191 | ||
| 1096 | if (sdata->local->use_chanctx) { | 1192 | if (local->use_chanctx) { |
| 1097 | sdata_info(sdata, | 1193 | sdata_info(sdata, |
| 1098 | "not handling channel switch with channel contexts\n"); | 1194 | "not handling channel switch with channel contexts\n"); |
| 1099 | ieee80211_queue_work(&sdata->local->hw, | 1195 | ieee80211_queue_work(&local->hw, |
| 1100 | &ifmgd->csa_connection_drop_work); | 1196 | &ifmgd->csa_connection_drop_work); |
| 1101 | return; | 1197 | return; |
| 1102 | } | 1198 | } |
| 1103 | 1199 | ||
| 1104 | mutex_lock(&sdata->local->chanctx_mtx); | 1200 | mutex_lock(&local->chanctx_mtx); |
| 1105 | if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) { | 1201 | if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) { |
| 1106 | mutex_unlock(&sdata->local->chanctx_mtx); | 1202 | mutex_unlock(&local->chanctx_mtx); |
| 1107 | return; | 1203 | return; |
| 1108 | } | 1204 | } |
| 1109 | chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf), | 1205 | chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf), |
| @@ -1111,40 +1207,39 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
| 1111 | if (chanctx->refcount > 1) { | 1207 | if (chanctx->refcount > 1) { |
| 1112 | sdata_info(sdata, | 1208 | sdata_info(sdata, |
| 1113 | "channel switch with multiple interfaces on the same channel, disconnecting\n"); | 1209 | "channel switch with multiple interfaces on the same channel, disconnecting\n"); |
| 1114 | ieee80211_queue_work(&sdata->local->hw, | 1210 | ieee80211_queue_work(&local->hw, |
| 1115 | &ifmgd->csa_connection_drop_work); | 1211 | &ifmgd->csa_connection_drop_work); |
| 1116 | mutex_unlock(&sdata->local->chanctx_mtx); | 1212 | mutex_unlock(&local->chanctx_mtx); |
| 1117 | return; | 1213 | return; |
| 1118 | } | 1214 | } |
| 1119 | mutex_unlock(&sdata->local->chanctx_mtx); | 1215 | mutex_unlock(&local->chanctx_mtx); |
| 1120 | 1216 | ||
| 1121 | sdata->local->csa_channel = new_ch; | 1217 | local->csa_chandef = new_chandef; |
| 1122 | 1218 | ||
| 1123 | if (sw_elem->mode) | 1219 | if (mode) |
| 1124 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | 1220 | ieee80211_stop_queues_by_reason(&local->hw, |
| 1125 | IEEE80211_MAX_QUEUE_MAP, | 1221 | IEEE80211_MAX_QUEUE_MAP, |
| 1126 | IEEE80211_QUEUE_STOP_REASON_CSA); | 1222 | IEEE80211_QUEUE_STOP_REASON_CSA); |
| 1127 | 1223 | ||
| 1128 | if (sdata->local->ops->channel_switch) { | 1224 | if (local->ops->channel_switch) { |
| 1129 | /* use driver's channel switch callback */ | 1225 | /* use driver's channel switch callback */ |
| 1130 | struct ieee80211_channel_switch ch_switch = { | 1226 | struct ieee80211_channel_switch ch_switch = { |
| 1131 | .timestamp = timestamp, | 1227 | .timestamp = timestamp, |
| 1132 | .block_tx = sw_elem->mode, | 1228 | .block_tx = mode, |
| 1133 | .channel = new_ch, | 1229 | .chandef = new_chandef, |
| 1134 | .count = sw_elem->count, | 1230 | .count = count, |
| 1135 | }; | 1231 | }; |
| 1136 | 1232 | ||
| 1137 | drv_channel_switch(sdata->local, &ch_switch); | 1233 | drv_channel_switch(local, &ch_switch); |
| 1138 | return; | 1234 | return; |
| 1139 | } | 1235 | } |
| 1140 | 1236 | ||
| 1141 | /* channel switch handled in software */ | 1237 | /* channel switch handled in software */ |
| 1142 | if (sw_elem->count <= 1) | 1238 | if (count <= 1) |
| 1143 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); | 1239 | ieee80211_queue_work(&local->hw, &ifmgd->chswitch_work); |
| 1144 | else | 1240 | else |
| 1145 | mod_timer(&ifmgd->chswitch_timer, | 1241 | mod_timer(&ifmgd->chswitch_timer, |
| 1146 | TU_TO_EXP_TIME(sw_elem->count * | 1242 | TU_TO_EXP_TIME(count * cbss->beacon_interval)); |
| 1147 | cbss->beacon_interval)); | ||
| 1148 | } | 1243 | } |
| 1149 | 1244 | ||
| 1150 | static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | 1245 | static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, |
| @@ -1566,6 +1661,7 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
| 1566 | params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); | 1661 | params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); |
| 1567 | params.cw_min = ecw2cw(pos[1] & 0x0f); | 1662 | params.cw_min = ecw2cw(pos[1] & 0x0f); |
| 1568 | params.txop = get_unaligned_le16(pos + 2); | 1663 | params.txop = get_unaligned_le16(pos + 2); |
| 1664 | params.acm = acm; | ||
| 1569 | params.uapsd = uapsd; | 1665 | params.uapsd = uapsd; |
| 1570 | 1666 | ||
| 1571 | mlme_dbg(sdata, | 1667 | mlme_dbg(sdata, |
| @@ -2120,7 +2216,6 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif) | |||
| 2120 | 2216 | ||
| 2121 | trace_api_beacon_loss(sdata); | 2217 | trace_api_beacon_loss(sdata); |
| 2122 | 2218 | ||
| 2123 | WARN_ON(hw->flags & IEEE80211_HW_CONNECTION_MONITOR); | ||
| 2124 | sdata->u.mgd.connection_loss = false; | 2219 | sdata->u.mgd.connection_loss = false; |
| 2125 | ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work); | 2220 | ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work); |
| 2126 | } | 2221 | } |
| @@ -2170,7 +2265,7 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | |||
| 2170 | u32 tx_flags = 0; | 2265 | u32 tx_flags = 0; |
| 2171 | 2266 | ||
| 2172 | pos = mgmt->u.auth.variable; | 2267 | pos = mgmt->u.auth.variable; |
| 2173 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | 2268 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), false, &elems); |
| 2174 | if (!elems.challenge) | 2269 | if (!elems.challenge) |
| 2175 | return; | 2270 | return; |
| 2176 | auth_data->expected_transaction = 4; | 2271 | auth_data->expected_transaction = 4; |
| @@ -2435,7 +2530,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
| 2435 | } | 2530 | } |
| 2436 | 2531 | ||
| 2437 | pos = mgmt->u.assoc_resp.variable; | 2532 | pos = mgmt->u.assoc_resp.variable; |
| 2438 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | 2533 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), false, &elems); |
| 2439 | 2534 | ||
| 2440 | if (!elems.supp_rates) { | 2535 | if (!elems.supp_rates) { |
| 2441 | sdata_info(sdata, "no SuppRates element in AssocResp\n"); | 2536 | sdata_info(sdata, "no SuppRates element in AssocResp\n"); |
| @@ -2604,7 +2699,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
| 2604 | capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); | 2699 | capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); |
| 2605 | 2700 | ||
| 2606 | pos = mgmt->u.assoc_resp.variable; | 2701 | pos = mgmt->u.assoc_resp.variable; |
| 2607 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | 2702 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), false, &elems); |
| 2608 | 2703 | ||
| 2609 | if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && | 2704 | if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && |
| 2610 | elems.timeout_int && | 2705 | elems.timeout_int && |
| @@ -2659,6 +2754,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 2659 | struct ieee80211_channel *channel; | 2754 | struct ieee80211_channel *channel; |
| 2660 | bool need_ps = false; | 2755 | bool need_ps = false; |
| 2661 | 2756 | ||
| 2757 | lockdep_assert_held(&sdata->u.mgd.mtx); | ||
| 2758 | |||
| 2662 | if ((sdata->u.mgd.associated && | 2759 | if ((sdata->u.mgd.associated && |
| 2663 | ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) || | 2760 | ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) || |
| 2664 | (sdata->u.mgd.assoc_data && | 2761 | (sdata->u.mgd.assoc_data && |
| @@ -2689,7 +2786,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 2689 | if (bss) | 2786 | if (bss) |
| 2690 | ieee80211_rx_bss_put(local, bss); | 2787 | ieee80211_rx_bss_put(local, bss); |
| 2691 | 2788 | ||
| 2692 | if (!sdata->u.mgd.associated) | 2789 | if (!sdata->u.mgd.associated || |
| 2790 | !ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) | ||
| 2693 | return; | 2791 | return; |
| 2694 | 2792 | ||
| 2695 | if (need_ps) { | 2793 | if (need_ps) { |
| @@ -2698,10 +2796,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 2698 | mutex_unlock(&local->iflist_mtx); | 2796 | mutex_unlock(&local->iflist_mtx); |
| 2699 | } | 2797 | } |
| 2700 | 2798 | ||
| 2701 | if (elems->ch_switch_ie && | 2799 | ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, elems); |
| 2702 | memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, ETH_ALEN) == 0) | 2800 | |
| 2703 | ieee80211_sta_process_chanswitch(sdata, elems->ch_switch_ie, | ||
| 2704 | bss, rx_status->mactime); | ||
| 2705 | } | 2801 | } |
| 2706 | 2802 | ||
| 2707 | 2803 | ||
| @@ -2726,7 +2822,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
| 2726 | return; | 2822 | return; |
| 2727 | 2823 | ||
| 2728 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, | 2824 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, |
| 2729 | &elems); | 2825 | false, &elems); |
| 2730 | 2826 | ||
| 2731 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); | 2827 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); |
| 2732 | 2828 | ||
| @@ -2809,7 +2905,7 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 2809 | if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon && | 2905 | if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon && |
| 2810 | ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) { | 2906 | ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) { |
| 2811 | ieee802_11_parse_elems(mgmt->u.beacon.variable, | 2907 | ieee802_11_parse_elems(mgmt->u.beacon.variable, |
| 2812 | len - baselen, &elems); | 2908 | len - baselen, false, &elems); |
| 2813 | 2909 | ||
| 2814 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); | 2910 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); |
| 2815 | ifmgd->assoc_data->have_beacon = true; | 2911 | ifmgd->assoc_data->have_beacon = true; |
| @@ -2919,7 +3015,7 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 2919 | 3015 | ||
| 2920 | ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); | 3016 | ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); |
| 2921 | ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, | 3017 | ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, |
| 2922 | len - baselen, &elems, | 3018 | len - baselen, false, &elems, |
| 2923 | care_about_ies, ncrc); | 3019 | care_about_ies, ncrc); |
| 2924 | 3020 | ||
| 2925 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) { | 3021 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) { |
| @@ -3066,6 +3162,8 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
| 3066 | enum rx_mgmt_action rma = RX_MGMT_NONE; | 3162 | enum rx_mgmt_action rma = RX_MGMT_NONE; |
| 3067 | u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN]; | 3163 | u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
| 3068 | u16 fc; | 3164 | u16 fc; |
| 3165 | struct ieee802_11_elems elems; | ||
| 3166 | int ies_len; | ||
| 3069 | 3167 | ||
| 3070 | rx_status = (struct ieee80211_rx_status *) skb->cb; | 3168 | rx_status = (struct ieee80211_rx_status *) skb->cb; |
| 3071 | mgmt = (struct ieee80211_mgmt *) skb->data; | 3169 | mgmt = (struct ieee80211_mgmt *) skb->data; |
| @@ -3095,14 +3193,48 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
| 3095 | rma = ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, &bss); | 3193 | rma = ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, &bss); |
| 3096 | break; | 3194 | break; |
| 3097 | case IEEE80211_STYPE_ACTION: | 3195 | case IEEE80211_STYPE_ACTION: |
| 3098 | switch (mgmt->u.action.category) { | 3196 | if (mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) { |
| 3099 | case WLAN_CATEGORY_SPECTRUM_MGMT: | 3197 | ies_len = skb->len - |
| 3198 | offsetof(struct ieee80211_mgmt, | ||
| 3199 | u.action.u.chan_switch.variable); | ||
| 3200 | |||
| 3201 | if (ies_len < 0) | ||
| 3202 | break; | ||
| 3203 | |||
| 3204 | ieee802_11_parse_elems( | ||
| 3205 | mgmt->u.action.u.chan_switch.variable, | ||
| 3206 | ies_len, true, &elems); | ||
| 3207 | |||
| 3208 | if (elems.parse_error) | ||
| 3209 | break; | ||
| 3210 | |||
| 3100 | ieee80211_sta_process_chanswitch(sdata, | 3211 | ieee80211_sta_process_chanswitch(sdata, |
| 3101 | &mgmt->u.action.u.chan_switch.sw_elem, | 3212 | rx_status->mactime, |
| 3102 | (void *)ifmgd->associated->priv, | 3213 | &elems); |
| 3103 | rx_status->mactime); | 3214 | } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { |
| 3104 | break; | 3215 | ies_len = skb->len - |
| 3216 | offsetof(struct ieee80211_mgmt, | ||
| 3217 | u.action.u.ext_chan_switch.variable); | ||
| 3218 | |||
| 3219 | if (ies_len < 0) | ||
| 3220 | break; | ||
| 3221 | |||
| 3222 | ieee802_11_parse_elems( | ||
| 3223 | mgmt->u.action.u.ext_chan_switch.variable, | ||
| 3224 | ies_len, true, &elems); | ||
| 3225 | |||
| 3226 | if (elems.parse_error) | ||
| 3227 | break; | ||
| 3228 | |||
| 3229 | /* for the handling code pretend this was also an IE */ | ||
| 3230 | elems.ext_chansw_ie = | ||
| 3231 | &mgmt->u.action.u.ext_chan_switch.data; | ||
| 3232 | |||
| 3233 | ieee80211_sta_process_chanswitch(sdata, | ||
| 3234 | rx_status->mactime, | ||
| 3235 | &elems); | ||
| 3105 | } | 3236 | } |
| 3237 | break; | ||
| 3106 | } | 3238 | } |
| 3107 | mutex_unlock(&ifmgd->mtx); | 3239 | mutex_unlock(&ifmgd->mtx); |
| 3108 | 3240 | ||
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index d1c021b62fe5..7fc5d0d8149a 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
| @@ -37,8 +37,9 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
| 37 | IEEE80211_MAX_QUEUE_MAP, | 37 | IEEE80211_MAX_QUEUE_MAP, |
| 38 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 38 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); |
| 39 | 39 | ||
| 40 | /* flush out all packets */ | 40 | /* flush out all packets and station cleanup call_rcu()s */ |
| 41 | synchronize_net(); | 41 | synchronize_net(); |
| 42 | rcu_barrier(); | ||
| 42 | 43 | ||
| 43 | ieee80211_flush_queues(local, NULL); | 44 | ieee80211_flush_queues(local, NULL); |
| 44 | 45 | ||
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index dd88381c53b7..0d51877efdb7 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
| @@ -252,6 +252,25 @@ rate_lowest_non_cck_index(struct ieee80211_supported_band *sband, | |||
| 252 | return 0; | 252 | return 0; |
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | static void __rate_control_send_low(struct ieee80211_hw *hw, | ||
| 256 | struct ieee80211_supported_band *sband, | ||
| 257 | struct ieee80211_sta *sta, | ||
| 258 | struct ieee80211_tx_info *info) | ||
| 259 | { | ||
| 260 | if ((sband->band != IEEE80211_BAND_2GHZ) || | ||
| 261 | !(info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)) | ||
| 262 | info->control.rates[0].idx = rate_lowest_index(sband, sta); | ||
| 263 | else | ||
| 264 | info->control.rates[0].idx = | ||
| 265 | rate_lowest_non_cck_index(sband, sta); | ||
| 266 | |||
| 267 | info->control.rates[0].count = | ||
| 268 | (info->flags & IEEE80211_TX_CTL_NO_ACK) ? | ||
| 269 | 1 : hw->max_rate_tries; | ||
| 270 | |||
| 271 | info->control.skip_table = 1; | ||
| 272 | } | ||
| 273 | |||
| 255 | 274 | ||
| 256 | bool rate_control_send_low(struct ieee80211_sta *sta, | 275 | bool rate_control_send_low(struct ieee80211_sta *sta, |
| 257 | void *priv_sta, | 276 | void *priv_sta, |
| @@ -262,16 +281,8 @@ bool rate_control_send_low(struct ieee80211_sta *sta, | |||
| 262 | int mcast_rate; | 281 | int mcast_rate; |
| 263 | 282 | ||
| 264 | if (!sta || !priv_sta || rc_no_data_or_no_ack_use_min(txrc)) { | 283 | if (!sta || !priv_sta || rc_no_data_or_no_ack_use_min(txrc)) { |
| 265 | if ((sband->band != IEEE80211_BAND_2GHZ) || | 284 | __rate_control_send_low(txrc->hw, sband, sta, info); |
| 266 | !(info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)) | 285 | |
| 267 | info->control.rates[0].idx = | ||
| 268 | rate_lowest_index(txrc->sband, sta); | ||
| 269 | else | ||
| 270 | info->control.rates[0].idx = | ||
| 271 | rate_lowest_non_cck_index(txrc->sband, sta); | ||
| 272 | info->control.rates[0].count = | ||
| 273 | (info->flags & IEEE80211_TX_CTL_NO_ACK) ? | ||
| 274 | 1 : txrc->hw->max_rate_tries; | ||
| 275 | if (!sta && txrc->bss) { | 286 | if (!sta && txrc->bss) { |
| 276 | mcast_rate = txrc->bss_conf->mcast_rate[sband->band]; | 287 | mcast_rate = txrc->bss_conf->mcast_rate[sband->band]; |
| 277 | if (mcast_rate > 0) { | 288 | if (mcast_rate > 0) { |
| @@ -355,7 +366,8 @@ static bool rate_idx_match_mcs_mask(struct ieee80211_tx_rate *rate, | |||
| 355 | 366 | ||
| 356 | 367 | ||
| 357 | static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, | 368 | static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, |
| 358 | struct ieee80211_tx_rate_control *txrc, | 369 | struct ieee80211_supported_band *sband, |
| 370 | enum nl80211_chan_width chan_width, | ||
| 359 | u32 mask, | 371 | u32 mask, |
| 360 | u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) | 372 | u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) |
| 361 | { | 373 | { |
| @@ -375,27 +387,17 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, | |||
| 375 | IEEE80211_TX_RC_USE_SHORT_PREAMBLE); | 387 | IEEE80211_TX_RC_USE_SHORT_PREAMBLE); |
| 376 | alt_rate.count = rate->count; | 388 | alt_rate.count = rate->count; |
| 377 | if (rate_idx_match_legacy_mask(&alt_rate, | 389 | if (rate_idx_match_legacy_mask(&alt_rate, |
| 378 | txrc->sband->n_bitrates, | 390 | sband->n_bitrates, mask)) { |
| 379 | mask)) { | ||
| 380 | *rate = alt_rate; | 391 | *rate = alt_rate; |
| 381 | return; | 392 | return; |
| 382 | } | 393 | } |
| 383 | } else { | 394 | } else { |
| 384 | struct sk_buff *skb = txrc->skb; | ||
| 385 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
| 386 | __le16 fc; | ||
| 387 | |||
| 388 | /* handle legacy rates */ | 395 | /* handle legacy rates */ |
| 389 | if (rate_idx_match_legacy_mask(rate, txrc->sband->n_bitrates, | 396 | if (rate_idx_match_legacy_mask(rate, sband->n_bitrates, mask)) |
| 390 | mask)) | ||
| 391 | return; | 397 | return; |
| 392 | 398 | ||
| 393 | /* if HT BSS, and we handle a data frame, also try HT rates */ | 399 | /* if HT BSS, and we handle a data frame, also try HT rates */ |
| 394 | if (txrc->bss_conf->chandef.width == NL80211_CHAN_WIDTH_20_NOHT) | 400 | if (chan_width == NL80211_CHAN_WIDTH_20_NOHT) |
| 395 | return; | ||
| 396 | |||
| 397 | fc = hdr->frame_control; | ||
| 398 | if (!ieee80211_is_data(fc)) | ||
| 399 | return; | 401 | return; |
| 400 | 402 | ||
| 401 | alt_rate.idx = 0; | 403 | alt_rate.idx = 0; |
| @@ -408,7 +410,7 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, | |||
| 408 | 410 | ||
| 409 | alt_rate.flags |= IEEE80211_TX_RC_MCS; | 411 | alt_rate.flags |= IEEE80211_TX_RC_MCS; |
| 410 | 412 | ||
| 411 | if (txrc->bss_conf->chandef.width == NL80211_CHAN_WIDTH_40) | 413 | if (chan_width == NL80211_CHAN_WIDTH_40) |
| 412 | alt_rate.flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | 414 | alt_rate.flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; |
| 413 | 415 | ||
| 414 | if (rate_idx_match_mcs_mask(&alt_rate, mcs_mask)) { | 416 | if (rate_idx_match_mcs_mask(&alt_rate, mcs_mask)) { |
| @@ -426,6 +428,228 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, | |||
| 426 | */ | 428 | */ |
| 427 | } | 429 | } |
| 428 | 430 | ||
| 431 | static void rate_fixup_ratelist(struct ieee80211_vif *vif, | ||
| 432 | struct ieee80211_supported_band *sband, | ||
| 433 | struct ieee80211_tx_info *info, | ||
| 434 | struct ieee80211_tx_rate *rates, | ||
| 435 | int max_rates) | ||
| 436 | { | ||
| 437 | struct ieee80211_rate *rate; | ||
| 438 | bool inval = false; | ||
| 439 | int i; | ||
| 440 | |||
| 441 | /* | ||
| 442 | * Set up the RTS/CTS rate as the fastest basic rate | ||
| 443 | * that is not faster than the data rate unless there | ||
| 444 | * is no basic rate slower than the data rate, in which | ||
| 445 | * case we pick the slowest basic rate | ||
| 446 | * | ||
| 447 | * XXX: Should this check all retry rates? | ||
| 448 | */ | ||
| 449 | if (!(rates[0].flags & IEEE80211_TX_RC_MCS)) { | ||
| 450 | u32 basic_rates = vif->bss_conf.basic_rates; | ||
| 451 | s8 baserate = basic_rates ? ffs(basic_rates - 1) : 0; | ||
| 452 | |||
| 453 | rate = &sband->bitrates[rates[0].idx]; | ||
| 454 | |||
| 455 | for (i = 0; i < sband->n_bitrates; i++) { | ||
| 456 | /* must be a basic rate */ | ||
| 457 | if (!(basic_rates & BIT(i))) | ||
| 458 | continue; | ||
| 459 | /* must not be faster than the data rate */ | ||
| 460 | if (sband->bitrates[i].bitrate > rate->bitrate) | ||
| 461 | continue; | ||
| 462 | /* maximum */ | ||
| 463 | if (sband->bitrates[baserate].bitrate < | ||
| 464 | sband->bitrates[i].bitrate) | ||
| 465 | baserate = i; | ||
| 466 | } | ||
| 467 | |||
| 468 | info->control.rts_cts_rate_idx = baserate; | ||
| 469 | } | ||
| 470 | |||
| 471 | for (i = 0; i < max_rates; i++) { | ||
| 472 | /* | ||
| 473 | * make sure there's no valid rate following | ||
| 474 | * an invalid one, just in case drivers don't | ||
| 475 | * take the API seriously to stop at -1. | ||
| 476 | */ | ||
| 477 | if (inval) { | ||
| 478 | rates[i].idx = -1; | ||
| 479 | continue; | ||
| 480 | } | ||
| 481 | if (rates[i].idx < 0) { | ||
| 482 | inval = true; | ||
| 483 | continue; | ||
| 484 | } | ||
| 485 | |||
| 486 | /* | ||
| 487 | * For now assume MCS is already set up correctly, this | ||
| 488 | * needs to be fixed. | ||
| 489 | */ | ||
| 490 | if (rates[i].flags & IEEE80211_TX_RC_MCS) { | ||
| 491 | WARN_ON(rates[i].idx > 76); | ||
| 492 | |||
| 493 | if (!(rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) && | ||
| 494 | info->control.use_cts_prot) | ||
| 495 | rates[i].flags |= | ||
| 496 | IEEE80211_TX_RC_USE_CTS_PROTECT; | ||
| 497 | continue; | ||
| 498 | } | ||
| 499 | |||
| 500 | if (rates[i].flags & IEEE80211_TX_RC_VHT_MCS) { | ||
| 501 | WARN_ON(ieee80211_rate_get_vht_mcs(&rates[i]) > 9); | ||
| 502 | continue; | ||
| 503 | } | ||
| 504 | |||
| 505 | /* set up RTS protection if desired */ | ||
| 506 | if (info->control.use_rts) { | ||
| 507 | rates[i].flags |= IEEE80211_TX_RC_USE_RTS_CTS; | ||
| 508 | info->control.use_cts_prot = false; | ||
| 509 | } | ||
| 510 | |||
| 511 | /* RC is busted */ | ||
| 512 | if (WARN_ON_ONCE(rates[i].idx >= sband->n_bitrates)) { | ||
| 513 | rates[i].idx = -1; | ||
| 514 | continue; | ||
| 515 | } | ||
| 516 | |||
| 517 | rate = &sband->bitrates[rates[i].idx]; | ||
| 518 | |||
| 519 | /* set up short preamble */ | ||
| 520 | if (info->control.short_preamble && | ||
| 521 | rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) | ||
| 522 | rates[i].flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; | ||
| 523 | |||
| 524 | /* set up G protection */ | ||
| 525 | if (!(rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) && | ||
| 526 | info->control.use_cts_prot && | ||
| 527 | rate->flags & IEEE80211_RATE_ERP_G) | ||
| 528 | rates[i].flags |= IEEE80211_TX_RC_USE_CTS_PROTECT; | ||
| 529 | } | ||
| 530 | } | ||
| 531 | |||
| 532 | |||
| 533 | static void rate_control_fill_sta_table(struct ieee80211_sta *sta, | ||
| 534 | struct ieee80211_tx_info *info, | ||
| 535 | struct ieee80211_tx_rate *rates, | ||
| 536 | int max_rates) | ||
| 537 | { | ||
| 538 | struct ieee80211_sta_rates *ratetbl = NULL; | ||
| 539 | int i; | ||
| 540 | |||
| 541 | if (sta && !info->control.skip_table) | ||
| 542 | ratetbl = rcu_dereference(sta->rates); | ||
| 543 | |||
| 544 | /* Fill remaining rate slots with data from the sta rate table. */ | ||
| 545 | max_rates = min_t(int, max_rates, IEEE80211_TX_RATE_TABLE_SIZE); | ||
| 546 | for (i = 0; i < max_rates; i++) { | ||
| 547 | if (i < ARRAY_SIZE(info->control.rates) && | ||
| 548 | info->control.rates[i].idx >= 0 && | ||
| 549 | info->control.rates[i].count) { | ||
| 550 | if (rates != info->control.rates) | ||
| 551 | rates[i] = info->control.rates[i]; | ||
| 552 | } else if (ratetbl) { | ||
| 553 | rates[i].idx = ratetbl->rate[i].idx; | ||
| 554 | rates[i].flags = ratetbl->rate[i].flags; | ||
| 555 | if (info->control.use_rts) | ||
| 556 | rates[i].count = ratetbl->rate[i].count_rts; | ||
| 557 | else if (info->control.use_cts_prot) | ||
| 558 | rates[i].count = ratetbl->rate[i].count_cts; | ||
| 559 | else | ||
| 560 | rates[i].count = ratetbl->rate[i].count; | ||
| 561 | } else { | ||
| 562 | rates[i].idx = -1; | ||
| 563 | rates[i].count = 0; | ||
| 564 | } | ||
| 565 | |||
| 566 | if (rates[i].idx < 0 || !rates[i].count) | ||
| 567 | break; | ||
| 568 | } | ||
| 569 | } | ||
| 570 | |||
| 571 | static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata, | ||
| 572 | struct ieee80211_sta *sta, | ||
| 573 | struct ieee80211_supported_band *sband, | ||
| 574 | struct ieee80211_tx_info *info, | ||
| 575 | struct ieee80211_tx_rate *rates, | ||
| 576 | int max_rates) | ||
| 577 | { | ||
| 578 | enum nl80211_chan_width chan_width; | ||
| 579 | u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]; | ||
| 580 | bool has_mcs_mask; | ||
| 581 | u32 mask; | ||
| 582 | int i; | ||
| 583 | |||
| 584 | /* | ||
| 585 | * Try to enforce the rateidx mask the user wanted. skip this if the | ||
| 586 | * default mask (allow all rates) is used to save some processing for | ||
| 587 | * the common case. | ||
| 588 | */ | ||
| 589 | mask = sdata->rc_rateidx_mask[info->band]; | ||
| 590 | has_mcs_mask = sdata->rc_has_mcs_mask[info->band]; | ||
| 591 | if (mask == (1 << sband->n_bitrates) - 1 && !has_mcs_mask) | ||
| 592 | return; | ||
| 593 | |||
| 594 | if (has_mcs_mask) | ||
| 595 | memcpy(mcs_mask, sdata->rc_rateidx_mcs_mask[info->band], | ||
| 596 | sizeof(mcs_mask)); | ||
| 597 | else | ||
| 598 | memset(mcs_mask, 0xff, sizeof(mcs_mask)); | ||
| 599 | |||
| 600 | if (sta) { | ||
| 601 | /* Filter out rates that the STA does not support */ | ||
| 602 | mask &= sta->supp_rates[info->band]; | ||
| 603 | for (i = 0; i < sizeof(mcs_mask); i++) | ||
| 604 | mcs_mask[i] &= sta->ht_cap.mcs.rx_mask[i]; | ||
| 605 | } | ||
| 606 | |||
| 607 | /* | ||
| 608 | * Make sure the rate index selected for each TX rate is | ||
| 609 | * included in the configured mask and change the rate indexes | ||
| 610 | * if needed. | ||
| 611 | */ | ||
| 612 | chan_width = sdata->vif.bss_conf.chandef.width; | ||
| 613 | for (i = 0; i < max_rates; i++) { | ||
| 614 | /* Skip invalid rates */ | ||
| 615 | if (rates[i].idx < 0) | ||
| 616 | break; | ||
| 617 | |||
| 618 | rate_idx_match_mask(&rates[i], sband, mask, chan_width, | ||
| 619 | mcs_mask); | ||
| 620 | } | ||
| 621 | } | ||
| 622 | |||
| 623 | void ieee80211_get_tx_rates(struct ieee80211_vif *vif, | ||
| 624 | struct ieee80211_sta *sta, | ||
| 625 | struct sk_buff *skb, | ||
| 626 | struct ieee80211_tx_rate *dest, | ||
| 627 | int max_rates) | ||
| 628 | { | ||
| 629 | struct ieee80211_sub_if_data *sdata; | ||
| 630 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
| 631 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
| 632 | struct ieee80211_supported_band *sband; | ||
| 633 | |||
| 634 | rate_control_fill_sta_table(sta, info, dest, max_rates); | ||
| 635 | |||
| 636 | if (!vif) | ||
| 637 | return; | ||
| 638 | |||
| 639 | sdata = vif_to_sdata(vif); | ||
| 640 | sband = sdata->local->hw.wiphy->bands[info->band]; | ||
| 641 | |||
| 642 | if (ieee80211_is_data(hdr->frame_control)) | ||
| 643 | rate_control_apply_mask(sdata, sta, sband, info, dest, max_rates); | ||
| 644 | |||
| 645 | if (dest[0].idx < 0) | ||
| 646 | __rate_control_send_low(&sdata->local->hw, sband, sta, info); | ||
| 647 | |||
| 648 | if (sta) | ||
| 649 | rate_fixup_ratelist(vif, sband, info, dest, max_rates); | ||
| 650 | } | ||
| 651 | EXPORT_SYMBOL(ieee80211_get_tx_rates); | ||
| 652 | |||
| 429 | void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, | 653 | void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, |
| 430 | struct sta_info *sta, | 654 | struct sta_info *sta, |
| 431 | struct ieee80211_tx_rate_control *txrc) | 655 | struct ieee80211_tx_rate_control *txrc) |
| @@ -435,8 +659,6 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, | |||
| 435 | struct ieee80211_sta *ista = NULL; | 659 | struct ieee80211_sta *ista = NULL; |
| 436 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); | 660 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); |
| 437 | int i; | 661 | int i; |
| 438 | u32 mask; | ||
| 439 | u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]; | ||
| 440 | 662 | ||
| 441 | if (sta && test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) { | 663 | if (sta && test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) { |
| 442 | ista = &sta->sta; | 664 | ista = &sta->sta; |
| @@ -454,37 +676,27 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, | |||
| 454 | 676 | ||
| 455 | ref->ops->get_rate(ref->priv, ista, priv_sta, txrc); | 677 | ref->ops->get_rate(ref->priv, ista, priv_sta, txrc); |
| 456 | 678 | ||
| 457 | /* | 679 | if (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_RC_TABLE) |
| 458 | * Try to enforce the rateidx mask the user wanted. skip this if the | 680 | return; |
| 459 | * default mask (allow all rates) is used to save some processing for | 681 | |
| 460 | * the common case. | 682 | ieee80211_get_tx_rates(&sdata->vif, ista, txrc->skb, |
| 461 | */ | 683 | info->control.rates, |
| 462 | mask = sdata->rc_rateidx_mask[info->band]; | 684 | ARRAY_SIZE(info->control.rates)); |
| 463 | memcpy(mcs_mask, sdata->rc_rateidx_mcs_mask[info->band], | 685 | } |
| 464 | sizeof(mcs_mask)); | ||
| 465 | if (mask != (1 << txrc->sband->n_bitrates) - 1) { | ||
| 466 | if (sta) { | ||
| 467 | /* Filter out rates that the STA does not support */ | ||
| 468 | mask &= sta->sta.supp_rates[info->band]; | ||
| 469 | for (i = 0; i < sizeof(mcs_mask); i++) | ||
| 470 | mcs_mask[i] &= sta->sta.ht_cap.mcs.rx_mask[i]; | ||
| 471 | } | ||
| 472 | /* | ||
| 473 | * Make sure the rate index selected for each TX rate is | ||
| 474 | * included in the configured mask and change the rate indexes | ||
| 475 | * if needed. | ||
| 476 | */ | ||
| 477 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | ||
| 478 | /* Skip invalid rates */ | ||
| 479 | if (info->control.rates[i].idx < 0) | ||
| 480 | break; | ||
| 481 | rate_idx_match_mask(&info->control.rates[i], txrc, | ||
| 482 | mask, mcs_mask); | ||
| 483 | } | ||
| 484 | } | ||
| 485 | 686 | ||
| 486 | BUG_ON(info->control.rates[0].idx < 0); | 687 | int rate_control_set_rates(struct ieee80211_hw *hw, |
| 688 | struct ieee80211_sta *pubsta, | ||
| 689 | struct ieee80211_sta_rates *rates) | ||
| 690 | { | ||
| 691 | struct ieee80211_sta_rates *old = rcu_dereference(pubsta->rates); | ||
| 692 | |||
| 693 | rcu_assign_pointer(pubsta->rates, rates); | ||
| 694 | if (old) | ||
| 695 | kfree_rcu(old, rcu_head); | ||
| 696 | |||
| 697 | return 0; | ||
| 487 | } | 698 | } |
| 699 | EXPORT_SYMBOL(rate_control_set_rates); | ||
| 488 | 700 | ||
| 489 | int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, | 701 | int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, |
| 490 | const char *name) | 702 | const char *name) |
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 1c36c9b4fa4a..ac7ef5414bde 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
| @@ -84,6 +84,50 @@ minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list) | |||
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | static void | 86 | static void |
| 87 | minstrel_set_rate(struct minstrel_sta_info *mi, struct ieee80211_sta_rates *ratetbl, | ||
| 88 | int offset, int idx) | ||
| 89 | { | ||
| 90 | struct minstrel_rate *r = &mi->r[idx]; | ||
| 91 | |||
| 92 | ratetbl->rate[offset].idx = r->rix; | ||
| 93 | ratetbl->rate[offset].count = r->adjusted_retry_count; | ||
| 94 | ratetbl->rate[offset].count_cts = r->retry_count_cts; | ||
| 95 | ratetbl->rate[offset].count_rts = r->retry_count_rtscts; | ||
| 96 | } | ||
| 97 | |||
| 98 | static void | ||
| 99 | minstrel_update_rates(struct minstrel_priv *mp, struct minstrel_sta_info *mi) | ||
| 100 | { | ||
| 101 | struct ieee80211_sta_rates *ratetbl; | ||
| 102 | int i = 0; | ||
| 103 | |||
| 104 | ratetbl = kzalloc(sizeof(*ratetbl), GFP_ATOMIC); | ||
| 105 | if (!ratetbl) | ||
| 106 | return; | ||
| 107 | |||
| 108 | /* Start with max_tp_rate */ | ||
| 109 | minstrel_set_rate(mi, ratetbl, i++, mi->max_tp_rate[0]); | ||
| 110 | |||
| 111 | if (mp->hw->max_rates >= 3) { | ||
| 112 | /* At least 3 tx rates supported, use max_tp_rate2 next */ | ||
| 113 | minstrel_set_rate(mi, ratetbl, i++, mi->max_tp_rate[1]); | ||
| 114 | } | ||
| 115 | |||
| 116 | if (mp->hw->max_rates >= 2) { | ||
| 117 | /* At least 2 tx rates supported, use max_prob_rate next */ | ||
| 118 | minstrel_set_rate(mi, ratetbl, i++, mi->max_prob_rate); | ||
| 119 | } | ||
| 120 | |||
| 121 | /* Use lowest rate last */ | ||
| 122 | ratetbl->rate[i].idx = mi->lowest_rix; | ||
| 123 | ratetbl->rate[i].count = mp->max_retry; | ||
| 124 | ratetbl->rate[i].count_cts = mp->max_retry; | ||
| 125 | ratetbl->rate[i].count_rts = mp->max_retry; | ||
| 126 | |||
| 127 | rate_control_set_rates(mp->hw, mi->sta, ratetbl); | ||
| 128 | } | ||
| 129 | |||
| 130 | static void | ||
| 87 | minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) | 131 | minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) |
| 88 | { | 132 | { |
| 89 | u8 tmp_tp_rate[MAX_THR_RATES]; | 133 | u8 tmp_tp_rate[MAX_THR_RATES]; |
| @@ -161,6 +205,8 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) | |||
| 161 | 205 | ||
| 162 | /* Reset update timer */ | 206 | /* Reset update timer */ |
| 163 | mi->stats_update = jiffies; | 207 | mi->stats_update = jiffies; |
| 208 | |||
| 209 | minstrel_update_rates(mp, mi); | ||
| 164 | } | 210 | } |
| 165 | 211 | ||
| 166 | static void | 212 | static void |
| @@ -209,9 +255,9 @@ minstrel_get_retry_count(struct minstrel_rate *mr, | |||
| 209 | { | 255 | { |
| 210 | unsigned int retry = mr->adjusted_retry_count; | 256 | unsigned int retry = mr->adjusted_retry_count; |
| 211 | 257 | ||
| 212 | if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) | 258 | if (info->control.use_rts) |
| 213 | retry = max(2U, min(mr->retry_count_rtscts, retry)); | 259 | retry = max(2U, min(mr->retry_count_rtscts, retry)); |
| 214 | else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) | 260 | else if (info->control.use_cts_prot) |
| 215 | retry = max(2U, min(mr->retry_count_cts, retry)); | 261 | retry = max(2U, min(mr->retry_count_cts, retry)); |
| 216 | return retry; | 262 | return retry; |
| 217 | } | 263 | } |
| @@ -240,13 +286,12 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, | |||
| 240 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 286 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 241 | struct minstrel_sta_info *mi = priv_sta; | 287 | struct minstrel_sta_info *mi = priv_sta; |
| 242 | struct minstrel_priv *mp = priv; | 288 | struct minstrel_priv *mp = priv; |
| 243 | struct ieee80211_tx_rate *ar = info->control.rates; | 289 | struct ieee80211_tx_rate *rate = &info->control.rates[0]; |
| 244 | unsigned int ndx, sample_ndx = 0; | 290 | struct minstrel_rate *msr, *mr; |
| 291 | unsigned int ndx; | ||
| 245 | bool mrr_capable; | 292 | bool mrr_capable; |
| 246 | bool indirect_rate_sampling = false; | 293 | bool prev_sample = mi->prev_sample; |
| 247 | bool rate_sampling = false; | 294 | int delta; |
| 248 | int i, delta; | ||
| 249 | int mrr_ndx[3]; | ||
| 250 | int sampling_ratio; | 295 | int sampling_ratio; |
| 251 | 296 | ||
| 252 | /* management/no-ack frames do not use rate control */ | 297 | /* management/no-ack frames do not use rate control */ |
| @@ -262,107 +307,75 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, | |||
| 262 | else | 307 | else |
| 263 | sampling_ratio = mp->lookaround_rate; | 308 | sampling_ratio = mp->lookaround_rate; |
| 264 | 309 | ||
| 265 | /* init rateindex [ndx] with max throughput rate */ | ||
| 266 | ndx = mi->max_tp_rate[0]; | ||
| 267 | |||
| 268 | /* increase sum packet counter */ | 310 | /* increase sum packet counter */ |
| 269 | mi->packet_count++; | 311 | mi->packet_count++; |
| 270 | 312 | ||
| 271 | delta = (mi->packet_count * sampling_ratio / 100) - | 313 | delta = (mi->packet_count * sampling_ratio / 100) - |
| 272 | (mi->sample_count + mi->sample_deferred / 2); | 314 | (mi->sample_count + mi->sample_deferred / 2); |
| 273 | 315 | ||
| 274 | /* delta > 0: sampling required */ | 316 | /* delta < 0: no sampling required */ |
| 275 | if ((delta > 0) && (mrr_capable || !mi->prev_sample)) { | 317 | mi->prev_sample = false; |
| 276 | struct minstrel_rate *msr; | 318 | if (delta < 0 || (!mrr_capable && prev_sample)) |
| 277 | if (mi->packet_count >= 10000) { | 319 | return; |
| 278 | mi->sample_deferred = 0; | ||
| 279 | mi->sample_count = 0; | ||
| 280 | mi->packet_count = 0; | ||
| 281 | } else if (delta > mi->n_rates * 2) { | ||
| 282 | /* With multi-rate retry, not every planned sample | ||
| 283 | * attempt actually gets used, due to the way the retry | ||
| 284 | * chain is set up - [max_tp,sample,prob,lowest] for | ||
| 285 | * sample_rate < max_tp. | ||
| 286 | * | ||
| 287 | * If there's too much sampling backlog and the link | ||
| 288 | * starts getting worse, minstrel would start bursting | ||
| 289 | * out lots of sampling frames, which would result | ||
| 290 | * in a large throughput loss. */ | ||
| 291 | mi->sample_count += (delta - mi->n_rates * 2); | ||
| 292 | } | ||
| 293 | 320 | ||
| 294 | /* get next random rate sample */ | 321 | if (mi->packet_count >= 10000) { |
| 295 | sample_ndx = minstrel_get_next_sample(mi); | 322 | mi->sample_deferred = 0; |
| 296 | msr = &mi->r[sample_ndx]; | 323 | mi->sample_count = 0; |
| 297 | rate_sampling = true; | 324 | mi->packet_count = 0; |
| 298 | 325 | } else if (delta > mi->n_rates * 2) { | |
| 299 | /* Decide if direct ( 1st mrr stage) or indirect (2nd mrr stage) | 326 | /* With multi-rate retry, not every planned sample |
| 300 | * rate sampling method should be used. | 327 | * attempt actually gets used, due to the way the retry |
| 301 | * Respect such rates that are not sampled for 20 interations. | 328 | * chain is set up - [max_tp,sample,prob,lowest] for |
| 302 | */ | 329 | * sample_rate < max_tp. |
| 303 | if (mrr_capable && | 330 | * |
| 304 | msr->perfect_tx_time > mi->r[ndx].perfect_tx_time && | 331 | * If there's too much sampling backlog and the link |
| 305 | msr->sample_skipped < 20) | 332 | * starts getting worse, minstrel would start bursting |
| 306 | indirect_rate_sampling = true; | 333 | * out lots of sampling frames, which would result |
| 307 | 334 | * in a large throughput loss. */ | |
| 308 | if (!indirect_rate_sampling) { | 335 | mi->sample_count += (delta - mi->n_rates * 2); |
| 309 | if (msr->sample_limit != 0) { | 336 | } |
| 310 | ndx = sample_ndx; | 337 | |
| 311 | mi->sample_count++; | 338 | /* get next random rate sample */ |
| 312 | if (msr->sample_limit > 0) | 339 | ndx = minstrel_get_next_sample(mi); |
| 313 | msr->sample_limit--; | 340 | msr = &mi->r[ndx]; |
| 314 | } else | 341 | mr = &mi->r[mi->max_tp_rate[0]]; |
| 315 | rate_sampling = false; | 342 | |
| 316 | } else { | 343 | /* Decide if direct ( 1st mrr stage) or indirect (2nd mrr stage) |
| 317 | /* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark | 344 | * rate sampling method should be used. |
| 318 | * packets that have the sampling rate deferred to the | 345 | * Respect such rates that are not sampled for 20 interations. |
| 319 | * second MRR stage. Increase the sample counter only | 346 | */ |
| 320 | * if the deferred sample rate was actually used. | 347 | if (mrr_capable && |
| 321 | * Use the sample_deferred counter to make sure that | 348 | msr->perfect_tx_time > mr->perfect_tx_time && |
| 322 | * the sampling is not done in large bursts */ | 349 | msr->sample_skipped < 20) { |
| 323 | info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; | 350 | /* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark |
| 324 | mi->sample_deferred++; | 351 | * packets that have the sampling rate deferred to the |
| 325 | } | 352 | * second MRR stage. Increase the sample counter only |
| 353 | * if the deferred sample rate was actually used. | ||
| 354 | * Use the sample_deferred counter to make sure that | ||
| 355 | * the sampling is not done in large bursts */ | ||
| 356 | info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; | ||
| 357 | rate++; | ||
| 358 | mi->sample_deferred++; | ||
| 359 | } else { | ||
| 360 | if (!msr->sample_limit != 0) | ||
| 361 | return; | ||
| 362 | |||
| 363 | mi->sample_count++; | ||
| 364 | if (msr->sample_limit > 0) | ||
| 365 | msr->sample_limit--; | ||
| 326 | } | 366 | } |
| 327 | mi->prev_sample = rate_sampling; | ||
| 328 | 367 | ||
| 329 | /* If we're not using MRR and the sampling rate already | 368 | /* If we're not using MRR and the sampling rate already |
| 330 | * has a probability of >95%, we shouldn't be attempting | 369 | * has a probability of >95%, we shouldn't be attempting |
| 331 | * to use it, as this only wastes precious airtime */ | 370 | * to use it, as this only wastes precious airtime */ |
| 332 | if (!mrr_capable && rate_sampling && | 371 | if (!mrr_capable && |
| 333 | (mi->r[ndx].probability > MINSTREL_FRAC(95, 100))) | 372 | (mi->r[ndx].probability > MINSTREL_FRAC(95, 100))) |
| 334 | ndx = mi->max_tp_rate[0]; | ||
| 335 | |||
| 336 | /* mrr setup for 1st stage */ | ||
| 337 | ar[0].idx = mi->r[ndx].rix; | ||
| 338 | ar[0].count = minstrel_get_retry_count(&mi->r[ndx], info); | ||
| 339 | |||
| 340 | /* non mrr setup for 2nd stage */ | ||
| 341 | if (!mrr_capable) { | ||
| 342 | if (!rate_sampling) | ||
| 343 | ar[0].count = mp->max_retry; | ||
| 344 | ar[1].idx = mi->lowest_rix; | ||
| 345 | ar[1].count = mp->max_retry; | ||
| 346 | return; | 373 | return; |
| 347 | } | ||
| 348 | 374 | ||
| 349 | /* mrr setup for 2nd stage */ | 375 | mi->prev_sample = true; |
| 350 | if (rate_sampling) { | ||
| 351 | if (indirect_rate_sampling) | ||
| 352 | mrr_ndx[0] = sample_ndx; | ||
| 353 | else | ||
| 354 | mrr_ndx[0] = mi->max_tp_rate[0]; | ||
| 355 | } else { | ||
| 356 | mrr_ndx[0] = mi->max_tp_rate[1]; | ||
| 357 | } | ||
| 358 | 376 | ||
| 359 | /* mrr setup for 3rd & 4th stage */ | 377 | rate->idx = mi->r[ndx].rix; |
| 360 | mrr_ndx[1] = mi->max_prob_rate; | 378 | rate->count = minstrel_get_retry_count(&mi->r[ndx], info); |
| 361 | mrr_ndx[2] = 0; | ||
| 362 | for (i = 1; i < 4; i++) { | ||
| 363 | ar[i].idx = mi->r[mrr_ndx[i - 1]].rix; | ||
| 364 | ar[i].count = mi->r[mrr_ndx[i - 1]].adjusted_retry_count; | ||
| 365 | } | ||
| 366 | } | 379 | } |
| 367 | 380 | ||
| 368 | 381 | ||
| @@ -412,12 +425,16 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, | |||
| 412 | unsigned int i, n = 0; | 425 | unsigned int i, n = 0; |
| 413 | unsigned int t_slot = 9; /* FIXME: get real slot time */ | 426 | unsigned int t_slot = 9; /* FIXME: get real slot time */ |
| 414 | 427 | ||
| 428 | mi->sta = sta; | ||
| 415 | mi->lowest_rix = rate_lowest_index(sband, sta); | 429 | mi->lowest_rix = rate_lowest_index(sband, sta); |
| 416 | ctl_rate = &sband->bitrates[mi->lowest_rix]; | 430 | ctl_rate = &sband->bitrates[mi->lowest_rix]; |
| 417 | mi->sp_ack_dur = ieee80211_frame_duration(sband->band, 10, | 431 | mi->sp_ack_dur = ieee80211_frame_duration(sband->band, 10, |
| 418 | ctl_rate->bitrate, | 432 | ctl_rate->bitrate, |
| 419 | !!(ctl_rate->flags & IEEE80211_RATE_ERP_G), 1); | 433 | !!(ctl_rate->flags & IEEE80211_RATE_ERP_G), 1); |
| 420 | 434 | ||
| 435 | memset(mi->max_tp_rate, 0, sizeof(mi->max_tp_rate)); | ||
| 436 | mi->max_prob_rate = 0; | ||
| 437 | |||
| 421 | for (i = 0; i < sband->n_bitrates; i++) { | 438 | for (i = 0; i < sband->n_bitrates; i++) { |
| 422 | struct minstrel_rate *mr = &mi->r[n]; | 439 | struct minstrel_rate *mr = &mi->r[n]; |
| 423 | unsigned int tx_time = 0, tx_time_cts = 0, tx_time_rtscts = 0; | 440 | unsigned int tx_time = 0, tx_time_cts = 0, tx_time_rtscts = 0; |
| @@ -460,6 +477,8 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, | |||
| 460 | } while ((tx_time < mp->segment_size) && | 477 | } while ((tx_time < mp->segment_size) && |
| 461 | (++mr->retry_count < mp->max_retry)); | 478 | (++mr->retry_count < mp->max_retry)); |
| 462 | mr->adjusted_retry_count = mr->retry_count; | 479 | mr->adjusted_retry_count = mr->retry_count; |
| 480 | if (!(sband->bitrates[i].flags & IEEE80211_RATE_ERP_G)) | ||
| 481 | mr->retry_count_cts = mr->retry_count; | ||
| 463 | } | 482 | } |
| 464 | 483 | ||
| 465 | for (i = n; i < sband->n_bitrates; i++) { | 484 | for (i = n; i < sband->n_bitrates; i++) { |
| @@ -471,6 +490,7 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, | |||
| 471 | mi->stats_update = jiffies; | 490 | mi->stats_update = jiffies; |
| 472 | 491 | ||
| 473 | init_sample_table(mi); | 492 | init_sample_table(mi); |
| 493 | minstrel_update_rates(mp, mi); | ||
| 474 | } | 494 | } |
| 475 | 495 | ||
| 476 | static void * | 496 | static void * |
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h index 85ebf42cb46d..f4301f4b2e41 100644 --- a/net/mac80211/rc80211_minstrel.h +++ b/net/mac80211/rc80211_minstrel.h | |||
| @@ -9,7 +9,8 @@ | |||
| 9 | #ifndef __RC_MINSTREL_H | 9 | #ifndef __RC_MINSTREL_H |
| 10 | #define __RC_MINSTREL_H | 10 | #define __RC_MINSTREL_H |
| 11 | 11 | ||
| 12 | #define EWMA_LEVEL 75 /* ewma weighting factor [%] */ | 12 | #define EWMA_LEVEL 96 /* ewma weighting factor [/EWMA_DIV] */ |
| 13 | #define EWMA_DIV 128 | ||
| 13 | #define SAMPLE_COLUMNS 10 /* number of columns in sample table */ | 14 | #define SAMPLE_COLUMNS 10 /* number of columns in sample table */ |
| 14 | 15 | ||
| 15 | 16 | ||
| @@ -27,7 +28,7 @@ | |||
| 27 | static inline int | 28 | static inline int |
| 28 | minstrel_ewma(int old, int new, int weight) | 29 | minstrel_ewma(int old, int new, int weight) |
| 29 | { | 30 | { |
| 30 | return (new * (100 - weight) + old * weight) / 100; | 31 | return (new * (EWMA_DIV - weight) + old * weight) / EWMA_DIV; |
| 31 | } | 32 | } |
| 32 | 33 | ||
| 33 | 34 | ||
| @@ -62,6 +63,8 @@ struct minstrel_rate { | |||
| 62 | }; | 63 | }; |
| 63 | 64 | ||
| 64 | struct minstrel_sta_info { | 65 | struct minstrel_sta_info { |
| 66 | struct ieee80211_sta *sta; | ||
| 67 | |||
| 65 | unsigned long stats_update; | 68 | unsigned long stats_update; |
| 66 | unsigned int sp_ack_dur; | 69 | unsigned int sp_ack_dur; |
| 67 | unsigned int rate_avg; | 70 | unsigned int rate_avg; |
diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c index d1048348d399..fd0b9ca1570e 100644 --- a/net/mac80211/rc80211_minstrel_debugfs.c +++ b/net/mac80211/rc80211_minstrel_debugfs.c | |||
| @@ -68,7 +68,7 @@ minstrel_stats_open(struct inode *inode, struct file *file) | |||
| 68 | 68 | ||
| 69 | file->private_data = ms; | 69 | file->private_data = ms; |
| 70 | p = ms->buf; | 70 | p = ms->buf; |
| 71 | p += sprintf(p, "rate throughput ewma prob this prob " | 71 | p += sprintf(p, "rate throughput ewma prob this prob " |
| 72 | "this succ/attempt success attempts\n"); | 72 | "this succ/attempt success attempts\n"); |
| 73 | for (i = 0; i < mi->n_rates; i++) { | 73 | for (i = 0; i < mi->n_rates; i++) { |
| 74 | struct minstrel_rate *mr = &mi->r[i]; | 74 | struct minstrel_rate *mr = &mi->r[i]; |
| @@ -86,7 +86,7 @@ minstrel_stats_open(struct inode *inode, struct file *file) | |||
| 86 | eprob = MINSTREL_TRUNC(mr->probability * 1000); | 86 | eprob = MINSTREL_TRUNC(mr->probability * 1000); |
| 87 | 87 | ||
| 88 | p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u " | 88 | p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u " |
| 89 | "%3u(%3u) %8llu %8llu\n", | 89 | " %3u(%3u) %8llu %8llu\n", |
| 90 | tp / 10, tp % 10, | 90 | tp / 10, tp % 10, |
| 91 | eprob / 10, eprob % 10, | 91 | eprob / 10, eprob % 10, |
| 92 | prob / 10, prob % 10, | 92 | prob / 10, prob % 10, |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index d2b264d1311d..5b2d3012b983 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
| @@ -126,6 +126,9 @@ const struct mcs_group minstrel_mcs_groups[] = { | |||
| 126 | 126 | ||
| 127 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES]; | 127 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES]; |
| 128 | 128 | ||
| 129 | static void | ||
| 130 | minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi); | ||
| 131 | |||
| 129 | /* | 132 | /* |
| 130 | * Look up an MCS group index based on mac80211 rate information | 133 | * Look up an MCS group index based on mac80211 rate information |
| 131 | */ | 134 | */ |
| @@ -244,6 +247,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
| 244 | struct minstrel_rate_stats *mr; | 247 | struct minstrel_rate_stats *mr; |
| 245 | int cur_prob, cur_prob_tp, cur_tp, cur_tp2; | 248 | int cur_prob, cur_prob_tp, cur_tp, cur_tp2; |
| 246 | int group, i, index; | 249 | int group, i, index; |
| 250 | bool mi_rates_valid = false; | ||
| 247 | 251 | ||
| 248 | if (mi->ampdu_packets > 0) { | 252 | if (mi->ampdu_packets > 0) { |
| 249 | mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, | 253 | mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, |
| @@ -254,11 +258,10 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
| 254 | 258 | ||
| 255 | mi->sample_slow = 0; | 259 | mi->sample_slow = 0; |
| 256 | mi->sample_count = 0; | 260 | mi->sample_count = 0; |
| 257 | mi->max_tp_rate = 0; | ||
| 258 | mi->max_tp_rate2 = 0; | ||
| 259 | mi->max_prob_rate = 0; | ||
| 260 | 261 | ||
| 261 | for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { | 262 | for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { |
| 263 | bool mg_rates_valid = false; | ||
| 264 | |||
| 262 | cur_prob = 0; | 265 | cur_prob = 0; |
| 263 | cur_prob_tp = 0; | 266 | cur_prob_tp = 0; |
| 264 | cur_tp = 0; | 267 | cur_tp = 0; |
| @@ -268,15 +271,24 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
| 268 | if (!mg->supported) | 271 | if (!mg->supported) |
| 269 | continue; | 272 | continue; |
| 270 | 273 | ||
| 271 | mg->max_tp_rate = 0; | ||
| 272 | mg->max_tp_rate2 = 0; | ||
| 273 | mg->max_prob_rate = 0; | ||
| 274 | mi->sample_count++; | 274 | mi->sample_count++; |
| 275 | 275 | ||
| 276 | for (i = 0; i < MCS_GROUP_RATES; i++) { | 276 | for (i = 0; i < MCS_GROUP_RATES; i++) { |
| 277 | if (!(mg->supported & BIT(i))) | 277 | if (!(mg->supported & BIT(i))) |
| 278 | continue; | 278 | continue; |
| 279 | 279 | ||
| 280 | /* initialize rates selections starting indexes */ | ||
| 281 | if (!mg_rates_valid) { | ||
| 282 | mg->max_tp_rate = mg->max_tp_rate2 = | ||
| 283 | mg->max_prob_rate = i; | ||
| 284 | if (!mi_rates_valid) { | ||
| 285 | mi->max_tp_rate = mi->max_tp_rate2 = | ||
| 286 | mi->max_prob_rate = i; | ||
| 287 | mi_rates_valid = true; | ||
| 288 | } | ||
| 289 | mg_rates_valid = true; | ||
| 290 | } | ||
| 291 | |||
| 280 | mr = &mg->rates[i]; | 292 | mr = &mg->rates[i]; |
| 281 | mr->retry_updated = false; | 293 | mr->retry_updated = false; |
| 282 | index = MCS_GROUP_RATES * group + i; | 294 | index = MCS_GROUP_RATES * group + i; |
| @@ -456,7 +468,7 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
| 456 | struct ieee80211_tx_rate *ar = info->status.rates; | 468 | struct ieee80211_tx_rate *ar = info->status.rates; |
| 457 | struct minstrel_rate_stats *rate, *rate2; | 469 | struct minstrel_rate_stats *rate, *rate2; |
| 458 | struct minstrel_priv *mp = priv; | 470 | struct minstrel_priv *mp = priv; |
| 459 | bool last; | 471 | bool last, update = false; |
| 460 | int i; | 472 | int i; |
| 461 | 473 | ||
| 462 | if (!msp->is_ht) | 474 | if (!msp->is_ht) |
| @@ -505,21 +517,29 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
| 505 | rate = minstrel_get_ratestats(mi, mi->max_tp_rate); | 517 | rate = minstrel_get_ratestats(mi, mi->max_tp_rate); |
| 506 | if (rate->attempts > 30 && | 518 | if (rate->attempts > 30 && |
| 507 | MINSTREL_FRAC(rate->success, rate->attempts) < | 519 | MINSTREL_FRAC(rate->success, rate->attempts) < |
| 508 | MINSTREL_FRAC(20, 100)) | 520 | MINSTREL_FRAC(20, 100)) { |
| 509 | minstrel_downgrade_rate(mi, &mi->max_tp_rate, true); | 521 | minstrel_downgrade_rate(mi, &mi->max_tp_rate, true); |
| 522 | update = true; | ||
| 523 | } | ||
| 510 | 524 | ||
| 511 | rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate2); | 525 | rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate2); |
| 512 | if (rate2->attempts > 30 && | 526 | if (rate2->attempts > 30 && |
| 513 | MINSTREL_FRAC(rate2->success, rate2->attempts) < | 527 | MINSTREL_FRAC(rate2->success, rate2->attempts) < |
| 514 | MINSTREL_FRAC(20, 100)) | 528 | MINSTREL_FRAC(20, 100)) { |
| 515 | minstrel_downgrade_rate(mi, &mi->max_tp_rate2, false); | 529 | minstrel_downgrade_rate(mi, &mi->max_tp_rate2, false); |
| 530 | update = true; | ||
| 531 | } | ||
| 516 | 532 | ||
| 517 | if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) { | 533 | if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) { |
| 534 | update = true; | ||
| 518 | minstrel_ht_update_stats(mp, mi); | 535 | minstrel_ht_update_stats(mp, mi); |
| 519 | if (!(info->flags & IEEE80211_TX_CTL_AMPDU) && | 536 | if (!(info->flags & IEEE80211_TX_CTL_AMPDU) && |
| 520 | mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP) | 537 | mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP) |
| 521 | minstrel_aggr_check(sta, skb); | 538 | minstrel_aggr_check(sta, skb); |
| 522 | } | 539 | } |
| 540 | |||
| 541 | if (update) | ||
| 542 | minstrel_ht_update_rates(mp, mi); | ||
| 523 | } | 543 | } |
| 524 | 544 | ||
| 525 | static void | 545 | static void |
| @@ -583,36 +603,71 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
| 583 | 603 | ||
| 584 | static void | 604 | static void |
| 585 | minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | 605 | minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, |
| 586 | struct ieee80211_tx_rate *rate, int index, | 606 | struct ieee80211_sta_rates *ratetbl, int offset, int index) |
| 587 | bool sample, bool rtscts) | ||
| 588 | { | 607 | { |
| 589 | const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; | 608 | const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; |
| 590 | struct minstrel_rate_stats *mr; | 609 | struct minstrel_rate_stats *mr; |
| 610 | u8 idx; | ||
| 611 | u16 flags; | ||
| 591 | 612 | ||
| 592 | mr = minstrel_get_ratestats(mi, index); | 613 | mr = minstrel_get_ratestats(mi, index); |
| 593 | if (!mr->retry_updated) | 614 | if (!mr->retry_updated) |
| 594 | minstrel_calc_retransmit(mp, mi, index); | 615 | minstrel_calc_retransmit(mp, mi, index); |
| 595 | 616 | ||
| 596 | if (sample) | 617 | if (mr->probability < MINSTREL_FRAC(20, 100) || !mr->retry_count) { |
| 597 | rate->count = 1; | 618 | ratetbl->rate[offset].count = 2; |
| 598 | else if (mr->probability < MINSTREL_FRAC(20, 100)) | 619 | ratetbl->rate[offset].count_rts = 2; |
| 599 | rate->count = 2; | 620 | ratetbl->rate[offset].count_cts = 2; |
| 600 | else if (rtscts) | 621 | } else { |
| 601 | rate->count = mr->retry_count_rtscts; | 622 | ratetbl->rate[offset].count = mr->retry_count; |
| 602 | else | 623 | ratetbl->rate[offset].count_cts = mr->retry_count; |
| 603 | rate->count = mr->retry_count; | 624 | ratetbl->rate[offset].count_rts = mr->retry_count_rtscts; |
| 604 | 625 | } | |
| 605 | rate->flags = 0; | ||
| 606 | if (rtscts) | ||
| 607 | rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; | ||
| 608 | 626 | ||
| 609 | if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) { | 627 | if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) { |
| 610 | rate->idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; | 628 | idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; |
| 629 | flags = 0; | ||
| 630 | } else { | ||
| 631 | idx = index % MCS_GROUP_RATES + | ||
| 632 | (group->streams - 1) * MCS_GROUP_RATES; | ||
| 633 | flags = IEEE80211_TX_RC_MCS | group->flags; | ||
| 634 | } | ||
| 635 | |||
| 636 | if (offset > 0) { | ||
| 637 | ratetbl->rate[offset].count = ratetbl->rate[offset].count_rts; | ||
| 638 | flags |= IEEE80211_TX_RC_USE_RTS_CTS; | ||
| 639 | } | ||
| 640 | |||
| 641 | ratetbl->rate[offset].idx = idx; | ||
| 642 | ratetbl->rate[offset].flags = flags; | ||
| 643 | } | ||
| 644 | |||
| 645 | static void | ||
| 646 | minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | ||
| 647 | { | ||
| 648 | struct ieee80211_sta_rates *rates; | ||
| 649 | int i = 0; | ||
| 650 | |||
| 651 | rates = kzalloc(sizeof(*rates), GFP_ATOMIC); | ||
| 652 | if (!rates) | ||
| 611 | return; | 653 | return; |
| 654 | |||
| 655 | /* Start with max_tp_rate */ | ||
| 656 | minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate); | ||
| 657 | |||
| 658 | if (mp->hw->max_rates >= 3) { | ||
| 659 | /* At least 3 tx rates supported, use max_tp_rate2 next */ | ||
| 660 | minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate2); | ||
| 661 | } | ||
| 662 | |||
| 663 | if (mp->hw->max_rates >= 2) { | ||
| 664 | /* | ||
| 665 | * At least 2 tx rates supported, use max_prob_rate next */ | ||
| 666 | minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_prob_rate); | ||
| 612 | } | 667 | } |
| 613 | 668 | ||
| 614 | rate->flags |= IEEE80211_TX_RC_MCS | group->flags; | 669 | rates->rate[i].idx = -1; |
| 615 | rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES; | 670 | rate_control_set_rates(mp->hw, mi->sta, rates); |
| 616 | } | 671 | } |
| 617 | 672 | ||
| 618 | static inline int | 673 | static inline int |
| @@ -702,13 +757,13 @@ static void | |||
| 702 | minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | 757 | minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, |
| 703 | struct ieee80211_tx_rate_control *txrc) | 758 | struct ieee80211_tx_rate_control *txrc) |
| 704 | { | 759 | { |
| 760 | const struct mcs_group *sample_group; | ||
| 705 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); | 761 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); |
| 706 | struct ieee80211_tx_rate *ar = info->status.rates; | 762 | struct ieee80211_tx_rate *rate = &info->status.rates[0]; |
| 707 | struct minstrel_ht_sta_priv *msp = priv_sta; | 763 | struct minstrel_ht_sta_priv *msp = priv_sta; |
| 708 | struct minstrel_ht_sta *mi = &msp->ht; | 764 | struct minstrel_ht_sta *mi = &msp->ht; |
| 709 | struct minstrel_priv *mp = priv; | 765 | struct minstrel_priv *mp = priv; |
| 710 | int sample_idx; | 766 | int sample_idx; |
| 711 | bool sample = false; | ||
| 712 | 767 | ||
| 713 | if (rate_control_send_low(sta, priv_sta, txrc)) | 768 | if (rate_control_send_low(sta, priv_sta, txrc)) |
| 714 | return; | 769 | return; |
| @@ -736,51 +791,6 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
| 736 | } | 791 | } |
| 737 | #endif | 792 | #endif |
| 738 | 793 | ||
| 739 | if (sample_idx >= 0) { | ||
| 740 | sample = true; | ||
| 741 | minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx, | ||
| 742 | true, false); | ||
| 743 | info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; | ||
| 744 | } else { | ||
| 745 | minstrel_ht_set_rate(mp, mi, &ar[0], mi->max_tp_rate, | ||
| 746 | false, false); | ||
| 747 | } | ||
| 748 | |||
| 749 | if (mp->hw->max_rates >= 3) { | ||
| 750 | /* | ||
| 751 | * At least 3 tx rates supported, use | ||
| 752 | * sample_rate -> max_tp_rate -> max_prob_rate for sampling and | ||
| 753 | * max_tp_rate -> max_tp_rate2 -> max_prob_rate by default. | ||
| 754 | */ | ||
| 755 | if (sample_idx >= 0) | ||
| 756 | minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate, | ||
| 757 | false, false); | ||
| 758 | else | ||
| 759 | minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate2, | ||
| 760 | false, true); | ||
| 761 | |||
| 762 | minstrel_ht_set_rate(mp, mi, &ar[2], mi->max_prob_rate, | ||
| 763 | false, !sample); | ||
| 764 | |||
| 765 | ar[3].count = 0; | ||
| 766 | ar[3].idx = -1; | ||
| 767 | } else if (mp->hw->max_rates == 2) { | ||
| 768 | /* | ||
| 769 | * Only 2 tx rates supported, use | ||
| 770 | * sample_rate -> max_prob_rate for sampling and | ||
| 771 | * max_tp_rate -> max_prob_rate by default. | ||
| 772 | */ | ||
| 773 | minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_prob_rate, | ||
| 774 | false, !sample); | ||
| 775 | |||
| 776 | ar[2].count = 0; | ||
| 777 | ar[2].idx = -1; | ||
| 778 | } else { | ||
| 779 | /* Not using MRR, only use the first rate */ | ||
| 780 | ar[1].count = 0; | ||
| 781 | ar[1].idx = -1; | ||
| 782 | } | ||
| 783 | |||
| 784 | mi->total_packets++; | 794 | mi->total_packets++; |
| 785 | 795 | ||
| 786 | /* wraparound */ | 796 | /* wraparound */ |
| @@ -788,6 +798,16 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
| 788 | mi->total_packets = 0; | 798 | mi->total_packets = 0; |
| 789 | mi->sample_packets = 0; | 799 | mi->sample_packets = 0; |
| 790 | } | 800 | } |
| 801 | |||
| 802 | if (sample_idx < 0) | ||
| 803 | return; | ||
| 804 | |||
| 805 | sample_group = &minstrel_mcs_groups[sample_idx / MCS_GROUP_RATES]; | ||
| 806 | info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; | ||
| 807 | rate->idx = sample_idx % MCS_GROUP_RATES + | ||
| 808 | (sample_group->streams - 1) * MCS_GROUP_RATES; | ||
| 809 | rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags; | ||
| 810 | rate->count = 1; | ||
| 791 | } | 811 | } |
| 792 | 812 | ||
| 793 | static void | 813 | static void |
| @@ -837,6 +857,8 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
| 837 | 857 | ||
| 838 | msp->is_ht = true; | 858 | msp->is_ht = true; |
| 839 | memset(mi, 0, sizeof(*mi)); | 859 | memset(mi, 0, sizeof(*mi)); |
| 860 | |||
| 861 | mi->sta = sta; | ||
| 840 | mi->stats_update = jiffies; | 862 | mi->stats_update = jiffies; |
| 841 | 863 | ||
| 842 | ack_dur = ieee80211_frame_duration(sband->band, 10, 60, 1, 1); | 864 | ack_dur = ieee80211_frame_duration(sband->band, 10, 60, 1, 1); |
| @@ -898,6 +920,10 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
| 898 | if (!n_supported) | 920 | if (!n_supported) |
| 899 | goto use_legacy; | 921 | goto use_legacy; |
| 900 | 922 | ||
| 923 | /* create an initial rate table with the lowest supported rates */ | ||
| 924 | minstrel_ht_update_stats(mp, mi); | ||
| 925 | minstrel_ht_update_rates(mp, mi); | ||
| 926 | |||
| 901 | return; | 927 | return; |
| 902 | 928 | ||
| 903 | use_legacy: | 929 | use_legacy: |
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h index 9b16e9de9923..d655586773ac 100644 --- a/net/mac80211/rc80211_minstrel_ht.h +++ b/net/mac80211/rc80211_minstrel_ht.h | |||
| @@ -65,6 +65,8 @@ struct minstrel_mcs_group_data { | |||
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| 67 | struct minstrel_ht_sta { | 67 | struct minstrel_ht_sta { |
| 68 | struct ieee80211_sta *sta; | ||
| 69 | |||
| 68 | /* ampdu length (average, per sampling interval) */ | 70 | /* ampdu length (average, per sampling interval) */ |
| 69 | unsigned int ampdu_len; | 71 | unsigned int ampdu_len; |
| 70 | unsigned int ampdu_packets; | 72 | unsigned int ampdu_packets; |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 2528b5a4d6d4..c8447af76ead 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
| @@ -2085,6 +2085,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
| 2085 | } | 2085 | } |
| 2086 | 2086 | ||
| 2087 | fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; | 2087 | fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; |
| 2088 | fwd_hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_RETRY); | ||
| 2088 | info = IEEE80211_SKB_CB(fwd_skb); | 2089 | info = IEEE80211_SKB_CB(fwd_skb); |
| 2089 | memset(info, 0, sizeof(*info)); | 2090 | memset(info, 0, sizeof(*info)); |
| 2090 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; | 2091 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
| @@ -2423,6 +2424,22 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
| 2423 | } | 2424 | } |
| 2424 | 2425 | ||
| 2425 | break; | 2426 | break; |
| 2427 | case WLAN_CATEGORY_PUBLIC: | ||
| 2428 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) | ||
| 2429 | goto invalid; | ||
| 2430 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
| 2431 | break; | ||
| 2432 | if (!rx->sta) | ||
| 2433 | break; | ||
| 2434 | if (!ether_addr_equal(mgmt->bssid, sdata->u.mgd.bssid)) | ||
| 2435 | break; | ||
| 2436 | if (mgmt->u.action.u.ext_chan_switch.action_code != | ||
| 2437 | WLAN_PUB_ACTION_EXT_CHANSW_ANN) | ||
| 2438 | break; | ||
| 2439 | if (len < offsetof(struct ieee80211_mgmt, | ||
| 2440 | u.action.u.ext_chan_switch.variable)) | ||
| 2441 | goto invalid; | ||
| 2442 | goto queue; | ||
| 2426 | case WLAN_CATEGORY_VHT: | 2443 | case WLAN_CATEGORY_VHT: |
| 2427 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | 2444 | if (sdata->vif.type != NL80211_IFTYPE_STATION && |
| 2428 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT && | 2445 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT && |
| @@ -2506,10 +2523,6 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
| 2506 | ieee80211_process_measurement_req(sdata, mgmt, len); | 2523 | ieee80211_process_measurement_req(sdata, mgmt, len); |
| 2507 | goto handled; | 2524 | goto handled; |
| 2508 | case WLAN_ACTION_SPCT_CHL_SWITCH: | 2525 | case WLAN_ACTION_SPCT_CHL_SWITCH: |
| 2509 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
| 2510 | sizeof(mgmt->u.action.u.chan_switch))) | ||
| 2511 | break; | ||
| 2512 | |||
| 2513 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 2526 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
| 2514 | break; | 2527 | break; |
| 2515 | 2528 | ||
| @@ -3042,7 +3055,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, | |||
| 3042 | !ieee80211_is_probe_resp(hdr->frame_control) && | 3055 | !ieee80211_is_probe_resp(hdr->frame_control) && |
| 3043 | !ieee80211_is_beacon(hdr->frame_control)) | 3056 | !ieee80211_is_beacon(hdr->frame_control)) |
| 3044 | return 0; | 3057 | return 0; |
| 3045 | if (!ether_addr_equal(sdata->vif.addr, hdr->addr1)) | 3058 | if (!ether_addr_equal(sdata->vif.addr, hdr->addr1) && |
| 3059 | !multicast) | ||
| 3046 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; | 3060 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; |
| 3047 | break; | 3061 | break; |
| 3048 | default: | 3062 | default: |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 33fbf1045690..99b103921a4b 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
| @@ -181,7 +181,7 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) | |||
| 181 | if (baselen > skb->len) | 181 | if (baselen > skb->len) |
| 182 | return; | 182 | return; |
| 183 | 183 | ||
| 184 | ieee802_11_parse_elems(elements, skb->len - baselen, &elems); | 184 | ieee802_11_parse_elems(elements, skb->len - baselen, false, &elems); |
| 185 | 185 | ||
| 186 | channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq); | 186 | channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq); |
| 187 | 187 | ||
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/tx.c b/net/mac80211/tx.c index aad0bf5d8812..4a5fbf83cd1e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
| @@ -48,15 +48,15 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, | |||
| 48 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 48 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 49 | 49 | ||
| 50 | /* assume HW handles this */ | 50 | /* assume HW handles this */ |
| 51 | if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) | 51 | if (tx->rate.flags & IEEE80211_TX_RC_MCS) |
| 52 | return 0; | 52 | return 0; |
| 53 | 53 | ||
| 54 | /* uh huh? */ | 54 | /* uh huh? */ |
| 55 | if (WARN_ON_ONCE(info->control.rates[0].idx < 0)) | 55 | if (WARN_ON_ONCE(tx->rate.idx < 0)) |
| 56 | return 0; | 56 | return 0; |
| 57 | 57 | ||
| 58 | sband = local->hw.wiphy->bands[info->band]; | 58 | sband = local->hw.wiphy->bands[info->band]; |
| 59 | txrate = &sband->bitrates[info->control.rates[0].idx]; | 59 | txrate = &sband->bitrates[tx->rate.idx]; |
| 60 | 60 | ||
| 61 | erp = txrate->flags & IEEE80211_RATE_ERP_G; | 61 | erp = txrate->flags & IEEE80211_RATE_ERP_G; |
| 62 | 62 | ||
| @@ -617,11 +617,9 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) | |||
| 617 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | 617 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); |
| 618 | struct ieee80211_hdr *hdr = (void *)tx->skb->data; | 618 | struct ieee80211_hdr *hdr = (void *)tx->skb->data; |
| 619 | struct ieee80211_supported_band *sband; | 619 | struct ieee80211_supported_band *sband; |
| 620 | struct ieee80211_rate *rate; | ||
| 621 | int i; | ||
| 622 | u32 len; | 620 | u32 len; |
| 623 | bool inval = false, rts = false, short_preamble = false; | ||
| 624 | struct ieee80211_tx_rate_control txrc; | 621 | struct ieee80211_tx_rate_control txrc; |
| 622 | struct ieee80211_sta_rates *ratetbl = NULL; | ||
| 625 | bool assoc = false; | 623 | bool assoc = false; |
| 626 | 624 | ||
| 627 | memset(&txrc, 0, sizeof(txrc)); | 625 | memset(&txrc, 0, sizeof(txrc)); |
| @@ -642,18 +640,23 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) | |||
| 642 | txrc.max_rate_idx = -1; | 640 | txrc.max_rate_idx = -1; |
| 643 | else | 641 | else |
| 644 | txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; | 642 | txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; |
| 645 | memcpy(txrc.rate_idx_mcs_mask, | 643 | |
| 646 | tx->sdata->rc_rateidx_mcs_mask[info->band], | 644 | if (tx->sdata->rc_has_mcs_mask[info->band]) |
| 647 | sizeof(txrc.rate_idx_mcs_mask)); | 645 | txrc.rate_idx_mcs_mask = |
| 646 | tx->sdata->rc_rateidx_mcs_mask[info->band]; | ||
| 647 | |||
| 648 | txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP || | 648 | txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP || |
| 649 | tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT || | 649 | tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT || |
| 650 | tx->sdata->vif.type == NL80211_IFTYPE_ADHOC); | 650 | tx->sdata->vif.type == NL80211_IFTYPE_ADHOC); |
| 651 | 651 | ||
| 652 | /* set up RTS protection if desired */ | 652 | /* set up RTS protection if desired */ |
| 653 | if (len > tx->local->hw.wiphy->rts_threshold) { | 653 | if (len > tx->local->hw.wiphy->rts_threshold) { |
| 654 | txrc.rts = rts = true; | 654 | txrc.rts = true; |
| 655 | } | 655 | } |
| 656 | 656 | ||
| 657 | info->control.use_rts = txrc.rts; | ||
| 658 | info->control.use_cts_prot = tx->sdata->vif.bss_conf.use_cts_prot; | ||
| 659 | |||
| 657 | /* | 660 | /* |
| 658 | * Use short preamble if the BSS can handle it, but not for | 661 | * Use short preamble if the BSS can handle it, but not for |
| 659 | * management frames unless we know the receiver can handle | 662 | * management frames unless we know the receiver can handle |
| @@ -663,7 +666,9 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) | |||
| 663 | if (tx->sdata->vif.bss_conf.use_short_preamble && | 666 | if (tx->sdata->vif.bss_conf.use_short_preamble && |
| 664 | (ieee80211_is_data(hdr->frame_control) || | 667 | (ieee80211_is_data(hdr->frame_control) || |
| 665 | (tx->sta && test_sta_flag(tx->sta, WLAN_STA_SHORT_PREAMBLE)))) | 668 | (tx->sta && test_sta_flag(tx->sta, WLAN_STA_SHORT_PREAMBLE)))) |
| 666 | txrc.short_preamble = short_preamble = true; | 669 | txrc.short_preamble = true; |
| 670 | |||
| 671 | info->control.short_preamble = txrc.short_preamble; | ||
| 667 | 672 | ||
| 668 | if (tx->sta) | 673 | if (tx->sta) |
| 669 | assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC); | 674 | assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC); |
| @@ -687,16 +692,38 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) | |||
| 687 | */ | 692 | */ |
| 688 | rate_control_get_rate(tx->sdata, tx->sta, &txrc); | 693 | rate_control_get_rate(tx->sdata, tx->sta, &txrc); |
| 689 | 694 | ||
| 690 | if (unlikely(info->control.rates[0].idx < 0)) | 695 | if (tx->sta && !info->control.skip_table) |
| 691 | return TX_DROP; | 696 | ratetbl = rcu_dereference(tx->sta->sta.rates); |
| 697 | |||
| 698 | if (unlikely(info->control.rates[0].idx < 0)) { | ||
| 699 | if (ratetbl) { | ||
| 700 | struct ieee80211_tx_rate rate = { | ||
| 701 | .idx = ratetbl->rate[0].idx, | ||
| 702 | .flags = ratetbl->rate[0].flags, | ||
| 703 | .count = ratetbl->rate[0].count | ||
| 704 | }; | ||
| 705 | |||
| 706 | if (ratetbl->rate[0].idx < 0) | ||
| 707 | return TX_DROP; | ||
| 708 | |||
| 709 | tx->rate = rate; | ||
| 710 | } else { | ||
| 711 | return TX_DROP; | ||
| 712 | } | ||
| 713 | } else { | ||
| 714 | tx->rate = info->control.rates[0]; | ||
| 715 | } | ||
| 692 | 716 | ||
| 693 | if (txrc.reported_rate.idx < 0) { | 717 | if (txrc.reported_rate.idx < 0) { |
| 694 | txrc.reported_rate = info->control.rates[0]; | 718 | txrc.reported_rate = tx->rate; |
| 695 | if (tx->sta && ieee80211_is_data(hdr->frame_control)) | 719 | if (tx->sta && ieee80211_is_data(hdr->frame_control)) |
| 696 | tx->sta->last_tx_rate = txrc.reported_rate; | 720 | tx->sta->last_tx_rate = txrc.reported_rate; |
| 697 | } else if (tx->sta) | 721 | } else if (tx->sta) |
| 698 | tx->sta->last_tx_rate = txrc.reported_rate; | 722 | tx->sta->last_tx_rate = txrc.reported_rate; |
| 699 | 723 | ||
| 724 | if (ratetbl) | ||
| 725 | return TX_CONTINUE; | ||
| 726 | |||
| 700 | if (unlikely(!info->control.rates[0].count)) | 727 | if (unlikely(!info->control.rates[0].count)) |
| 701 | info->control.rates[0].count = 1; | 728 | info->control.rates[0].count = 1; |
| 702 | 729 | ||
| @@ -704,91 +731,6 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) | |||
| 704 | (info->flags & IEEE80211_TX_CTL_NO_ACK))) | 731 | (info->flags & IEEE80211_TX_CTL_NO_ACK))) |
| 705 | info->control.rates[0].count = 1; | 732 | info->control.rates[0].count = 1; |
| 706 | 733 | ||
| 707 | if (is_multicast_ether_addr(hdr->addr1)) { | ||
| 708 | /* | ||
| 709 | * XXX: verify the rate is in the basic rateset | ||
| 710 | */ | ||
| 711 | return TX_CONTINUE; | ||
| 712 | } | ||
| 713 | |||
| 714 | /* | ||
| 715 | * set up the RTS/CTS rate as the fastest basic rate | ||
| 716 | * that is not faster than the data rate | ||
| 717 | * | ||
| 718 | * XXX: Should this check all retry rates? | ||
| 719 | */ | ||
| 720 | if (!(info->control.rates[0].flags & IEEE80211_TX_RC_MCS)) { | ||
| 721 | s8 baserate = 0; | ||
| 722 | |||
| 723 | rate = &sband->bitrates[info->control.rates[0].idx]; | ||
| 724 | |||
| 725 | for (i = 0; i < sband->n_bitrates; i++) { | ||
| 726 | /* must be a basic rate */ | ||
| 727 | if (!(tx->sdata->vif.bss_conf.basic_rates & BIT(i))) | ||
| 728 | continue; | ||
| 729 | /* must not be faster than the data rate */ | ||
| 730 | if (sband->bitrates[i].bitrate > rate->bitrate) | ||
| 731 | continue; | ||
| 732 | /* maximum */ | ||
| 733 | if (sband->bitrates[baserate].bitrate < | ||
| 734 | sband->bitrates[i].bitrate) | ||
| 735 | baserate = i; | ||
| 736 | } | ||
| 737 | |||
| 738 | info->control.rts_cts_rate_idx = baserate; | ||
| 739 | } | ||
| 740 | |||
| 741 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | ||
| 742 | /* | ||
| 743 | * make sure there's no valid rate following | ||
| 744 | * an invalid one, just in case drivers don't | ||
| 745 | * take the API seriously to stop at -1. | ||
| 746 | */ | ||
| 747 | if (inval) { | ||
| 748 | info->control.rates[i].idx = -1; | ||
| 749 | continue; | ||
| 750 | } | ||
| 751 | if (info->control.rates[i].idx < 0) { | ||
| 752 | inval = true; | ||
| 753 | continue; | ||
| 754 | } | ||
| 755 | |||
| 756 | /* | ||
| 757 | * For now assume MCS is already set up correctly, this | ||
| 758 | * needs to be fixed. | ||
| 759 | */ | ||
| 760 | if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) { | ||
| 761 | WARN_ON(info->control.rates[i].idx > 76); | ||
| 762 | continue; | ||
| 763 | } | ||
| 764 | |||
| 765 | /* set up RTS protection if desired */ | ||
| 766 | if (rts) | ||
| 767 | info->control.rates[i].flags |= | ||
| 768 | IEEE80211_TX_RC_USE_RTS_CTS; | ||
| 769 | |||
| 770 | /* RC is busted */ | ||
| 771 | if (WARN_ON_ONCE(info->control.rates[i].idx >= | ||
| 772 | sband->n_bitrates)) { | ||
| 773 | info->control.rates[i].idx = -1; | ||
| 774 | continue; | ||
| 775 | } | ||
| 776 | |||
| 777 | rate = &sband->bitrates[info->control.rates[i].idx]; | ||
| 778 | |||
| 779 | /* set up short preamble */ | ||
| 780 | if (short_preamble && | ||
| 781 | rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) | ||
| 782 | info->control.rates[i].flags |= | ||
| 783 | IEEE80211_TX_RC_USE_SHORT_PREAMBLE; | ||
| 784 | |||
| 785 | /* set up G protection */ | ||
| 786 | if (!rts && tx->sdata->vif.bss_conf.use_cts_prot && | ||
| 787 | rate->flags & IEEE80211_RATE_ERP_G) | ||
| 788 | info->control.rates[i].flags |= | ||
| 789 | IEEE80211_TX_RC_USE_CTS_PROTECT; | ||
| 790 | } | ||
| 791 | |||
| 792 | return TX_CONTINUE; | 734 | return TX_CONTINUE; |
| 793 | } | 735 | } |
| 794 | 736 | ||
| @@ -2502,8 +2444,6 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
| 2502 | txrc.max_rate_idx = -1; | 2444 | txrc.max_rate_idx = -1; |
| 2503 | else | 2445 | else |
| 2504 | txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; | 2446 | txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; |
| 2505 | memcpy(txrc.rate_idx_mcs_mask, sdata->rc_rateidx_mcs_mask[band], | ||
| 2506 | sizeof(txrc.rate_idx_mcs_mask)); | ||
| 2507 | txrc.bss = true; | 2447 | txrc.bss = true; |
| 2508 | rate_control_get_rate(sdata, NULL, &txrc); | 2448 | rate_control_get_rate(sdata, NULL, &txrc); |
| 2509 | 2449 | ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 447e6651e7fa..3f87fa468b1f 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
| @@ -485,7 +485,8 @@ int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) | |||
| 485 | return true; | 485 | return true; |
| 486 | 486 | ||
| 487 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 487 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
| 488 | ret = !!local->queue_stop_reasons[queue]; | 488 | ret = test_bit(IEEE80211_QUEUE_STOP_REASON_DRIVER, |
| 489 | &local->queue_stop_reasons[queue]); | ||
| 489 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 490 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
| 490 | return ret; | 491 | return ret; |
| 491 | } | 492 | } |
| @@ -660,7 +661,7 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, | |||
| 660 | } | 661 | } |
| 661 | EXPORT_SYMBOL(ieee80211_queue_delayed_work); | 662 | EXPORT_SYMBOL(ieee80211_queue_delayed_work); |
| 662 | 663 | ||
| 663 | u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | 664 | u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, bool action, |
| 664 | struct ieee802_11_elems *elems, | 665 | struct ieee802_11_elems *elems, |
| 665 | u64 filter, u32 crc) | 666 | u64 filter, u32 crc) |
| 666 | { | 667 | { |
| @@ -668,6 +669,7 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
| 668 | u8 *pos = start; | 669 | u8 *pos = start; |
| 669 | bool calc_crc = filter != 0; | 670 | bool calc_crc = filter != 0; |
| 670 | DECLARE_BITMAP(seen_elems, 256); | 671 | DECLARE_BITMAP(seen_elems, 256); |
| 672 | const u8 *ie; | ||
| 671 | 673 | ||
| 672 | bitmap_zero(seen_elems, 256); | 674 | bitmap_zero(seen_elems, 256); |
| 673 | memset(elems, 0, sizeof(*elems)); | 675 | memset(elems, 0, sizeof(*elems)); |
| @@ -715,6 +717,12 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
| 715 | case WLAN_EID_COUNTRY: | 717 | case WLAN_EID_COUNTRY: |
| 716 | case WLAN_EID_PWR_CONSTRAINT: | 718 | case WLAN_EID_PWR_CONSTRAINT: |
| 717 | case WLAN_EID_TIMEOUT_INTERVAL: | 719 | case WLAN_EID_TIMEOUT_INTERVAL: |
| 720 | case WLAN_EID_SECONDARY_CHANNEL_OFFSET: | ||
| 721 | case WLAN_EID_WIDE_BW_CHANNEL_SWITCH: | ||
| 722 | /* | ||
| 723 | * not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible | ||
| 724 | * that if the content gets bigger it might be needed more than once | ||
| 725 | */ | ||
| 718 | if (test_bit(id, seen_elems)) { | 726 | if (test_bit(id, seen_elems)) { |
| 719 | elems->parse_error = true; | 727 | elems->parse_error = true; |
| 720 | left -= elen; | 728 | left -= elen; |
| @@ -862,6 +870,48 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
| 862 | } | 870 | } |
| 863 | elems->ch_switch_ie = (void *)pos; | 871 | elems->ch_switch_ie = (void *)pos; |
| 864 | break; | 872 | break; |
| 873 | case WLAN_EID_EXT_CHANSWITCH_ANN: | ||
| 874 | if (elen != sizeof(struct ieee80211_ext_chansw_ie)) { | ||
| 875 | elem_parse_failed = true; | ||
| 876 | break; | ||
| 877 | } | ||
| 878 | elems->ext_chansw_ie = (void *)pos; | ||
| 879 | break; | ||
| 880 | case WLAN_EID_SECONDARY_CHANNEL_OFFSET: | ||
| 881 | if (elen != sizeof(struct ieee80211_sec_chan_offs_ie)) { | ||
| 882 | elem_parse_failed = true; | ||
| 883 | break; | ||
| 884 | } | ||
| 885 | elems->sec_chan_offs = (void *)pos; | ||
| 886 | break; | ||
| 887 | case WLAN_EID_WIDE_BW_CHANNEL_SWITCH: | ||
| 888 | if (!action || | ||
| 889 | elen != sizeof(*elems->wide_bw_chansw_ie)) { | ||
| 890 | elem_parse_failed = true; | ||
| 891 | break; | ||
| 892 | } | ||
| 893 | elems->wide_bw_chansw_ie = (void *)pos; | ||
| 894 | break; | ||
| 895 | case WLAN_EID_CHANNEL_SWITCH_WRAPPER: | ||
| 896 | if (action) { | ||
| 897 | elem_parse_failed = true; | ||
| 898 | break; | ||
| 899 | } | ||
| 900 | /* | ||
| 901 | * This is a bit tricky, but as we only care about | ||
| 902 | * the wide bandwidth channel switch element, so | ||
| 903 | * just parse it out manually. | ||
| 904 | */ | ||
| 905 | ie = cfg80211_find_ie(WLAN_EID_WIDE_BW_CHANNEL_SWITCH, | ||
| 906 | pos, elen); | ||
| 907 | if (ie) { | ||
| 908 | if (ie[1] == sizeof(*elems->wide_bw_chansw_ie)) | ||
| 909 | elems->wide_bw_chansw_ie = | ||
| 910 | (void *)(ie + 2); | ||
| 911 | else | ||
| 912 | elem_parse_failed = true; | ||
| 913 | } | ||
| 914 | break; | ||
| 865 | case WLAN_EID_COUNTRY: | 915 | case WLAN_EID_COUNTRY: |
| 866 | elems->country_elem = pos; | 916 | elems->country_elem = pos; |
| 867 | elems->country_elem_len = elen; | 917 | elems->country_elem_len = elen; |
diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c index 78fc0937948d..fb076cd6f808 100644 --- a/net/rfkill/rfkill-gpio.c +++ b/net/rfkill/rfkill-gpio.c | |||
| @@ -131,6 +131,7 @@ static int rfkill_gpio_probe(struct platform_device *pdev) | |||
| 131 | rfkill->pwr_clk = clk_get(&pdev->dev, pdata->power_clk_name); | 131 | rfkill->pwr_clk = clk_get(&pdev->dev, pdata->power_clk_name); |
| 132 | if (IS_ERR(rfkill->pwr_clk)) { | 132 | if (IS_ERR(rfkill->pwr_clk)) { |
| 133 | pr_warn("%s: can't find pwr_clk.\n", __func__); | 133 | pr_warn("%s: can't find pwr_clk.\n", __func__); |
| 134 | ret = PTR_ERR(rfkill->pwr_clk); | ||
| 134 | goto fail_shutdown_name; | 135 | goto fail_shutdown_name; |
| 135 | } | 136 | } |
| 136 | } | 137 | } |
| @@ -152,9 +153,11 @@ static int rfkill_gpio_probe(struct platform_device *pdev) | |||
| 152 | } | 153 | } |
| 153 | 154 | ||
| 154 | rfkill->rfkill_dev = rfkill_alloc(pdata->name, &pdev->dev, pdata->type, | 155 | rfkill->rfkill_dev = rfkill_alloc(pdata->name, &pdev->dev, pdata->type, |
| 155 | &rfkill_gpio_ops, rfkill); | 156 | &rfkill_gpio_ops, rfkill); |
| 156 | if (!rfkill->rfkill_dev) | 157 | if (!rfkill->rfkill_dev) { |
| 158 | ret = -ENOMEM; | ||
| 157 | goto fail_shutdown; | 159 | goto fail_shutdown; |
| 160 | } | ||
| 158 | 161 | ||
| 159 | ret = rfkill_register(rfkill->rfkill_dev); | 162 | ret = rfkill_register(rfkill->rfkill_dev); |
| 160 | if (ret < 0) | 163 | if (ret < 0) |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 124e5e773fbc..fd35dae547c4 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
| @@ -88,6 +88,9 @@ struct cfg80211_registered_device { | |||
| 88 | 88 | ||
| 89 | struct delayed_work dfs_update_channels_wk; | 89 | struct delayed_work dfs_update_channels_wk; |
| 90 | 90 | ||
| 91 | /* netlink port which started critical protocol (0 means not started) */ | ||
| 92 | u32 crit_proto_nlportid; | ||
| 93 | |||
| 91 | /* must be last because of the way we do wiphy_priv(), | 94 | /* must be last because of the way we do wiphy_priv(), |
| 92 | * and it should at least be aligned to NETDEV_ALIGN */ | 95 | * and it should at least be aligned to NETDEV_ALIGN */ |
| 93 | struct wiphy wiphy __aligned(NETDEV_ALIGN); | 96 | struct wiphy wiphy __aligned(NETDEV_ALIGN); |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 390198bf4b36..0c7b7dd855f6 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
| @@ -648,6 +648,11 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid) | |||
| 648 | 648 | ||
| 649 | spin_unlock_bh(&wdev->mgmt_registrations_lock); | 649 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
| 650 | 650 | ||
| 651 | if (nlportid && rdev->crit_proto_nlportid == nlportid) { | ||
| 652 | rdev->crit_proto_nlportid = 0; | ||
| 653 | rdev_crit_proto_stop(rdev, wdev); | ||
| 654 | } | ||
| 655 | |||
| 651 | if (nlportid == wdev->ap_unexpected_nlportid) | 656 | if (nlportid == wdev->ap_unexpected_nlportid) |
| 652 | wdev->ap_unexpected_nlportid = 0; | 657 | wdev->ap_unexpected_nlportid = 0; |
| 653 | } | 658 | } |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 671b69a3c136..afa283841e8c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
| @@ -447,62 +447,69 @@ nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = { | |||
| 447 | [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 }, | 447 | [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 }, |
| 448 | }; | 448 | }; |
| 449 | 449 | ||
| 450 | /* ifidx get helper */ | 450 | static int nl80211_prepare_wdev_dump(struct sk_buff *skb, |
| 451 | static int nl80211_get_ifidx(struct netlink_callback *cb) | 451 | struct netlink_callback *cb, |
| 452 | struct cfg80211_registered_device **rdev, | ||
| 453 | struct wireless_dev **wdev) | ||
| 452 | { | 454 | { |
| 453 | int res; | 455 | int err; |
| 454 | |||
| 455 | res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | ||
| 456 | nl80211_fam.attrbuf, nl80211_fam.maxattr, | ||
| 457 | nl80211_policy); | ||
| 458 | if (res) | ||
| 459 | return res; | ||
| 460 | |||
| 461 | if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) | ||
| 462 | return -EINVAL; | ||
| 463 | 456 | ||
| 464 | res = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); | 457 | rtnl_lock(); |
| 465 | if (!res) | 458 | mutex_lock(&cfg80211_mutex); |
| 466 | return -EINVAL; | ||
| 467 | return res; | ||
| 468 | } | ||
| 469 | 459 | ||
| 470 | static int nl80211_prepare_netdev_dump(struct sk_buff *skb, | 460 | if (!cb->args[0]) { |
| 471 | struct netlink_callback *cb, | 461 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, |
| 472 | struct cfg80211_registered_device **rdev, | 462 | nl80211_fam.attrbuf, nl80211_fam.maxattr, |
| 473 | struct net_device **dev) | 463 | nl80211_policy); |
| 474 | { | 464 | if (err) |
| 475 | int ifidx = cb->args[0]; | 465 | goto out_unlock; |
| 476 | int err; | ||
| 477 | 466 | ||
| 478 | if (!ifidx) | 467 | *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), |
| 479 | ifidx = nl80211_get_ifidx(cb); | 468 | nl80211_fam.attrbuf); |
| 480 | if (ifidx < 0) | 469 | if (IS_ERR(*wdev)) { |
| 481 | return ifidx; | 470 | err = PTR_ERR(*wdev); |
| 471 | goto out_unlock; | ||
| 472 | } | ||
| 473 | *rdev = wiphy_to_dev((*wdev)->wiphy); | ||
| 474 | cb->args[0] = (*rdev)->wiphy_idx; | ||
| 475 | cb->args[1] = (*wdev)->identifier; | ||
| 476 | } else { | ||
| 477 | struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0]); | ||
| 478 | struct wireless_dev *tmp; | ||
| 482 | 479 | ||
| 483 | cb->args[0] = ifidx; | 480 | if (!wiphy) { |
| 481 | err = -ENODEV; | ||
| 482 | goto out_unlock; | ||
| 483 | } | ||
| 484 | *rdev = wiphy_to_dev(wiphy); | ||
| 485 | *wdev = NULL; | ||
| 484 | 486 | ||
| 485 | rtnl_lock(); | 487 | mutex_lock(&(*rdev)->devlist_mtx); |
| 488 | list_for_each_entry(tmp, &(*rdev)->wdev_list, list) { | ||
| 489 | if (tmp->identifier == cb->args[1]) { | ||
| 490 | *wdev = tmp; | ||
| 491 | break; | ||
| 492 | } | ||
| 493 | } | ||
| 494 | mutex_unlock(&(*rdev)->devlist_mtx); | ||
| 486 | 495 | ||
| 487 | *dev = __dev_get_by_index(sock_net(skb->sk), ifidx); | 496 | if (!*wdev) { |
| 488 | if (!*dev) { | 497 | err = -ENODEV; |
| 489 | err = -ENODEV; | 498 | goto out_unlock; |
| 490 | goto out_rtnl; | 499 | } |
| 491 | } | 500 | } |
| 492 | 501 | ||
| 493 | *rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | 502 | cfg80211_lock_rdev(*rdev); |
| 494 | if (IS_ERR(*rdev)) { | ||
| 495 | err = PTR_ERR(*rdev); | ||
| 496 | goto out_rtnl; | ||
| 497 | } | ||
| 498 | 503 | ||
| 504 | mutex_unlock(&cfg80211_mutex); | ||
| 499 | return 0; | 505 | return 0; |
| 500 | out_rtnl: | 506 | out_unlock: |
| 507 | mutex_unlock(&cfg80211_mutex); | ||
| 501 | rtnl_unlock(); | 508 | rtnl_unlock(); |
| 502 | return err; | 509 | return err; |
| 503 | } | 510 | } |
| 504 | 511 | ||
| 505 | static void nl80211_finish_netdev_dump(struct cfg80211_registered_device *rdev) | 512 | static void nl80211_finish_wdev_dump(struct cfg80211_registered_device *rdev) |
| 506 | { | 513 | { |
| 507 | cfg80211_unlock_rdev(rdev); | 514 | cfg80211_unlock_rdev(rdev); |
| 508 | rtnl_unlock(); | 515 | rtnl_unlock(); |
| @@ -1417,6 +1424,10 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
| 1417 | } | 1424 | } |
| 1418 | CMD(start_p2p_device, START_P2P_DEVICE); | 1425 | CMD(start_p2p_device, START_P2P_DEVICE); |
| 1419 | CMD(set_mcast_rate, SET_MCAST_RATE); | 1426 | CMD(set_mcast_rate, SET_MCAST_RATE); |
| 1427 | if (split) { | ||
| 1428 | CMD(crit_proto_start, CRIT_PROTOCOL_START); | ||
| 1429 | CMD(crit_proto_stop, CRIT_PROTOCOL_STOP); | ||
| 1430 | } | ||
| 1420 | 1431 | ||
| 1421 | #ifdef CONFIG_NL80211_TESTMODE | 1432 | #ifdef CONFIG_NL80211_TESTMODE |
| 1422 | CMD(testmode_cmd, TESTMODE); | 1433 | CMD(testmode_cmd, TESTMODE); |
| @@ -3525,15 +3536,20 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
| 3525 | { | 3536 | { |
| 3526 | struct station_info sinfo; | 3537 | struct station_info sinfo; |
| 3527 | struct cfg80211_registered_device *dev; | 3538 | struct cfg80211_registered_device *dev; |
| 3528 | struct net_device *netdev; | 3539 | struct wireless_dev *wdev; |
| 3529 | u8 mac_addr[ETH_ALEN]; | 3540 | u8 mac_addr[ETH_ALEN]; |
| 3530 | int sta_idx = cb->args[1]; | 3541 | int sta_idx = cb->args[2]; |
| 3531 | int err; | 3542 | int err; |
| 3532 | 3543 | ||
| 3533 | err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); | 3544 | err = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev); |
| 3534 | if (err) | 3545 | if (err) |
| 3535 | return err; | 3546 | return err; |
| 3536 | 3547 | ||
| 3548 | if (!wdev->netdev) { | ||
| 3549 | err = -EINVAL; | ||
| 3550 | goto out_err; | ||
| 3551 | } | ||
| 3552 | |||
| 3537 | if (!dev->ops->dump_station) { | 3553 | if (!dev->ops->dump_station) { |
| 3538 | err = -EOPNOTSUPP; | 3554 | err = -EOPNOTSUPP; |
| 3539 | goto out_err; | 3555 | goto out_err; |
| @@ -3541,7 +3557,7 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
| 3541 | 3557 | ||
| 3542 | while (1) { | 3558 | while (1) { |
| 3543 | memset(&sinfo, 0, sizeof(sinfo)); | 3559 | memset(&sinfo, 0, sizeof(sinfo)); |
| 3544 | err = rdev_dump_station(dev, netdev, sta_idx, | 3560 | err = rdev_dump_station(dev, wdev->netdev, sta_idx, |
| 3545 | mac_addr, &sinfo); | 3561 | mac_addr, &sinfo); |
| 3546 | if (err == -ENOENT) | 3562 | if (err == -ENOENT) |
| 3547 | break; | 3563 | break; |
| @@ -3551,7 +3567,7 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
| 3551 | if (nl80211_send_station(skb, | 3567 | if (nl80211_send_station(skb, |
| 3552 | NETLINK_CB(cb->skb).portid, | 3568 | NETLINK_CB(cb->skb).portid, |
| 3553 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 3569 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
| 3554 | dev, netdev, mac_addr, | 3570 | dev, wdev->netdev, mac_addr, |
| 3555 | &sinfo) < 0) | 3571 | &sinfo) < 0) |
| 3556 | goto out; | 3572 | goto out; |
| 3557 | 3573 | ||
| @@ -3560,10 +3576,10 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
| 3560 | 3576 | ||
| 3561 | 3577 | ||
| 3562 | out: | 3578 | out: |
| 3563 | cb->args[1] = sta_idx; | 3579 | cb->args[2] = sta_idx; |
| 3564 | err = skb->len; | 3580 | err = skb->len; |
| 3565 | out_err: | 3581 | out_err: |
| 3566 | nl80211_finish_netdev_dump(dev); | 3582 | nl80211_finish_wdev_dump(dev); |
| 3567 | 3583 | ||
| 3568 | return err; | 3584 | return err; |
| 3569 | } | 3585 | } |
| @@ -4167,13 +4183,13 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
| 4167 | { | 4183 | { |
| 4168 | struct mpath_info pinfo; | 4184 | struct mpath_info pinfo; |
| 4169 | struct cfg80211_registered_device *dev; | 4185 | struct cfg80211_registered_device *dev; |
| 4170 | struct net_device *netdev; | 4186 | struct wireless_dev *wdev; |
| 4171 | u8 dst[ETH_ALEN]; | 4187 | u8 dst[ETH_ALEN]; |
| 4172 | u8 next_hop[ETH_ALEN]; | 4188 | u8 next_hop[ETH_ALEN]; |
| 4173 | int path_idx = cb->args[1]; | 4189 | int path_idx = cb->args[2]; |
| 4174 | int err; | 4190 | int err; |
| 4175 | 4191 | ||
| 4176 | err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); | 4192 | err = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev); |
| 4177 | if (err) | 4193 | if (err) |
| 4178 | return err; | 4194 | return err; |
| 4179 | 4195 | ||
| @@ -4182,14 +4198,14 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
| 4182 | goto out_err; | 4198 | goto out_err; |
| 4183 | } | 4199 | } |
| 4184 | 4200 | ||
| 4185 | if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | 4201 | if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) { |
| 4186 | err = -EOPNOTSUPP; | 4202 | err = -EOPNOTSUPP; |
| 4187 | goto out_err; | 4203 | goto out_err; |
| 4188 | } | 4204 | } |
| 4189 | 4205 | ||
| 4190 | while (1) { | 4206 | while (1) { |
| 4191 | err = rdev_dump_mpath(dev, netdev, path_idx, dst, next_hop, | 4207 | err = rdev_dump_mpath(dev, wdev->netdev, path_idx, dst, |
| 4192 | &pinfo); | 4208 | next_hop, &pinfo); |
| 4193 | if (err == -ENOENT) | 4209 | if (err == -ENOENT) |
| 4194 | break; | 4210 | break; |
| 4195 | if (err) | 4211 | if (err) |
| @@ -4197,7 +4213,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
| 4197 | 4213 | ||
| 4198 | if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid, | 4214 | if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid, |
| 4199 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 4215 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
| 4200 | netdev, dst, next_hop, | 4216 | wdev->netdev, dst, next_hop, |
| 4201 | &pinfo) < 0) | 4217 | &pinfo) < 0) |
| 4202 | goto out; | 4218 | goto out; |
| 4203 | 4219 | ||
| @@ -4206,10 +4222,10 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
| 4206 | 4222 | ||
| 4207 | 4223 | ||
| 4208 | out: | 4224 | out: |
| 4209 | cb->args[1] = path_idx; | 4225 | cb->args[2] = path_idx; |
| 4210 | err = skb->len; | 4226 | err = skb->len; |
| 4211 | out_err: | 4227 | out_err: |
| 4212 | nl80211_finish_netdev_dump(dev); | 4228 | nl80211_finish_wdev_dump(dev); |
| 4213 | return err; | 4229 | return err; |
| 4214 | } | 4230 | } |
| 4215 | 4231 | ||
| @@ -5565,9 +5581,13 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, | |||
| 5565 | 5581 | ||
| 5566 | genl_dump_check_consistent(cb, hdr, &nl80211_fam); | 5582 | genl_dump_check_consistent(cb, hdr, &nl80211_fam); |
| 5567 | 5583 | ||
| 5568 | if (nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation) || | 5584 | if (nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation)) |
| 5585 | goto nla_put_failure; | ||
| 5586 | if (wdev->netdev && | ||
| 5569 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex)) | 5587 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex)) |
| 5570 | goto nla_put_failure; | 5588 | goto nla_put_failure; |
| 5589 | if (nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev))) | ||
| 5590 | goto nla_put_failure; | ||
| 5571 | 5591 | ||
| 5572 | bss = nla_nest_start(msg, NL80211_ATTR_BSS); | 5592 | bss = nla_nest_start(msg, NL80211_ATTR_BSS); |
| 5573 | if (!bss) | 5593 | if (!bss) |
| @@ -5647,22 +5667,18 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, | |||
| 5647 | return -EMSGSIZE; | 5667 | return -EMSGSIZE; |
| 5648 | } | 5668 | } |
| 5649 | 5669 | ||
| 5650 | static int nl80211_dump_scan(struct sk_buff *skb, | 5670 | static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb) |
| 5651 | struct netlink_callback *cb) | ||
| 5652 | { | 5671 | { |
| 5653 | struct cfg80211_registered_device *rdev; | 5672 | struct cfg80211_registered_device *rdev; |
| 5654 | struct net_device *dev; | ||
| 5655 | struct cfg80211_internal_bss *scan; | 5673 | struct cfg80211_internal_bss *scan; |
| 5656 | struct wireless_dev *wdev; | 5674 | struct wireless_dev *wdev; |
| 5657 | int start = cb->args[1], idx = 0; | 5675 | int start = cb->args[2], idx = 0; |
| 5658 | int err; | 5676 | int err; |
| 5659 | 5677 | ||
| 5660 | err = nl80211_prepare_netdev_dump(skb, cb, &rdev, &dev); | 5678 | err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); |
| 5661 | if (err) | 5679 | if (err) |
| 5662 | return err; | 5680 | return err; |
| 5663 | 5681 | ||
| 5664 | wdev = dev->ieee80211_ptr; | ||
| 5665 | |||
| 5666 | wdev_lock(wdev); | 5682 | wdev_lock(wdev); |
| 5667 | spin_lock_bh(&rdev->bss_lock); | 5683 | spin_lock_bh(&rdev->bss_lock); |
| 5668 | cfg80211_bss_expire(rdev); | 5684 | cfg80211_bss_expire(rdev); |
| @@ -5683,8 +5699,8 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
| 5683 | spin_unlock_bh(&rdev->bss_lock); | 5699 | spin_unlock_bh(&rdev->bss_lock); |
| 5684 | wdev_unlock(wdev); | 5700 | wdev_unlock(wdev); |
| 5685 | 5701 | ||
| 5686 | cb->args[1] = idx; | 5702 | cb->args[2] = idx; |
| 5687 | nl80211_finish_netdev_dump(rdev); | 5703 | nl80211_finish_wdev_dump(rdev); |
| 5688 | 5704 | ||
| 5689 | return skb->len; | 5705 | return skb->len; |
| 5690 | } | 5706 | } |
| @@ -5753,14 +5769,19 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
| 5753 | { | 5769 | { |
| 5754 | struct survey_info survey; | 5770 | struct survey_info survey; |
| 5755 | struct cfg80211_registered_device *dev; | 5771 | struct cfg80211_registered_device *dev; |
| 5756 | struct net_device *netdev; | 5772 | struct wireless_dev *wdev; |
| 5757 | int survey_idx = cb->args[1]; | 5773 | int survey_idx = cb->args[2]; |
| 5758 | int res; | 5774 | int res; |
| 5759 | 5775 | ||
| 5760 | res = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); | 5776 | res = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev); |
| 5761 | if (res) | 5777 | if (res) |
| 5762 | return res; | 5778 | return res; |
| 5763 | 5779 | ||
| 5780 | if (!wdev->netdev) { | ||
| 5781 | res = -EINVAL; | ||
| 5782 | goto out_err; | ||
| 5783 | } | ||
| 5784 | |||
| 5764 | if (!dev->ops->dump_survey) { | 5785 | if (!dev->ops->dump_survey) { |
| 5765 | res = -EOPNOTSUPP; | 5786 | res = -EOPNOTSUPP; |
| 5766 | goto out_err; | 5787 | goto out_err; |
| @@ -5769,7 +5790,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
| 5769 | while (1) { | 5790 | while (1) { |
| 5770 | struct ieee80211_channel *chan; | 5791 | struct ieee80211_channel *chan; |
| 5771 | 5792 | ||
| 5772 | res = rdev_dump_survey(dev, netdev, survey_idx, &survey); | 5793 | res = rdev_dump_survey(dev, wdev->netdev, survey_idx, &survey); |
| 5773 | if (res == -ENOENT) | 5794 | if (res == -ENOENT) |
| 5774 | break; | 5795 | break; |
| 5775 | if (res) | 5796 | if (res) |
| @@ -5791,17 +5812,16 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
| 5791 | if (nl80211_send_survey(skb, | 5812 | if (nl80211_send_survey(skb, |
| 5792 | NETLINK_CB(cb->skb).portid, | 5813 | NETLINK_CB(cb->skb).portid, |
| 5793 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 5814 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
| 5794 | netdev, | 5815 | wdev->netdev, &survey) < 0) |
| 5795 | &survey) < 0) | ||
| 5796 | goto out; | 5816 | goto out; |
| 5797 | survey_idx++; | 5817 | survey_idx++; |
| 5798 | } | 5818 | } |
| 5799 | 5819 | ||
| 5800 | out: | 5820 | out: |
| 5801 | cb->args[1] = survey_idx; | 5821 | cb->args[2] = survey_idx; |
| 5802 | res = skb->len; | 5822 | res = skb->len; |
| 5803 | out_err: | 5823 | out_err: |
| 5804 | nl80211_finish_netdev_dump(dev); | 5824 | nl80211_finish_wdev_dump(dev); |
| 5805 | return res; | 5825 | return res; |
| 5806 | } | 5826 | } |
| 5807 | 5827 | ||
| @@ -8143,9 +8163,11 @@ static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info) | |||
| 8143 | if (!rdev->ops->stop_p2p_device) | 8163 | if (!rdev->ops->stop_p2p_device) |
| 8144 | return -EOPNOTSUPP; | 8164 | return -EOPNOTSUPP; |
| 8145 | 8165 | ||
| 8166 | mutex_lock(&rdev->devlist_mtx); | ||
| 8146 | mutex_lock(&rdev->sched_scan_mtx); | 8167 | mutex_lock(&rdev->sched_scan_mtx); |
| 8147 | cfg80211_stop_p2p_device(rdev, wdev); | 8168 | cfg80211_stop_p2p_device(rdev, wdev); |
| 8148 | mutex_unlock(&rdev->sched_scan_mtx); | 8169 | mutex_unlock(&rdev->sched_scan_mtx); |
| 8170 | mutex_unlock(&rdev->devlist_mtx); | ||
| 8149 | 8171 | ||
| 8150 | return 0; | 8172 | return 0; |
| 8151 | } | 8173 | } |
| @@ -8198,6 +8220,64 @@ static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info) | |||
| 8198 | return rdev_update_ft_ies(rdev, dev, &ft_params); | 8220 | return rdev_update_ft_ies(rdev, dev, &ft_params); |
| 8199 | } | 8221 | } |
| 8200 | 8222 | ||
| 8223 | static int nl80211_crit_protocol_start(struct sk_buff *skb, | ||
| 8224 | struct genl_info *info) | ||
| 8225 | { | ||
| 8226 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
| 8227 | struct wireless_dev *wdev = info->user_ptr[1]; | ||
| 8228 | enum nl80211_crit_proto_id proto = NL80211_CRIT_PROTO_UNSPEC; | ||
| 8229 | u16 duration; | ||
| 8230 | int ret; | ||
| 8231 | |||
| 8232 | if (!rdev->ops->crit_proto_start) | ||
| 8233 | return -EOPNOTSUPP; | ||
| 8234 | |||
| 8235 | if (WARN_ON(!rdev->ops->crit_proto_stop)) | ||
| 8236 | return -EINVAL; | ||
| 8237 | |||
| 8238 | if (rdev->crit_proto_nlportid) | ||
| 8239 | return -EBUSY; | ||
| 8240 | |||
| 8241 | /* determine protocol if provided */ | ||
| 8242 | if (info->attrs[NL80211_ATTR_CRIT_PROT_ID]) | ||
| 8243 | proto = nla_get_u16(info->attrs[NL80211_ATTR_CRIT_PROT_ID]); | ||
| 8244 | |||
| 8245 | if (proto >= NUM_NL80211_CRIT_PROTO) | ||
| 8246 | return -EINVAL; | ||
| 8247 | |||
| 8248 | /* timeout must be provided */ | ||
| 8249 | if (!info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION]) | ||
| 8250 | return -EINVAL; | ||
| 8251 | |||
| 8252 | duration = | ||
| 8253 | nla_get_u16(info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION]); | ||
| 8254 | |||
| 8255 | if (duration > NL80211_CRIT_PROTO_MAX_DURATION) | ||
| 8256 | return -ERANGE; | ||
| 8257 | |||
| 8258 | ret = rdev_crit_proto_start(rdev, wdev, proto, duration); | ||
| 8259 | if (!ret) | ||
| 8260 | rdev->crit_proto_nlportid = info->snd_portid; | ||
| 8261 | |||
| 8262 | return ret; | ||
| 8263 | } | ||
| 8264 | |||
| 8265 | static int nl80211_crit_protocol_stop(struct sk_buff *skb, | ||
| 8266 | struct genl_info *info) | ||
| 8267 | { | ||
| 8268 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
| 8269 | struct wireless_dev *wdev = info->user_ptr[1]; | ||
| 8270 | |||
| 8271 | if (!rdev->ops->crit_proto_stop) | ||
| 8272 | return -EOPNOTSUPP; | ||
| 8273 | |||
| 8274 | if (rdev->crit_proto_nlportid) { | ||
| 8275 | rdev->crit_proto_nlportid = 0; | ||
| 8276 | rdev_crit_proto_stop(rdev, wdev); | ||
| 8277 | } | ||
| 8278 | return 0; | ||
| 8279 | } | ||
| 8280 | |||
| 8201 | #define NL80211_FLAG_NEED_WIPHY 0x01 | 8281 | #define NL80211_FLAG_NEED_WIPHY 0x01 |
| 8202 | #define NL80211_FLAG_NEED_NETDEV 0x02 | 8282 | #define NL80211_FLAG_NEED_NETDEV 0x02 |
| 8203 | #define NL80211_FLAG_NEED_RTNL 0x04 | 8283 | #define NL80211_FLAG_NEED_RTNL 0x04 |
| @@ -8887,6 +8967,22 @@ static struct genl_ops nl80211_ops[] = { | |||
| 8887 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 8967 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
| 8888 | NL80211_FLAG_NEED_RTNL, | 8968 | NL80211_FLAG_NEED_RTNL, |
| 8889 | }, | 8969 | }, |
| 8970 | { | ||
| 8971 | .cmd = NL80211_CMD_CRIT_PROTOCOL_START, | ||
| 8972 | .doit = nl80211_crit_protocol_start, | ||
| 8973 | .policy = nl80211_policy, | ||
| 8974 | .flags = GENL_ADMIN_PERM, | ||
| 8975 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | | ||
| 8976 | NL80211_FLAG_NEED_RTNL, | ||
| 8977 | }, | ||
| 8978 | { | ||
| 8979 | .cmd = NL80211_CMD_CRIT_PROTOCOL_STOP, | ||
| 8980 | .doit = nl80211_crit_protocol_stop, | ||
| 8981 | .policy = nl80211_policy, | ||
| 8982 | .flags = GENL_ADMIN_PERM, | ||
| 8983 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | | ||
| 8984 | NL80211_FLAG_NEED_RTNL, | ||
| 8985 | } | ||
| 8890 | }; | 8986 | }; |
| 8891 | 8987 | ||
| 8892 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 8988 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
| @@ -10632,6 +10728,45 @@ void cfg80211_ft_event(struct net_device *netdev, | |||
| 10632 | } | 10728 | } |
| 10633 | EXPORT_SYMBOL(cfg80211_ft_event); | 10729 | EXPORT_SYMBOL(cfg80211_ft_event); |
| 10634 | 10730 | ||
| 10731 | void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp) | ||
| 10732 | { | ||
| 10733 | struct cfg80211_registered_device *rdev; | ||
| 10734 | struct sk_buff *msg; | ||
| 10735 | void *hdr; | ||
| 10736 | u32 nlportid; | ||
| 10737 | |||
| 10738 | rdev = wiphy_to_dev(wdev->wiphy); | ||
| 10739 | if (!rdev->crit_proto_nlportid) | ||
| 10740 | return; | ||
| 10741 | |||
| 10742 | nlportid = rdev->crit_proto_nlportid; | ||
| 10743 | rdev->crit_proto_nlportid = 0; | ||
| 10744 | |||
| 10745 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | ||
| 10746 | if (!msg) | ||
| 10747 | return; | ||
| 10748 | |||
| 10749 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CRIT_PROTOCOL_STOP); | ||
| 10750 | if (!hdr) | ||
| 10751 | goto nla_put_failure; | ||
| 10752 | |||
| 10753 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
| 10754 | nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev))) | ||
| 10755 | goto nla_put_failure; | ||
| 10756 | |||
| 10757 | genlmsg_end(msg, hdr); | ||
| 10758 | |||
| 10759 | genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid); | ||
| 10760 | return; | ||
| 10761 | |||
| 10762 | nla_put_failure: | ||
| 10763 | if (hdr) | ||
| 10764 | genlmsg_cancel(msg, hdr); | ||
| 10765 | nlmsg_free(msg); | ||
| 10766 | |||
| 10767 | } | ||
| 10768 | EXPORT_SYMBOL(cfg80211_crit_proto_stopped); | ||
| 10769 | |||
| 10635 | /* initialisation/exit functions */ | 10770 | /* initialisation/exit functions */ |
| 10636 | 10771 | ||
| 10637 | int nl80211_init(void) | 10772 | int nl80211_init(void) |
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index d77e1c1d3a0e..9f15f0ac824d 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h | |||
| @@ -875,7 +875,7 @@ static inline void rdev_stop_p2p_device(struct cfg80211_registered_device *rdev, | |||
| 875 | trace_rdev_stop_p2p_device(&rdev->wiphy, wdev); | 875 | trace_rdev_stop_p2p_device(&rdev->wiphy, wdev); |
| 876 | rdev->ops->stop_p2p_device(&rdev->wiphy, wdev); | 876 | rdev->ops->stop_p2p_device(&rdev->wiphy, wdev); |
| 877 | trace_rdev_return_void(&rdev->wiphy); | 877 | trace_rdev_return_void(&rdev->wiphy); |
| 878 | } | 878 | } |
| 879 | 879 | ||
| 880 | static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev, | 880 | static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev, |
| 881 | struct net_device *dev, | 881 | struct net_device *dev, |
| @@ -901,4 +901,26 @@ static inline int rdev_update_ft_ies(struct cfg80211_registered_device *rdev, | |||
| 901 | return ret; | 901 | return ret; |
| 902 | } | 902 | } |
| 903 | 903 | ||
| 904 | static inline int rdev_crit_proto_start(struct cfg80211_registered_device *rdev, | ||
| 905 | struct wireless_dev *wdev, | ||
| 906 | enum nl80211_crit_proto_id protocol, | ||
| 907 | u16 duration) | ||
| 908 | { | ||
| 909 | int ret; | ||
| 910 | |||
| 911 | trace_rdev_crit_proto_start(&rdev->wiphy, wdev, protocol, duration); | ||
| 912 | ret = rdev->ops->crit_proto_start(&rdev->wiphy, wdev, | ||
| 913 | protocol, duration); | ||
| 914 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
| 915 | return ret; | ||
| 916 | } | ||
| 917 | |||
| 918 | static inline void rdev_crit_proto_stop(struct cfg80211_registered_device *rdev, | ||
| 919 | struct wireless_dev *wdev) | ||
| 920 | { | ||
| 921 | trace_rdev_crit_proto_stop(&rdev->wiphy, wdev); | ||
| 922 | rdev->ops->crit_proto_stop(&rdev->wiphy, wdev); | ||
| 923 | trace_rdev_return_void(&rdev->wiphy); | ||
| 924 | } | ||
| 925 | |||
| 904 | #endif /* __CFG80211_RDEV_OPS */ | 926 | #endif /* __CFG80211_RDEV_OPS */ |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index e6df52dc8c69..cc35fbaa4578 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
| @@ -855,7 +855,7 @@ static void handle_channel(struct wiphy *wiphy, | |||
| 855 | return; | 855 | return; |
| 856 | 856 | ||
| 857 | REG_DBG_PRINT("Disabling freq %d MHz\n", chan->center_freq); | 857 | REG_DBG_PRINT("Disabling freq %d MHz\n", chan->center_freq); |
| 858 | chan->flags = IEEE80211_CHAN_DISABLED; | 858 | chan->flags |= IEEE80211_CHAN_DISABLED; |
| 859 | return; | 859 | return; |
| 860 | } | 860 | } |
| 861 | 861 | ||
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 3c2033b8f596..ecd4fcec3c94 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
| @@ -1806,6 +1806,41 @@ TRACE_EVENT(rdev_update_ft_ies, | |||
| 1806 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->md) | 1806 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->md) |
| 1807 | ); | 1807 | ); |
| 1808 | 1808 | ||
| 1809 | TRACE_EVENT(rdev_crit_proto_start, | ||
| 1810 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
| 1811 | enum nl80211_crit_proto_id protocol, u16 duration), | ||
| 1812 | TP_ARGS(wiphy, wdev, protocol, duration), | ||
| 1813 | TP_STRUCT__entry( | ||
| 1814 | WIPHY_ENTRY | ||
| 1815 | WDEV_ENTRY | ||
| 1816 | __field(u16, proto) | ||
| 1817 | __field(u16, duration) | ||
| 1818 | ), | ||
| 1819 | TP_fast_assign( | ||
| 1820 | WIPHY_ASSIGN; | ||
| 1821 | WDEV_ASSIGN; | ||
| 1822 | __entry->proto = protocol; | ||
| 1823 | __entry->duration = duration; | ||
| 1824 | ), | ||
| 1825 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", proto=%x, duration=%u", | ||
| 1826 | WIPHY_PR_ARG, WDEV_PR_ARG, __entry->proto, __entry->duration) | ||
| 1827 | ); | ||
| 1828 | |||
| 1829 | TRACE_EVENT(rdev_crit_proto_stop, | ||
| 1830 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), | ||
| 1831 | TP_ARGS(wiphy, wdev), | ||
| 1832 | TP_STRUCT__entry( | ||
| 1833 | WIPHY_ENTRY | ||
| 1834 | WDEV_ENTRY | ||
| 1835 | ), | ||
| 1836 | TP_fast_assign( | ||
| 1837 | WIPHY_ASSIGN; | ||
| 1838 | WDEV_ASSIGN; | ||
| 1839 | ), | ||
| 1840 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, | ||
| 1841 | WIPHY_PR_ARG, WDEV_PR_ARG) | ||
| 1842 | ); | ||
| 1843 | |||
| 1809 | /************************************************************* | 1844 | /************************************************************* |
| 1810 | * cfg80211 exported functions traces * | 1845 | * cfg80211 exported functions traces * |
| 1811 | *************************************************************/ | 1846 | *************************************************************/ |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 37a56ee1e1ed..a7046a4333e9 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
| @@ -1155,6 +1155,26 @@ int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len, | |||
| 1155 | } | 1155 | } |
| 1156 | EXPORT_SYMBOL(cfg80211_get_p2p_attr); | 1156 | EXPORT_SYMBOL(cfg80211_get_p2p_attr); |
| 1157 | 1157 | ||
| 1158 | bool ieee80211_operating_class_to_band(u8 operating_class, | ||
| 1159 | enum ieee80211_band *band) | ||
| 1160 | { | ||
| 1161 | switch (operating_class) { | ||
| 1162 | case 112: | ||
| 1163 | case 115 ... 127: | ||
| 1164 | *band = IEEE80211_BAND_5GHZ; | ||
| 1165 | return true; | ||
| 1166 | case 81: | ||
| 1167 | case 82: | ||
| 1168 | case 83: | ||
| 1169 | case 84: | ||
| 1170 | *band = IEEE80211_BAND_2GHZ; | ||
| 1171 | return true; | ||
| 1172 | } | ||
| 1173 | |||
| 1174 | return false; | ||
| 1175 | } | ||
| 1176 | EXPORT_SYMBOL(ieee80211_operating_class_to_band); | ||
| 1177 | |||
| 1158 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | 1178 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, |
| 1159 | u32 beacon_int) | 1179 | u32 beacon_int) |
| 1160 | { | 1180 | { |
| @@ -1258,12 +1278,12 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, | |||
| 1258 | list_for_each_entry(wdev_iter, &rdev->wdev_list, list) { | 1278 | list_for_each_entry(wdev_iter, &rdev->wdev_list, list) { |
| 1259 | if (wdev_iter == wdev) | 1279 | if (wdev_iter == wdev) |
| 1260 | continue; | 1280 | continue; |
| 1261 | if (wdev_iter->netdev) { | 1281 | if (wdev_iter->iftype == NL80211_IFTYPE_P2P_DEVICE) { |
| 1262 | if (!netif_running(wdev_iter->netdev)) | ||
| 1263 | continue; | ||
| 1264 | } else if (wdev_iter->iftype == NL80211_IFTYPE_P2P_DEVICE) { | ||
| 1265 | if (!wdev_iter->p2p_started) | 1282 | if (!wdev_iter->p2p_started) |
| 1266 | continue; | 1283 | continue; |
| 1284 | } else if (wdev_iter->netdev) { | ||
| 1285 | if (!netif_running(wdev_iter->netdev)) | ||
| 1286 | continue; | ||
| 1267 | } else { | 1287 | } else { |
| 1268 | WARN_ON(1); | 1288 | WARN_ON(1); |
| 1269 | } | 1289 | } |
