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 | } |