Unified · Split
| @@ -6057,7 +6057,7 @@ il4965_mac_channel_switch(struct ieee80211_hw *hw, · 6056 unmodified lines | ||
| 6057 | 6057 | struct il_priv *il = hw->priv; |
| 6058 | 6058 | const struct il_channel_info *ch_info; |
| 6059 | 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 | 6061 | struct il_ht_config *ht_conf = &il->current_ht_config; |
| 6062 | 6062 | u16 ch; |
| 6063 | 6063 | |
| @@ -6094,23 +6094,21 @@ il4965_mac_channel_switch(struct ieee80211_hw *hw, · 30 unmodified lines | ||
| 6094 | 6094 | il->current_ht_config.smps = conf->smps_mode; |
| 6095 | 6095 | |
| 6096 | 6096 | /* Configure HT40 channels */ |
| 6097 | − il->ht.enabled = conf_is_ht(conf); | |
| 6098 | − if (il->ht.enabled) { | |
| 6099 | − if (conf_is_ht40_minus(conf)) { | |
| 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 | |
| 6097 | + switch (cfg80211_get_chandef_type(&ch_switch->chandef)) { | |
| 6098 | + case NL80211_CHAN_NO_HT: | |
| 6099 | + case NL80211_CHAN_HT20: | |
| 6113 | 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 | 6113 | if ((le16_to_cpu(il->staging.channel) != ch)) |
| 6116 | 6114 | il->staging.flags = 0; |
| @@ -1493,7 +1493,7 @@ il4965_hw_channel_switch(struct il_priv *il, · 1492 unmodified lines | ||
| 1493 | 1493 | |
| 1494 | 1494 | cmd.band = band; |
| 1495 | 1495 | cmd.expect_beacon = 0; |
| 1496 | − ch = ch_switch->channel->hw_value; | |
| 1496 | + ch = ch_switch->chandef.chan->hw_value; | |
| 1497 | 1497 | cmd.channel = cpu_to_le16(ch); |
| 1498 | 1498 | cmd.rxon_flags = il->staging.flags; |
| 1499 | 1499 | cmd.rxon_filter_flags = il->staging.filter_flags; |
| @@ -379,7 +379,7 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, · 378 unmodified lines | ||
| 379 | 379 | }; |
| 380 | 380 | |
| 381 | 381 | cmd.band = priv->band == IEEE80211_BAND_2GHZ; |
| 382 | − ch = ch_switch->channel->hw_value; | |
| 382 | + ch = ch_switch->chandef.chan->hw_value; | |
| 383 | 383 | IWL_DEBUG_11H(priv, "channel switch from %d to %d\n", |
| 384 | 384 | ctx->active.channel, ch); |
| 385 | 385 | cmd.channel = cpu_to_le16(ch); |
| @@ -414,7 +414,8 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, · 28 unmodified lines | ||
| 414 | 414 | } |
| 415 | 415 | IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", |
| 416 | 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 | 420 | return iwl_dvm_send_cmd(priv, &hcmd); |
| 420 | 421 | } |
| @@ -540,7 +541,7 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, · 119 unmodified lines | ||
| 540 | 541 | hcmd.data[0] = cmd; |
| 541 | 542 | |
| 542 | 543 | cmd->band = priv->band == IEEE80211_BAND_2GHZ; |
| 543 | − ch = ch_switch->channel->hw_value; | |
| 544 | + ch = ch_switch->chandef.chan->hw_value; | |
| 544 | 545 | IWL_DEBUG_11H(priv, "channel switch from %u to %u\n", |
| 545 | 546 | ctx->active.channel, ch); |
| 546 | 547 | cmd->channel = cpu_to_le16(ch); |
| @@ -575,7 +576,8 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, · 28 unmodified lines | ||
| 575 | 576 | } |
| 576 | 577 | IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", |
| 577 | 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 | 582 | err = iwl_dvm_send_cmd(priv, &hcmd); |
| 581 | 583 | kfree(cmd); |
| @@ -970,7 +970,7 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, · 969 unmodified lines | ||
| 970 | 970 | { |
| 971 | 971 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); |
| 972 | 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 | 974 | struct iwl_ht_config *ht_conf = &priv->current_ht_config; |
| 975 | 975 | /* |
| 976 | 976 | * MULTI-FIXME |
| @@ -1008,11 +1008,21 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, · 31 unmodified lines | ||
| 1008 | 1008 | priv->current_ht_config.smps = conf->smps_mode; |
| 1009 | 1009 | |
| 1010 | 1010 | /* Configure HT40 channels */ |
| 1011 | − ctx->ht.enabled = conf_is_ht(conf); | |
| 1012 | − if (ctx->ht.enabled) | |
| 1013 | − iwlagn_config_ht40(conf, ctx); | |
| 1014 | − else | |
| 1011 | + switch (cfg80211_get_chandef_type(&ch_switch->chandef)) { | |
| 1012 | + case NL80211_CHAN_NO_HT: | |
| 1013 | + case NL80211_CHAN_HT20: | |
| 1015 | 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 | 1027 | if ((le16_to_cpu(ctx->staging.channel) != ch)) |
| 1018 | 1028 | ctx->staging.flags = 0; |
| @@ -1160,7 +1160,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) · 1159 unmodified lines | ||
| 1160 | 1160 | } |
| 1161 | 1161 | |
| 1162 | 1162 | void iwlagn_config_ht40(struct ieee80211_conf *conf, |
| 1163 | − struct iwl_rxon_context *ctx) | |
| 1163 | + struct iwl_rxon_context *ctx) | |
| 1164 | 1164 | { |
| 1165 | 1165 | if (conf_is_ht40_minus(conf)) { |
| 1166 | 1166 | ctx->ht.extension_chan_offset = |
| @@ -25,6 +25,7 @@ · 24 unmodified lines | ||
| 25 | 25 | #include <linux/if_arp.h> |
| 26 | 26 | #include <linux/rtnetlink.h> |
| 27 | 27 | #include <linux/etherdevice.h> |
| 28 | +#include <linux/platform_device.h> | |
| 28 | 29 | #include <linux/debugfs.h> |
| 29 | 30 | #include <linux/module.h> |
| 30 | 31 | #include <linux/ktime.h> |
| @@ -52,6 +53,10 @@ static bool paged_rx = false; · 21 unmodified lines | ||
| 52 | 53 | module_param(paged_rx, bool, 0644); |
| 53 | 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 | 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, · 659 unmodified lines | ||
| 717 | 722 | rx_status.flag |= RX_FLAG_MACTIME_START; |
| 718 | 723 | rx_status.freq = chan->center_freq; |
| 719 | 724 | rx_status.band = chan->band; |
| 720 | − rx_status.rate_idx = info->control.rates[0].idx; | |
| 721 | − if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) | |
| 722 | − rx_status.flag |= RX_FLAG_HT; | |
| 725 | + if (info->control.rates[0].flags & IEEE80211_TX_RC_VHT_MCS) { | |
| 726 | + rx_status.rate_idx = | |
| 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 | 736 | if (info->control.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) |
| 724 | 737 | rx_status.flag |= RX_FLAG_40MHZ; |
| 725 | 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, · 160 unmodified lines | ||
| 886 | 899 | if (control->sta) |
| 887 | 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 | 908 | mac80211_hwsim_monitor_rx(hw, skb, channel); |
| 892 | 909 | |
| 893 | 910 | /* wmediumd mode check */ |
| @@ -989,6 +1006,13 @@ static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, · 95 unmodified lines | ||
| 989 | 1006 | { |
| 990 | 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 | 1016 | mac80211_hwsim_monitor_rx(hw, skb, chan); |
| 993 | 1017 | |
| 994 | 1018 | if (_pid) |
| @@ -1019,6 +1043,11 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, · 24 unmodified lines | ||
| 1019 | 1043 | if (skb == NULL) |
| 1020 | 1044 | return; |
| 1021 | 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 | 1051 | txrate = ieee80211_get_tx_rate(hw, info); |
| 1023 | 1052 | |
| 1024 | 1053 | mgmt = (struct ieee80211_mgmt *) skb->data; |
| @@ -1687,6 +1716,7 @@ static void mac80211_hwsim_free(void) · 662 unmodified lines | ||
| 1687 | 1716 | debugfs_remove(data->debugfs_ps); |
| 1688 | 1717 | debugfs_remove(data->debugfs); |
| 1689 | 1718 | ieee80211_unregister_hw(data->hw); |
| 1719 | + device_release_driver(data->dev); | |
| 1690 | 1720 | device_unregister(data->dev); |
| 1691 | 1721 | ieee80211_free_hw(data->hw); |
| 1692 | 1722 | } |
| @@ -1695,7 +1725,9 @@ static void mac80211_hwsim_free(void) · 2 unmodified lines | ||
| 1695 | 1725 | |
| 1696 | 1726 | |
| 1697 | 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 | 1733 | static const struct net_device_ops hwsim_netdev_ops = { |
| @@ -2187,9 +2219,15 @@ static int __init init_mac80211_hwsim(void) · 485 unmodified lines | ||
| 2187 | 2219 | spin_lock_init(&hwsim_radio_lock); |
| 2188 | 2220 | INIT_LIST_HEAD(&hwsim_radios); |
| 2189 | 2221 | |
| 2222 | + err = driver_register(&mac80211_hwsim_driver); | |
| 2223 | + if (err) | |
| 2224 | + return err; | |
| 2225 | + | |
| 2190 | 2226 | hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim"); |
| 2191 | − if (IS_ERR(hwsim_class)) | |
| 2192 | − return PTR_ERR(hwsim_class); | |
| 2227 | + if (IS_ERR(hwsim_class)) { | |
| 2228 | + err = PTR_ERR(hwsim_class); | |
| 2229 | + goto failed_unregister_driver; | |
| 2230 | + } | |
| 2193 | 2231 | |
| 2194 | 2232 | memset(addr, 0, ETH_ALEN); |
| 2195 | 2233 | addr[0] = 0x02; |
| @@ -2211,12 +2249,20 @@ static int __init init_mac80211_hwsim(void) · 15 unmodified lines | ||
| 2211 | 2249 | "hwsim%d", i); |
| 2212 | 2250 | if (IS_ERR(data->dev)) { |
| 2213 | 2251 | printk(KERN_DEBUG |
| 2214 | − "mac80211_hwsim: device_create " | |
| 2215 | − "failed (%ld)\n", PTR_ERR(data->dev)); | |
| 2252 | + "mac80211_hwsim: device_create failed (%ld)\n", | |
| 2253 | + PTR_ERR(data->dev)); | |
| 2216 | 2254 | err = -ENOMEM; |
| 2217 | 2255 | goto failed_drvdata; |
| 2218 | 2256 | } |
| 2219 | 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 | 2266 | skb_queue_head_init(&data->pending); |
| 2221 | 2267 | |
| 2222 | 2268 | SET_IEEE80211_DEV(hw, data->dev); |
| @@ -2259,6 +2305,8 @@ static int __init init_mac80211_hwsim(void) · 36 unmodified lines | ||
| 2259 | 2305 | IEEE80211_HW_AMPDU_AGGREGATION | |
| 2260 | 2306 | IEEE80211_HW_WANT_MONITOR_VIF | |
| 2261 | 2307 | IEEE80211_HW_QUEUE_CONTROL; |
| 2308 | + if (rctbl) | |
| 2309 | + hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE; | |
| 2262 | 2310 | |
| 2263 | 2311 | hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | |
| 2264 | 2312 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; |
| @@ -2515,6 +2563,8 @@ failed_drvdata: · 250 unmodified lines | ||
| 2515 | 2563 | ieee80211_free_hw(hw); |
| 2516 | 2564 | failed: |
| 2517 | 2565 | mac80211_hwsim_free(); |
| 2566 | +failed_unregister_driver: | |
| 2567 | + driver_unregister(&mac80211_hwsim_driver); | |
| 2518 | 2568 | return err; |
| 2519 | 2569 | } |
| 2520 | 2570 | module_init(init_mac80211_hwsim); |
| @@ -2527,5 +2577,6 @@ static void __exit exit_mac80211_hwsim(void) · 6 unmodified lines | ||
| 2527 | 2577 | |
| 2528 | 2578 | mac80211_hwsim_free(); |
| 2529 | 2579 | unregister_netdev(hwsim_mon); |
| 2580 | + driver_unregister(&mac80211_hwsim_driver); | |
| 2530 | 2581 | } |
| 2531 | 2582 | module_exit(exit_mac80211_hwsim); |
| @@ -301,7 +301,7 @@ int wl12xx_cmd_channel_switch(struct wl1271 *wl, · 300 unmodified lines | ||
| 301 | 301 | } |
| 302 | 302 | |
| 303 | 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 | 305 | cmd->switch_time = ch_switch->count; |
| 306 | 306 | cmd->stop_tx = ch_switch->block_tx; |
| 307 | 307 | |
| @@ -42,11 +42,11 @@ int wl18xx_cmd_channel_switch(struct wl1271 *wl, · 41 unmodified lines | ||
| 42 | 42 | } |
| 43 | 43 | |
| 44 | 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 | 46 | cmd->switch_time = ch_switch->count; |
| 47 | 47 | cmd->stop_tx = ch_switch->block_tx; |
| 48 | 48 | |
| 49 | − switch (ch_switch->channel->band) { | |
| 49 | + switch (ch_switch->chandef.chan->band) { | |
| 50 | 50 | case IEEE80211_BAND_2GHZ: |
| 51 | 51 | cmd->band = WLCORE_BAND_2_4GHZ; |
| 52 | 52 | break; |
| @@ -55,7 +55,7 @@ int wl18xx_cmd_channel_switch(struct wl1271 *wl, · 2 unmodified lines | ||
| 55 | 55 | break; |
| 56 | 56 | default: |
| 57 | 57 | wl1271_error("invalid channel switch band: %d", |
| 58 | − ch_switch->channel->band); | |
| 58 | + ch_switch->chandef.chan->band); | |
| 59 | 59 | ret = -EINVAL; |
| 60 | 60 | goto out_free; |
| 61 | 61 | } |
| @@ -672,6 +672,36 @@ struct ieee80211_channel_sw_ie { · 671 unmodified lines | ||
| 672 | 672 | u8 count; |
| 673 | 673 | } __packed; |
| 674 | 674 | |
| 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 | + | |
| 675 | 705 | /** |
| 676 | 706 | * struct ieee80211_tim |
| 677 | 707 | * |
| @@ -840,10 +870,13 @@ struct ieee80211_mgmt { · 162 unmodified lines | ||
| 840 | 870 | } __packed wme_action; |
| 841 | 871 | struct{ |
| 842 | 872 | u8 action_code; |
| 843 | − u8 element_id; | |
| 844 | − u8 length; | |
| 845 | − struct ieee80211_channel_sw_ie sw_elem; | |
| 873 | + u8 variable[0]; | |
| 846 | 874 | } __packed chan_switch; |
| 875 | + struct{ | |
| 876 | + u8 action_code; | |
| 877 | + struct ieee80211_ext_chansw_ie data; | |
| 878 | + u8 variable[0]; | |
| 879 | + } __packed ext_chan_switch; | |
| 847 | 880 | struct{ |
| 848 | 881 | u8 action_code; |
| 849 | 882 | u8 dialog_token; |
| @@ -1638,6 +1671,7 @@ enum ieee80211_eid { · 788 unmodified lines | ||
| 1638 | 1671 | |
| 1639 | 1672 | WLAN_EID_HT_CAPABILITY = 45, |
| 1640 | 1673 | WLAN_EID_HT_OPERATION = 61, |
| 1674 | + WLAN_EID_SECONDARY_CHANNEL_OFFSET = 62, | |
| 1641 | 1675 | |
| 1642 | 1676 | WLAN_EID_RSN = 48, |
| 1643 | 1677 | WLAN_EID_MMIE = 76, |
| @@ -1672,6 +1706,8 @@ enum ieee80211_eid { · 28 unmodified lines | ||
| 1672 | 1706 | WLAN_EID_VHT_CAPABILITY = 191, |
| 1673 | 1707 | WLAN_EID_VHT_OPERATION = 192, |
| 1674 | 1708 | WLAN_EID_OPMODE_NOTIF = 199, |
| 1709 | + WLAN_EID_WIDE_BW_CHANNEL_SWITCH = 194, | |
| 1710 | + WLAN_EID_CHANNEL_SWITCH_WRAPPER = 196, | |
| 1675 | 1711 | |
| 1676 | 1712 | /* 802.11ad */ |
| 1677 | 1713 | WLAN_EID_NON_TX_BSSID_CAP = 83, |
| @@ -1795,6 +1831,7 @@ enum ieee80211_key_len { · 117 unmodified lines | ||
| 1795 | 1831 | |
| 1796 | 1832 | /* Public action codes */ |
| 1797 | 1833 | enum ieee80211_pub_actioncode { |
| 1834 | + WLAN_PUB_ACTION_EXT_CHANSW_ANN = 4, | |
| 1798 | 1835 | WLAN_PUB_ACTION_TDLS_DISCOVER_RES = 14, |
| 1799 | 1836 | }; |
| 1800 | 1837 | |
| @@ -2002,6 +2002,12 @@ struct cfg80211_update_ft_ies_params { · 2001 unmodified lines | ||
| 2002 | 2002 | * @update_ft_ies: Provide updated Fast BSS Transition information to the |
| 2003 | 2003 | * driver. If the SME is in the driver/firmware, this information can be |
| 2004 | 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 | 2012 | struct cfg80211_ops { |
| 2007 | 2013 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); |
| @@ -2231,6 +2237,12 @@ struct cfg80211_ops { · 223 unmodified lines | ||
| 2231 | 2237 | struct cfg80211_chan_def *chandef); |
| 2232 | 2238 | int (*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev, |
| 2233 | 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, · 1787 unmodified lines | ||
| 4024 | 4036 | void cfg80211_ch_switch_notify(struct net_device *dev, |
| 4025 | 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 | 4051 | * cfg80211_tdls_oper_request - request userspace to perform TDLS operation |
| 4029 | 4052 | * @dev: the device on which the operation is requested |
| @@ -4126,6 +4149,17 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, · 96 unmodified lines | ||
| 4126 | 4149 | struct cfg80211_wowlan_wakeup *wakeup, |
| 4127 | 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 | 4163 | /* Logging, debugging and troubleshooting/diagnostic helpers. */ |
| 4130 | 4164 | |
| 4131 | 4165 | /* wiphy_printk helpers, similar to dev_printk */ |
| @@ -128,6 +128,7 @@ enum ieee80211_ac_numbers { · 127 unmodified lines | ||
| 128 | 128 | * 2^n-1 in the range 1..32767] |
| 129 | 129 | * @cw_max: maximum contention window [like @cw_min] |
| 130 | 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 | 132 | * @uapsd: is U-APSD mode enabled for the queue |
| 132 | 133 | */ |
| 133 | 134 | struct ieee80211_tx_queue_params { |
| @@ -135,6 +136,7 @@ struct ieee80211_tx_queue_params { · 1 unmodified line | ||
| 135 | 136 | u16 cw_min; |
| 136 | 137 | u16 cw_max; |
| 137 | 138 | u8 aifs; |
| 139 | + bool acm; | |
| 138 | 140 | bool uapsd; |
| 139 | 141 | }; |
| 140 | 142 | |
| @@ -209,7 +211,7 @@ struct ieee80211_chanctx_conf { · 68 unmodified lines | ||
| 209 | 211 | * @BSS_CHANGED_QOS: QoS for this association was enabled/disabled. Note |
| 210 | 212 | * that it is only ever disabled for station mode. |
| 211 | 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 | 215 | * @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode) |
| 214 | 216 | * @BSS_CHANGED_PS: PS changed for this BSS (STA mode) |
| 215 | 217 | * @BSS_CHANGED_TXPOWER: TX power setting changed for this interface |
| @@ -326,7 +328,7 @@ enum ieee80211_rssi_event { · 110 unmodified lines | ||
| 326 | 328 | * your driver/device needs to do. |
| 327 | 329 | * @ps: power-save mode (STA only). This flag is NOT affected by |
| 328 | 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 | 332 | * @ssid_len: Length of SSID given in @ssid. |
| 331 | 333 | * @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode. |
| 332 | 334 | * @txpower: TX power in dBm |
| @@ -561,6 +563,9 @@ enum mac80211_rate_control_flags { · 228 unmodified lines | ||
| 561 | 563 | /* maximum number of rate stages */ |
| 562 | 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 | 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, · 34 unmodified lines | ||
| 601 | 606 | u8 mcs, u8 nss) |
| 602 | 607 | { |
| 603 | 608 | WARN_ON(mcs & ~0xF); |
| 604 | − WARN_ON(nss & ~0x7); | |
| 605 | − rate->idx = (nss << 4) | mcs; | |
| 609 | + WARN_ON((nss - 1) & ~0x7); | |
| 610 | + rate->idx = ((nss - 1) << 4) | mcs; | |
| 606 | 611 | } |
| 607 | 612 | |
| 608 | 613 | static inline u8 |
| @@ -614,7 +619,7 @@ ieee80211_rate_get_vht_mcs(const struct ieee80211_tx_rate *rate) · 5 unmodified lines | ||
| 614 | 619 | static inline u8 |
| 615 | 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 { · 34 unmodified lines | ||
| 655 | 660 | struct ieee80211_tx_rate rates[ |
| 656 | 661 | IEEE80211_TX_MAX_RATES]; |
| 657 | 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 | 669 | /* only needed before rate control */ |
| 661 | 670 | unsigned long jiffies; |
| @@ -676,6 +685,8 @@ struct ieee80211_tx_info { · 14 unmodified lines | ||
| 676 | 685 | struct { |
| 677 | 686 | struct ieee80211_tx_rate driver_rates[ |
| 678 | 687 | IEEE80211_TX_MAX_RATES]; |
| 688 | + u8 pad[4]; | |
| 689 | + | |
| 679 | 690 | void *rate_driver_data[ |
| 680 | 691 | IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE / sizeof(void *)]; |
| 681 | 692 | }; |
| @@ -1017,13 +1028,13 @@ struct ieee80211_conf { · 335 unmodified lines | ||
| 1017 | 1028 | * the driver passed into mac80211. |
| 1018 | 1029 | * @block_tx: Indicates whether transmission must be blocked before the |
| 1019 | 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 | 1032 | * @count: the number of TBTT's until the channel switch event |
| 1022 | 1033 | */ |
| 1023 | 1034 | struct ieee80211_channel_switch { |
| 1024 | 1035 | u64 timestamp; |
| 1025 | 1036 | bool block_tx; |
| 1026 | − struct ieee80211_channel *channel; | |
| 1037 | + struct cfg80211_chan_def chandef; | |
| 1027 | 1038 | u8 count; |
| 1028 | 1039 | }; |
| 1029 | 1040 | |
| @@ -1220,6 +1231,24 @@ enum ieee80211_sta_rx_bandwidth { · 190 unmodified lines | ||
| 1220 | 1231 | IEEE80211_STA_RX_BW_160, |
| 1221 | 1232 | }; |
| 1222 | 1233 | |
| 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 | + | |
| 1223 | 1252 | /** |
| 1224 | 1253 | * struct ieee80211_sta - station table entry |
| 1225 | 1254 | * |
| @@ -1247,6 +1276,7 @@ enum ieee80211_sta_rx_bandwidth { · 21 unmodified lines | ||
| 1247 | 1276 | * notifications and capabilities. The value is only valid after |
| 1248 | 1277 | * the station moves to associated state. |
| 1249 | 1278 | * @smps_mode: current SMPS mode (off, static or dynamic) |
| 1279 | + * @tx_rates: rate control selection table | |
| 1250 | 1280 | */ |
| 1251 | 1281 | struct ieee80211_sta { |
| 1252 | 1282 | u32 supp_rates[IEEE80211_NUM_BANDS]; |
| @@ -1260,6 +1290,7 @@ struct ieee80211_sta { · 7 unmodified lines | ||
| 1260 | 1290 | u8 rx_nss; |
| 1261 | 1291 | enum ieee80211_sta_rx_bandwidth bandwidth; |
| 1262 | 1292 | enum ieee80211_smps_mode smps_mode; |
| 1293 | + struct ieee80211_sta_rates __rcu *rates; | |
| 1263 | 1294 | |
| 1264 | 1295 | /* must be last */ |
| 1265 | 1296 | u8 drv_priv[0] __aligned(sizeof(void *)); |
| @@ -1415,6 +1446,9 @@ struct ieee80211_tx_control { · 149 unmodified lines | ||
| 1415 | 1446 | * for different virtual interfaces. See the doc section on HW queue |
| 1416 | 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 | 1452 | * @IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF: Use the P2P Device address for any |
| 1419 | 1453 | * P2P Interface. This will be honoured even if more than one interface |
| 1420 | 1454 | * is supported. |
| @@ -1447,6 +1481,7 @@ enum ieee80211_hw_flags { · 26 unmodified lines | ||
| 1447 | 1481 | IEEE80211_HW_SUPPORTS_PER_STA_GTK = 1<<21, |
| 1448 | 1482 | IEEE80211_HW_AP_LINK_PS = 1<<22, |
| 1449 | 1483 | IEEE80211_HW_TX_AMPDU_SETUP_IN_HW = 1<<23, |
| 1484 | + IEEE80211_HW_SUPPORTS_RC_TABLE = 1<<24, | |
| 1450 | 1485 | IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF = 1<<25, |
| 1451 | 1486 | IEEE80211_HW_TIMING_BEACON_ONLY = 1<<26, |
| 1452 | 1487 | }; |
| @@ -3132,6 +3167,25 @@ static inline int ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta, · 1679 unmodified lines | ||
| 3132 | 3167 | void ieee80211_sta_set_buffered(struct ieee80211_sta *sta, |
| 3133 | 3168 | u8 tid, bool buffered); |
| 3134 | 3169 | |
| 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 | + | |
| 3135 | 3189 | /** |
| 3136 | 3190 | * ieee80211_tx_status - transmit status callback |
| 3137 | 3191 | * |
| @@ -4107,7 +4161,7 @@ void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn); · 969 unmodified lines | ||
| 4107 | 4161 | * (deprecated; this will be removed once drivers get updated to use |
| 4108 | 4162 | * rate_idx_mask) |
| 4109 | 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 | 4165 | * @bss: whether this frame is sent out in AP or IBSS mode |
| 4112 | 4166 | */ |
| 4113 | 4167 | struct ieee80211_tx_rate_control { |
| @@ -4119,7 +4173,7 @@ struct ieee80211_tx_rate_control { · 5 unmodified lines | ||
| 4119 | 4173 | bool rts, short_preamble; |
| 4120 | 4174 | u8 max_rate_idx; |
| 4121 | 4175 | u32 rate_idx_mask; |
| 4122 | − u8 rate_idx_mcs_mask[IEEE80211_HT_MCS_MASK_LEN]; | |
| 4176 | + u8 *rate_idx_mcs_mask; | |
| 4123 | 4177 | bool bss; |
| 4124 | 4178 | }; |
| 4125 | 4179 | |
| @@ -4208,6 +4262,22 @@ bool rate_usable_index_exists(struct ieee80211_supported_band *sband, · 82 unmodified lines | ||
| 4208 | 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 | 4281 | int ieee80211_rate_control_register(struct rate_control_ops *ops); |
| 4212 | 4282 | void ieee80211_rate_control_unregister(struct rate_control_ops *ops); |
| 4213 | 4283 | |
| @@ -639,6 +639,13 @@ · 638 unmodified lines | ||
| 639 | 639 | * with the relevant Information Elements. This event is used to report |
| 640 | 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 | 649 | * @NL80211_CMD_MAX: highest used command number |
| 643 | 650 | * @__NL80211_CMD_AFTER_LAST: internal use |
| 644 | 651 | */ |
| @@ -798,6 +805,9 @@ enum nl80211_commands { · 153 unmodified lines | ||
| 798 | 805 | NL80211_CMD_UPDATE_FT_IES, |
| 799 | 806 | NL80211_CMD_FT_EVENT, |
| 800 | 807 | |
| 808 | + NL80211_CMD_CRIT_PROTOCOL_START, | |
| 809 | + NL80211_CMD_CRIT_PROTOCOL_STOP, | |
| 810 | + | |
| 801 | 811 | /* add new commands above here */ |
| 802 | 812 | |
| 803 | 813 | /* used to define NL80211_CMD_MAX below */ |
| @@ -1414,6 +1424,11 @@ enum nl80211_commands { · 610 unmodified lines | ||
| 1414 | 1424 | * @NL80211_ATTR_IE_RIC: Resource Information Container Information |
| 1415 | 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 | 1432 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
| 1418 | 1433 | * @__NL80211_ATTR_AFTER_LAST: internal use |
| 1419 | 1434 | */ |
| @@ -1709,6 +1724,9 @@ enum nl80211_attrs { · 289 unmodified lines | ||
| 1709 | 1724 | NL80211_ATTR_MDID, |
| 1710 | 1725 | NL80211_ATTR_IE_RIC, |
| 1711 | 1726 | |
| 1727 | + NL80211_ATTR_CRIT_PROT_ID, | |
| 1728 | + NL80211_ATTR_MAX_CRIT_PROT_DURATION, | |
| 1729 | + | |
| 1712 | 1730 | /* add attributes here, update the policy in nl80211.c */ |
| 1713 | 1731 | |
| 1714 | 1732 | __NL80211_ATTR_AFTER_LAST, |
| @@ -3682,4 +3700,25 @@ enum nl80211_protocol_features { · 1967 unmodified lines | ||
| 3682 | 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 | 3724 | #endif /* __LINUX_NL80211_H */ |
| @@ -1043,6 +1043,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) · 1042 unmodified lines | ||
| 1043 | 1043 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) |
| 1044 | 1044 | sta_info_flush_defer(vlan); |
| 1045 | 1045 | sta_info_flush_defer(sdata); |
| 1046 | + synchronize_net(); | |
| 1046 | 1047 | rcu_barrier(); |
| 1047 | 1048 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { |
| 1048 | 1049 | sta_info_flush_cleanup(vlan); |
| @@ -1052,6 +1053,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) · 3 unmodified lines | ||
| 1052 | 1053 | ieee80211_free_keys(sdata); |
| 1053 | 1054 | |
| 1054 | 1055 | sdata->vif.bss_conf.enable_beacon = false; |
| 1056 | + sdata->vif.bss_conf.ssid_len = 0; | |
| 1055 | 1057 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); |
| 1056 | 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, · 1358 unmodified lines | ||
| 2416 | 2418 | } |
| 2417 | 2419 | |
| 2418 | 2420 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { |
| 2421 | + struct ieee80211_supported_band *sband = wiphy->bands[i]; | |
| 2422 | + int j; | |
| 2423 | + | |
| 2419 | 2424 | sdata->rc_rateidx_mask[i] = mask->control[i].legacy; |
| 2420 | 2425 | memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].mcs, |
| 2421 | 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 | 2439 | return 0; |
| @@ -57,6 +57,22 @@ ieee80211_find_chanctx(struct ieee80211_local *local, · 56 unmodified lines | ||
| 57 | 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 | 76 | static struct ieee80211_chanctx * |
| 61 | 77 | ieee80211_new_chanctx(struct ieee80211_local *local, |
| 62 | 78 | const struct cfg80211_chan_def *chandef, |
| @@ -76,6 +92,9 @@ ieee80211_new_chanctx(struct ieee80211_local *local, · 13 unmodified lines | ||
| 76 | 92 | ctx->conf.rx_chains_static = 1; |
| 77 | 93 | ctx->conf.rx_chains_dynamic = 1; |
| 78 | 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 | 99 | /* acquire mutex to prevent idle from changing */ |
| 81 | 100 | mutex_lock(&local->mtx); |
| @@ -110,6 +129,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local, · 28 unmodified lines | ||
| 110 | 129 | static void ieee80211_free_chanctx(struct ieee80211_local *local, |
| 111 | 130 | struct ieee80211_chanctx *ctx) |
| 112 | 131 | { |
| 132 | + bool check_single_channel = false; | |
| 113 | 133 | lockdep_assert_held(&local->chanctx_mtx); |
| 114 | 134 | |
| 115 | 135 | WARN_ON_ONCE(ctx->refcount != 0); |
| @@ -119,6 +139,14 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local, · 3 unmodified lines | ||
| 119 | 139 | chandef->width = NL80211_CHAN_WIDTH_20_NOHT; |
| 120 | 140 | chandef->center_freq1 = chandef->chan->center_freq; |
| 121 | 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 | 150 | ieee80211_hw_config(local, 0); |
| 123 | 151 | } else { |
| 124 | 152 | drv_remove_chanctx(local, ctx); |
| @@ -127,6 +155,9 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local, · 2 unmodified lines | ||
| 127 | 155 | list_del_rcu(&ctx->list); |
| 128 | 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 | 161 | mutex_lock(&local->mtx); |
| 131 | 162 | ieee80211_recalc_idle(local); |
| 132 | 163 | mutex_unlock(&local->mtx); |
| @@ -238,19 +269,11 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) · 105 unmodified lines | ||
| 238 | 269 | void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, |
| 239 | 270 | struct ieee80211_chanctx *chanctx) |
| 240 | 271 | { |
| 241 | − struct ieee80211_sub_if_data *sdata; | |
| 242 | − bool radar_enabled = false; | |
| 272 | + bool radar_enabled; | |
| 243 | 273 | |
| 244 | 274 | lockdep_assert_held(&local->chanctx_mtx); |
| 245 | 275 | |
| 246 | − rcu_read_lock(); | |
| 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(); | |
| 276 | + radar_enabled = ieee80211_is_radar_required(local); | |
| 254 | 277 | |
| 255 | 278 | if (radar_enabled == chanctx->conf.radar_enabled) |
| 256 | 279 | return; |
| @@ -209,6 +209,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, · 208 unmodified lines | ||
| 209 | 209 | sdata->vif.bss_conf.enable_beacon = true; |
| 210 | 210 | sdata->vif.bss_conf.beacon_int = beacon_int; |
| 211 | 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 | 214 | bss_change = BSS_CHANGED_BEACON_INT; |
| 213 | 215 | bss_change |= ieee80211_reset_erp_info(sdata); |
| 214 | 216 | bss_change |= BSS_CHANGED_BSSID; |
| @@ -217,6 +219,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, · 2 unmodified lines | ||
| 217 | 219 | bss_change |= BSS_CHANGED_BASIC_RATES; |
| 218 | 220 | bss_change |= BSS_CHANGED_HT; |
| 219 | 221 | bss_change |= BSS_CHANGED_IBSS; |
| 222 | + bss_change |= BSS_CHANGED_SSID; | |
| 220 | 223 | |
| 221 | 224 | /* |
| 222 | 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, · 688 unmodified lines | ||
| 911 | 914 | return; |
| 912 | 915 | |
| 913 | 916 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, |
| 914 | − &elems); | |
| 917 | + false, &elems); | |
| 915 | 918 | |
| 916 | 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) · 241 unmodified lines | ||
| 1159 | 1162 | sdata->vif.bss_conf.ibss_joined = false; |
| 1160 | 1163 | sdata->vif.bss_conf.ibss_creator = false; |
| 1161 | 1164 | sdata->vif.bss_conf.enable_beacon = false; |
| 1165 | + sdata->vif.bss_conf.ssid_len = 0; | |
| 1162 | 1166 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); |
| 1163 | 1167 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | |
| 1164 | 1168 | BSS_CHANGED_IBSS); |
| @@ -156,6 +156,7 @@ struct ieee80211_tx_data { · 155 unmodified lines | ||
| 156 | 156 | struct ieee80211_sub_if_data *sdata; |
| 157 | 157 | struct sta_info *sta; |
| 158 | 158 | struct ieee80211_key *key; |
| 159 | + struct ieee80211_tx_rate rate; | |
| 159 | 160 | |
| 160 | 161 | unsigned int flags; |
| 161 | 162 | }; |
| @@ -740,6 +741,8 @@ struct ieee80211_sub_if_data { · 578 unmodified lines | ||
| 740 | 741 | |
| 741 | 742 | /* bitmap of allowed (non-MCS) rate indexes for rate control */ |
| 742 | 743 | u32 rc_rateidx_mask[IEEE80211_NUM_BANDS]; |
| 744 | + | |
| 745 | + bool rc_has_mcs_mask[IEEE80211_NUM_BANDS]; | |
| 743 | 746 | u8 rc_rateidx_mcs_mask[IEEE80211_NUM_BANDS][IEEE80211_HT_MCS_MASK_LEN]; |
| 744 | 747 | |
| 745 | 748 | union { |
| @@ -1020,7 +1023,7 @@ struct ieee80211_local { · 274 unmodified lines | ||
| 1020 | 1023 | enum mac80211_scan_state next_scan_state; |
| 1021 | 1024 | struct delayed_work scan_work; |
| 1022 | 1025 | struct ieee80211_sub_if_data __rcu *scan_sdata; |
| 1023 | − struct ieee80211_channel *csa_channel; | |
| 1026 | + struct cfg80211_chan_def csa_chandef; | |
| 1024 | 1027 | /* For backward compatibility only -- do not use */ |
| 1025 | 1028 | struct cfg80211_chan_def _oper_chandef; |
| 1026 | 1029 | |
| @@ -1179,10 +1182,13 @@ struct ieee802_11_elems { · 152 unmodified lines | ||
| 1179 | 1182 | const u8 *perr; |
| 1180 | 1183 | const struct ieee80211_rann_ie *rann; |
| 1181 | 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 | 1187 | const u8 *country_elem; |
| 1183 | 1188 | const u8 *pwr_constr_elem; |
| 1184 | 1189 | const struct ieee80211_timeout_interval_ie *timeout_int; |
| 1185 | 1190 | const u8 *opmode_notif; |
| 1191 | + const struct ieee80211_sec_chan_offs_ie *sec_chan_offs; | |
| 1186 | 1192 | |
| 1187 | 1193 | /* length of them, respectively */ |
| 1188 | 1194 | u8 ssid_len; |
| @@ -1253,10 +1259,6 @@ void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata); · 64 unmodified lines | ||
| 1253 | 1259 | int ieee80211_max_network_latency(struct notifier_block *nb, |
| 1254 | 1260 | unsigned long data, void *dummy); |
| 1255 | 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 | 1262 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata); |
| 1261 | 1263 | void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
| 1262 | 1264 | struct sk_buff *skb); |
| @@ -1494,13 +1496,13 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, · 231 unmodified lines | ||
| 1494 | 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 | 1500 | struct ieee802_11_elems *elems, |
| 1499 | 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 | 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 | 1508 | u32 ieee80211_mandatory_rates(struct ieee80211_local *local, |
| @@ -839,11 +839,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, · 838 unmodified lines | ||
| 839 | 839 | * |
| 840 | 840 | * sta_info_flush_cleanup() requires rcu_barrier() |
| 841 | 841 | * first to wait for the station call_rcu() calls |
| 842 | − * to complete, here we need at least sychronize_rcu() | |
| 843 | − * it to wait for the RX path in case it is using the | |
| 842 | + * to complete, and we also need synchronize_rcu() | |
| 843 | + * to wait for the RX path in case it is using the | |
| 844 | 844 | * interface and enqueuing frames at this very time on |
| 845 | 845 | * another CPU. |
| 846 | 846 | */ |
| 847 | + synchronize_rcu(); | |
| 847 | 848 | rcu_barrier(); |
| 848 | 849 | sta_info_flush_cleanup(sdata); |
| 849 | 850 | |
| @@ -668,6 +668,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) · 667 unmodified lines | ||
| 668 | 668 | int channels, max_bitrates; |
| 669 | 669 | bool supp_ht, supp_vht; |
| 670 | 670 | netdev_features_t feature_whitelist; |
| 671 | + struct cfg80211_chan_def dflt_chandef = {}; | |
| 671 | 672 | static const u32 cipher_suites[] = { |
| 672 | 673 | /* keep WEP first, it may be removed below */ |
| 673 | 674 | WLAN_CIPHER_SUITE_WEP40, |
| @@ -745,19 +746,19 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) · 71 unmodified lines | ||
| 745 | 746 | sband = local->hw.wiphy->bands[band]; |
| 746 | 747 | if (!sband) |
| 747 | 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 | 754 | /* init channel we're on */ |
| 750 | − struct cfg80211_chan_def chandef = { | |
| 751 | − .chan = &sband->channels[0], | |
| 752 | − .width = NL80211_CHAN_NO_HT, | |
| 753 | − .center_freq1 = sband->channels[0].center_freq, | |
| 754 | − .center_freq2 = 0 | |
| 755 | − }; | |
| 756 | − local->hw.conf.chandef = local->_oper_chandef = chandef; | |
| 755 | + if (!local->use_chanctx && !local->_oper_chandef.chan) { | |
| 756 | + local->hw.conf.chandef = dflt_chandef; | |
| 757 | + local->_oper_chandef = dflt_chandef; | |
| 758 | + } | |
| 759 | + local->monitor_chandef = dflt_chandef; | |
| 757 | 760 | } |
| 758 | − cfg80211_chandef_create(&local->monitor_chandef, | |
| 759 | − &sband->channels[0], | |
| 760 | − NL80211_CHAN_NO_HT); | |
| 761 | + | |
| 761 | 762 | channels += sband->n_channels; |
| 762 | 763 | |
| 763 | 764 | if (max_bitrates < sband->n_bitrates) |
| @@ -838,7 +838,7 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata, · 837 unmodified lines | ||
| 838 | 838 | if (baselen > len) |
| 839 | 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 | 843 | /* 802.11-2012 10.1.4.3.2 */ |
| 844 | 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, · 54 unmodified lines | ||
| 899 | 899 | return; |
| 900 | 900 | |
| 901 | 901 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, |
| 902 | − &elems); | |
| 902 | + false, &elems); | |
| 903 | 903 | |
| 904 | 904 | /* ignore non-mesh or secure / unsecure mismatch */ |
| 905 | 905 | if ((!elems.mesh_id || !elems.mesh_config) || |
| @@ -880,7 +880,7 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, · 879 unmodified lines | ||
| 880 | 880 | |
| 881 | 881 | baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt; |
| 882 | 882 | ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, |
| 883 | − len - baselen, &elems); | |
| 883 | + len - baselen, false, &elems); | |
| 884 | 884 | |
| 885 | 885 | if (elems.preq) { |
| 886 | 886 | if (elems.preq_len != 37) |
| @@ -544,8 +544,8 @@ static void mesh_plink_timer(unsigned long data) · 543 unmodified lines | ||
| 544 | 544 | return; |
| 545 | 545 | } |
| 546 | 546 | mpl_dbg(sta->sdata, |
| 547 | − "Mesh plink timer for %pM fired on state %d\n", | |
| 548 | − sta->sta.addr, sta->plink_state); | |
| 547 | + "Mesh plink timer for %pM fired on state %s\n", | |
| 548 | + sta->sta.addr, mplstates[sta->plink_state]); | |
| 549 | 549 | reason = 0; |
| 550 | 550 | llid = sta->llid; |
| 551 | 551 | plid = sta->plid; |
| @@ -687,7 +687,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, · 135 unmodified lines | ||
| 687 | 687 | baseaddr += 4; |
| 688 | 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 | 692 | if (!elems.peering) { |
| 693 | 693 | mpl_dbg(sdata, |
| @@ -289,6 +289,8 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, · 288 unmodified lines | ||
| 289 | 289 | } else { |
| 290 | 290 | /* 40 MHz (and 80 MHz) must be supported for VHT */ |
| 291 | 291 | ret = IEEE80211_STA_DISABLE_VHT; |
| 292 | + /* also mark 40 MHz disabled */ | |
| 293 | + ret |= IEEE80211_STA_DISABLE_40MHZ; | |
| 292 | 294 | goto out; |
| 293 | 295 | } |
| 294 | 296 | |
| @@ -303,12 +305,6 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, · 8 unmodified lines | ||
| 303 | 305 | channel->band); |
| 304 | 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 | 308 | switch (vht_oper->chan_width) { |
| 313 | 309 | case IEEE80211_VHT_CHANWIDTH_USE_HT: |
| 314 | 310 | vht_chandef.width = chandef->width; |
| @@ -321,6 +317,10 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, · 6 unmodified lines | ||
| 321 | 317 | break; |
| 322 | 318 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: |
| 323 | 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 | 324 | break; |
| 325 | 325 | default: |
| 326 | 326 | if (verbose) |
| @@ -604,7 +604,6 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, · 277 unmodified lines | ||
| 604 | 604 | u8 *pos; |
| 605 | 605 | u32 cap; |
| 606 | 606 | struct ieee80211_sta_vht_cap vht_cap; |
| 607 | − int i; | |
| 608 | 607 | |
| 609 | 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, · 21 unmodified lines | ||
| 632 | 631 | cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE))) |
| 633 | 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 | 634 | /* reserve and fill IE */ |
| 667 | 635 | pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); |
| 668 | 636 | ieee80211_ie_build_vht_cap(pos, &vht_cap, cap); |
| @@ -998,16 +966,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) · 329 unmodified lines | ||
| 998 | 966 | if (!ifmgd->associated) |
| 999 | 967 | goto out; |
| 1000 | 968 | |
| 1001 | − /* | |
| 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; | |
| 969 | + local->_oper_chandef = local->csa_chandef; | |
| 1011 | 970 | |
| 1012 | 971 | if (!local->ops->channel_switch) { |
| 1013 | 972 | /* call "hw_config" only if doing sw channel switch */ |
| @@ -1054,56 +1013,193 @@ static void ieee80211_chswitch_timer(unsigned long data) · 40 unmodified lines | ||
| 1054 | 1013 | ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.chswitch_work); |
| 1055 | 1014 | } |
| 1056 | 1015 | |
| 1057 | −void | |
| 1016 | +static void | |
| 1058 | 1017 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, |
| 1059 | − const struct ieee80211_channel_sw_ie *sw_elem, | |
| 1060 | − struct ieee80211_bss *bss, u64 timestamp) | |
| 1018 | + u64 timestamp, struct ieee802_11_elems *elems) | |
| 1061 | 1019 | { |
| 1062 | − struct cfg80211_bss *cbss = | |
| 1063 | − container_of((void *)bss, struct cfg80211_bss, priv); | |
| 1064 | − struct ieee80211_channel *new_ch; | |
| 1020 | + struct ieee80211_local *local = sdata->local; | |
| 1065 | 1021 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 1066 | − int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num, | |
| 1067 | − cbss->channel->band); | |
| 1022 | + struct cfg80211_bss *cbss = ifmgd->associated; | |
| 1023 | + struct ieee80211_bss *bss; | |
| 1068 | 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 | 1037 | ASSERT_MGD_MTX(ifmgd); |
| 1071 | 1038 | |
| 1072 | − if (!ifmgd->associated) | |
| 1039 | + if (!cbss) | |
| 1073 | 1040 | return; |
| 1074 | 1041 | |
| 1075 | − if (sdata->local->scanning) | |
| 1042 | + if (local->scanning) | |
| 1076 | 1043 | return; |
| 1077 | 1044 | |
| 1078 | − /* Disregard subsequent beacons if we are already running a timer | |
| 1079 | − processing a CSA */ | |
| 1080 | − | |
| 1045 | + /* disregard subsequent announcements if we are already processing */ | |
| 1081 | 1046 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) |
| 1082 | 1047 | return; |
| 1083 | 1048 | |
| 1084 | − new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); | |
| 1085 | − if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) { | |
| 1049 | + sec_chan_offs = elems->sec_chan_offs; | |
| 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 | 1089 | sdata_info(sdata, |
| 1087 | 1090 | "AP %pM switches to unsupported channel (%d MHz), disconnecting\n", |
| 1088 | 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 | 1186 | &ifmgd->csa_connection_drop_work); |
| 1091 | 1187 | return; |
| 1092 | 1188 | } |
| 1093 | 1189 | |
| 1094 | 1190 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; |
| 1095 | 1191 | |
| 1096 | − if (sdata->local->use_chanctx) { | |
| 1192 | + if (local->use_chanctx) { | |
| 1097 | 1193 | sdata_info(sdata, |
| 1098 | 1194 | "not handling channel switch with channel contexts\n"); |
| 1099 | − ieee80211_queue_work(&sdata->local->hw, | |
| 1195 | + ieee80211_queue_work(&local->hw, | |
| 1100 | 1196 | &ifmgd->csa_connection_drop_work); |
| 1101 | 1197 | return; |
| 1102 | 1198 | } |
| 1103 | 1199 | |
| 1104 | − mutex_lock(&sdata->local->chanctx_mtx); | |
| 1200 | + mutex_lock(&local->chanctx_mtx); | |
| 1105 | 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 | 1203 | return; |
| 1108 | 1204 | } |
| 1109 | 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, · 1 unmodified line | ||
| 1111 | 1207 | if (chanctx->refcount > 1) { |
| 1112 | 1208 | sdata_info(sdata, |
| 1113 | 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 | 1211 | &ifmgd->csa_connection_drop_work); |
| 1116 | − mutex_unlock(&sdata->local->chanctx_mtx); | |
| 1212 | + mutex_unlock(&local->chanctx_mtx); | |
| 1117 | 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) | |
| 1124 | − ieee80211_stop_queues_by_reason(&sdata->local->hw, | |
| 1219 | + if (mode) | |
| 1220 | + ieee80211_stop_queues_by_reason(&local->hw, | |
| 1125 | 1221 | IEEE80211_MAX_QUEUE_MAP, |
| 1126 | 1222 | IEEE80211_QUEUE_STOP_REASON_CSA); |
| 1127 | 1223 | |
| 1128 | − if (sdata->local->ops->channel_switch) { | |
| 1224 | + if (local->ops->channel_switch) { | |
| 1129 | 1225 | /* use driver's channel switch callback */ |
| 1130 | 1226 | struct ieee80211_channel_switch ch_switch = { |
| 1131 | 1227 | .timestamp = timestamp, |
| 1132 | − .block_tx = sw_elem->mode, | |
| 1133 | − .channel = new_ch, | |
| 1134 | − .count = sw_elem->count, | |
| 1228 | + .block_tx = mode, | |
| 1229 | + .chandef = new_chandef, | |
| 1230 | + .count = count, | |
| 1135 | 1231 | }; |
| 1136 | 1232 | |
| 1137 | − drv_channel_switch(sdata->local, &ch_switch); | |
| 1233 | + drv_channel_switch(local, &ch_switch); | |
| 1138 | 1234 | return; |
| 1139 | 1235 | } |
| 1140 | 1236 | |
| 1141 | 1237 | /* channel switch handled in software */ |
| 1142 | − if (sw_elem->count <= 1) | |
| 1143 | − ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); | |
| 1238 | + if (count <= 1) | |
| 1239 | + ieee80211_queue_work(&local->hw, &ifmgd->chswitch_work); | |
| 1144 | 1240 | else |
| 1145 | 1241 | mod_timer(&ifmgd->chswitch_timer, |
| 1146 | − TU_TO_EXP_TIME(sw_elem->count * | |
| 1147 | − cbss->beacon_interval)); | |
| 1242 | + TU_TO_EXP_TIME(count * cbss->beacon_interval)); | |
| 1148 | 1243 | } |
| 1149 | 1244 | |
| 1150 | 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, · 415 unmodified lines | ||
| 1566 | 1661 | params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); |
| 1567 | 1662 | params.cw_min = ecw2cw(pos[1] & 0x0f); |
| 1568 | 1663 | params.txop = get_unaligned_le16(pos + 2); |
| 1664 | + params.acm = acm; | |
| 1569 | 1665 | params.uapsd = uapsd; |
| 1570 | 1666 | |
| 1571 | 1667 | mlme_dbg(sdata, |
| @@ -2120,7 +2216,6 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif) · 548 unmodified lines | ||
| 2120 | 2216 | |
| 2121 | 2217 | trace_api_beacon_loss(sdata); |
| 2122 | 2218 | |
| 2123 | − WARN_ON(hw->flags & IEEE80211_HW_CONNECTION_MONITOR); | |
| 2124 | 2219 | sdata->u.mgd.connection_loss = false; |
| 2125 | 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, · 43 unmodified lines | ||
| 2170 | 2265 | u32 tx_flags = 0; |
| 2171 | 2266 | |
| 2172 | 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 | 2269 | if (!elems.challenge) |
| 2175 | 2270 | return; |
| 2176 | 2271 | auth_data->expected_transaction = 4; |
| @@ -2435,7 +2530,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, · 258 unmodified lines | ||
| 2435 | 2530 | } |
| 2436 | 2531 | |
| 2437 | 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 | 2535 | if (!elems.supp_rates) { |
| 2441 | 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, · 162 unmodified lines | ||
| 2604 | 2699 | capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); |
| 2605 | 2700 | |
| 2606 | 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 | 2704 | if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && |
| 2610 | 2705 | elems.timeout_int && |
| @@ -2659,6 +2754,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, · 48 unmodified lines | ||
| 2659 | 2754 | struct ieee80211_channel *channel; |
| 2660 | 2755 | bool need_ps = false; |
| 2661 | 2756 | |
| 2757 | + lockdep_assert_held(&sdata->u.mgd.mtx); | |
| 2758 | + | |
| 2662 | 2759 | if ((sdata->u.mgd.associated && |
| 2663 | 2760 | ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) || |
| 2664 | 2761 | (sdata->u.mgd.assoc_data && |
| @@ -2689,7 +2786,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, · 24 unmodified lines | ||
| 2689 | 2786 | if (bss) |
| 2690 | 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 | 2791 | return; |
| 2694 | 2792 | |
| 2695 | 2793 | if (need_ps) { |
| @@ -2698,10 +2796,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, · 2 unmodified lines | ||
| 2698 | 2796 | mutex_unlock(&local->iflist_mtx); |
| 2699 | 2797 | } |
| 2700 | 2798 | |
| 2701 | − if (elems->ch_switch_ie && | |
| 2702 | − memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, ETH_ALEN) == 0) | |
| 2703 | − ieee80211_sta_process_chanswitch(sdata, elems->ch_switch_ie, | |
| 2704 | − bss, rx_status->mactime); | |
| 2799 | + ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, elems); | |
| 2800 | + | |
| 2705 | 2801 | } |
| 2706 | 2802 | |
| 2707 | 2803 | |
| @@ -2726,7 +2822,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, · 18 unmodified lines | ||
| 2726 | 2822 | return; |
| 2727 | 2823 | |
| 2728 | 2824 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, |
| 2729 | − &elems); | |
| 2825 | + false, &elems); | |
| 2730 | 2826 | |
| 2731 | 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, · 76 unmodified lines | ||
| 2809 | 2905 | if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon && |
| 2810 | 2906 | ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) { |
| 2811 | 2907 | ieee802_11_parse_elems(mgmt->u.beacon.variable, |
| 2812 | − len - baselen, &elems); | |
| 2908 | + len - baselen, false, &elems); | |
| 2813 | 2909 | |
| 2814 | 2910 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); |
| 2815 | 2911 | ifmgd->assoc_data->have_beacon = true; |
| @@ -2919,7 +3015,7 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, · 103 unmodified lines | ||
| 2919 | 3015 | |
| 2920 | 3016 | ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); |
| 2921 | 3017 | ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, |
| 2922 | − len - baselen, &elems, | |
| 3018 | + len - baselen, false, &elems, | |
| 2923 | 3019 | care_about_ies, ncrc); |
| 2924 | 3020 | |
| 2925 | 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, · 140 unmodified lines | ||
| 3066 | 3162 | enum rx_mgmt_action rma = RX_MGMT_NONE; |
| 3067 | 3163 | u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
| 3068 | 3164 | u16 fc; |
| 3165 | + struct ieee802_11_elems elems; | |
| 3166 | + int ies_len; | |
| 3069 | 3167 | |
| 3070 | 3168 | rx_status = (struct ieee80211_rx_status *) skb->cb; |
| 3071 | 3169 | mgmt = (struct ieee80211_mgmt *) skb->data; |
| @@ -3095,14 +3193,48 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, · 23 unmodified lines | ||
| 3095 | 3193 | rma = ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, &bss); |
| 3096 | 3194 | break; |
| 3097 | 3195 | case IEEE80211_STYPE_ACTION: |
| 3098 | − switch (mgmt->u.action.category) { | |
| 3099 | − case WLAN_CATEGORY_SPECTRUM_MGMT: | |
| 3196 | + if (mgmt->u.action.category == 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 | 3211 | ieee80211_sta_process_chanswitch(sdata, |
| 3101 | − &mgmt->u.action.u.chan_switch.sw_elem, | |
| 3102 | − (void *)ifmgd->associated->priv, | |
| 3103 | − rx_status->mactime); | |
| 3104 | − break; | |
| 3212 | + rx_status->mactime, | |
| 3213 | + &elems); | |
| 3214 | + } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { | |
| 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 | 3239 | mutex_unlock(&ifmgd->mtx); |
| 3108 | 3240 | |
| @@ -37,8 +37,9 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) · 36 unmodified lines | ||
| 37 | 37 | IEEE80211_MAX_QUEUE_MAP, |
| 38 | 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 | 41 | synchronize_net(); |
| 42 | + rcu_barrier(); | |
| 42 | 43 | |
| 43 | 44 | ieee80211_flush_queues(local, NULL); |
| 44 | 45 | |
| @@ -252,6 +252,25 @@ rate_lowest_non_cck_index(struct ieee80211_supported_band *sband, · 251 unmodified lines | ||
| 252 | 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 | 275 | bool rate_control_send_low(struct ieee80211_sta *sta, |
| 257 | 276 | void *priv_sta, |
| @@ -262,16 +281,8 @@ bool rate_control_send_low(struct ieee80211_sta *sta, · 4 unmodified lines | ||
| 262 | 281 | int mcast_rate; |
| 263 | 282 | |
| 264 | 283 | if (!sta || !priv_sta || rc_no_data_or_no_ack_use_min(txrc)) { |
| 265 | − if ((sband->band != IEEE80211_BAND_2GHZ) || | |
| 266 | − !(info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)) | |
| 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; | |
| 284 | + __rate_control_send_low(txrc->hw, sband, sta, info); | |
| 285 | + | |
| 275 | 286 | if (!sta && txrc->bss) { |
| 276 | 287 | mcast_rate = txrc->bss_conf->mcast_rate[sband->band]; |
| 277 | 288 | if (mcast_rate > 0) { |
| @@ -355,7 +366,8 @@ static bool rate_idx_match_mcs_mask(struct ieee80211_tx_rate *rate, · 77 unmodified lines | ||
| 355 | 366 | |
| 356 | 367 | |
| 357 | 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 | 371 | u32 mask, |
| 360 | 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, · 13 unmodified lines | ||
| 375 | 387 | IEEE80211_TX_RC_USE_SHORT_PREAMBLE); |
| 376 | 388 | alt_rate.count = rate->count; |
| 377 | 389 | if (rate_idx_match_legacy_mask(&alt_rate, |
| 378 | − txrc->sband->n_bitrates, | |
| 379 | − mask)) { | |
| 390 | + sband->n_bitrates, mask)) { | |
| 380 | 391 | *rate = alt_rate; |
| 381 | 392 | return; |
| 382 | 393 | } |
| 383 | 394 | } else { |
| 384 | − struct sk_buff *skb = txrc->skb; | |
| 385 | − struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | |
| 386 | − __le16 fc; | |
| 387 | − | |
| 388 | 395 | /* handle legacy rates */ |
| 389 | − if (rate_idx_match_legacy_mask(rate, txrc->sband->n_bitrates, | |
| 390 | − mask)) | |
| 396 | + if (rate_idx_match_legacy_mask(rate, sband->n_bitrates, mask)) | |
| 391 | 397 | return; |
| 392 | 398 | |
| 393 | 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) | |
| 395 | − return; | |
| 396 | − | |
| 397 | − fc = hdr->frame_control; | |
| 398 | − if (!ieee80211_is_data(fc)) | |
| 400 | + if (chan_width == NL80211_CHAN_WIDTH_20_NOHT) | |
| 399 | 401 | return; |
| 400 | 402 | |
| 401 | 403 | alt_rate.idx = 0; |
| @@ -408,7 +410,7 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, · 6 unmodified lines | ||
| 408 | 410 | |
| 409 | 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 | 414 | alt_rate.flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; |
| 413 | 415 | |
| 414 | 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, · 11 unmodified lines | ||
| 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 | 653 | void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, |
| 430 | 654 | struct sta_info *sta, |
| 431 | 655 | struct ieee80211_tx_rate_control *txrc) |
| @@ -435,8 +659,6 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, · 3 unmodified lines | ||
| 435 | 659 | struct ieee80211_sta *ista = NULL; |
| 436 | 660 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); |
| 437 | 661 | int i; |
| 438 | − u32 mask; | |
| 439 | − u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]; | |
| 440 | 662 | |
| 441 | 663 | if (sta && test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) { |
| 442 | 664 | ista = &sta->sta; |
| @@ -454,37 +676,27 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, · 11 unmodified lines | ||
| 454 | 676 | |
| 455 | 677 | ref->ops->get_rate(ref->priv, ista, priv_sta, txrc); |
| 456 | 678 | |
| 457 | − /* | |
| 458 | − * Try to enforce the rateidx mask the user wanted. skip this if the | |
| 459 | − * default mask (allow all rates) is used to save some processing for | |
| 460 | − * the common case. | |
| 461 | − */ | |
| 462 | − mask = sdata->rc_rateidx_mask[info->band]; | |
| 463 | − memcpy(mcs_mask, sdata->rc_rateidx_mcs_mask[info->band], | |
| 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 | − } | |
| 679 | + if (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_RC_TABLE) | |
| 680 | + return; | |
| 681 | + | |
| 682 | + ieee80211_get_tx_rates(&sdata->vif, ista, txrc->skb, | |
| 683 | + info->control.rates, | |
| 684 | + ARRAY_SIZE(info->control.rates)); | |
| 685 | +} | |
| 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 | 701 | int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, |
| 490 | 702 | const char *name) |
| @@ -83,6 +83,50 @@ minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list) · 82 unmodified lines | ||
| 83 | 83 | tp_list[j] = i; |
| 84 | 84 | } |
| 85 | 85 | |
| 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 | + | |
| 86 | 130 | static void |
| 87 | 131 | minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) |
| 88 | 132 | { |
| @@ -161,6 +205,8 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) · 72 unmodified lines | ||
| 161 | 205 | |
| 162 | 206 | /* Reset update timer */ |
| 163 | 207 | mi->stats_update = jiffies; |
| 208 | + | |
| 209 | + minstrel_update_rates(mp, mi); | |
| 164 | 210 | } |
| 165 | 211 | |
| 166 | 212 | static void |
| @@ -209,9 +255,9 @@ minstrel_get_retry_count(struct minstrel_rate *mr, · 42 unmodified lines | ||
| 209 | 255 | { |
| 210 | 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 | 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 | 261 | retry = max(2U, min(mr->retry_count_cts, retry)); |
| 216 | 262 | return retry; |
| 217 | 263 | } |
| @@ -240,13 +286,12 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, · 22 unmodified lines | ||
| 240 | 286 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 241 | 287 | struct minstrel_sta_info *mi = priv_sta; |
| 242 | 288 | struct minstrel_priv *mp = priv; |
| 243 | − struct ieee80211_tx_rate *ar = info->control.rates; | |
| 244 | − unsigned int ndx, sample_ndx = 0; | |
| 289 | + struct ieee80211_tx_rate *rate = &info->control.rates[0]; | |
| 290 | + struct minstrel_rate *msr, *mr; | |
| 291 | + unsigned int ndx; | |
| 245 | 292 | bool mrr_capable; |
| 246 | − bool indirect_rate_sampling = false; | |
| 247 | − bool rate_sampling = false; | |
| 248 | − int i, delta; | |
| 249 | − int mrr_ndx[3]; | |
| 293 | + bool prev_sample = mi->prev_sample; | |
| 294 | + int delta; | |
| 250 | 295 | int sampling_ratio; |
| 251 | 296 | |
| 252 | 297 | /* management/no-ack frames do not use rate control */ |
| @@ -262,107 +307,75 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, · 9 unmodified lines | ||
| 262 | 307 | else |
| 263 | 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 | 310 | /* increase sum packet counter */ |
| 269 | 311 | mi->packet_count++; |
| 270 | 312 | |
| 271 | 313 | delta = (mi->packet_count * sampling_ratio / 100) - |
| 272 | 314 | (mi->sample_count + mi->sample_deferred / 2); |
| 273 | 315 | |
| 274 | − /* delta > 0: sampling required */ | |
| 275 | − if ((delta > 0) && (mrr_capable || !mi->prev_sample)) { | |
| 276 | − struct minstrel_rate *msr; | |
| 277 | − if (mi->packet_count >= 10000) { | |
| 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 | − } | |
| 316 | + /* delta < 0: no sampling required */ | |
| 317 | + mi->prev_sample = false; | |
| 318 | + if (delta < 0 || (!mrr_capable && prev_sample)) | |
| 319 | + return; | |
| 293 | 320 | |
| 294 | − /* get next random rate sample */ | |
| 295 | − sample_ndx = minstrel_get_next_sample(mi); | |
| 296 | − msr = &mi->r[sample_ndx]; | |
| 297 | − rate_sampling = true; | |
| 298 | − | |
| 299 | − /* Decide if direct ( 1st mrr stage) or indirect (2nd mrr stage) | |
| 300 | − * rate sampling method should be used. | |
| 301 | − * Respect such rates that are not sampled for 20 interations. | |
| 302 | − */ | |
| 303 | − if (mrr_capable && | |
| 304 | − msr->perfect_tx_time > mi->r[ndx].perfect_tx_time && | |
| 305 | − msr->sample_skipped < 20) | |
| 306 | − indirect_rate_sampling = true; | |
| 307 | − | |
| 308 | − if (!indirect_rate_sampling) { | |
| 309 | − if (msr->sample_limit != 0) { | |
| 310 | − ndx = sample_ndx; | |
| 311 | − mi->sample_count++; | |
| 312 | − if (msr->sample_limit > 0) | |
| 313 | − msr->sample_limit--; | |
| 314 | − } else | |
| 315 | − rate_sampling = false; | |
| 316 | − } else { | |
| 317 | − /* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark | |
| 318 | − * packets that have the sampling rate deferred to the | |
| 319 | − * second MRR stage. Increase the sample counter only | |
| 320 | − * if the deferred sample rate was actually used. | |
| 321 | − * Use the sample_deferred counter to make sure that | |
| 322 | − * the sampling is not done in large bursts */ | |
| 323 | − info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; | |
| 324 | − mi->sample_deferred++; | |
| 325 | − } | |
| 321 | + if (mi->packet_count >= 10000) { | |
| 322 | + mi->sample_deferred = 0; | |
| 323 | + mi->sample_count = 0; | |
| 324 | + mi->packet_count = 0; | |
| 325 | + } else if (delta > mi->n_rates * 2) { | |
| 326 | + /* With multi-rate retry, not every planned sample | |
| 327 | + * attempt actually gets used, due to the way the retry | |
| 328 | + * chain is set up - [max_tp,sample,prob,lowest] for | |
| 329 | + * sample_rate < max_tp. | |
| 330 | + * | |
| 331 | + * If there's too much sampling backlog and the link | |
| 332 | + * starts getting worse, minstrel would start bursting | |
| 333 | + * out lots of sampling frames, which would result | |
| 334 | + * in a large throughput loss. */ | |
| 335 | + mi->sample_count += (delta - mi->n_rates * 2); | |
| 336 | + } | |
| 337 | + | |
| 338 | + /* get next random rate sample */ | |
| 339 | + ndx = minstrel_get_next_sample(mi); | |
| 340 | + msr = &mi->r[ndx]; | |
| 341 | + mr = &mi->r[mi->max_tp_rate[0]]; | |
| 342 | + | |
| 343 | + /* Decide if direct ( 1st mrr stage) or indirect (2nd mrr stage) | |
| 344 | + * rate sampling method should be used. | |
| 345 | + * Respect such rates that are not sampled for 20 interations. | |
| 346 | + */ | |
| 347 | + if (mrr_capable && | |
| 348 | + msr->perfect_tx_time > mr->perfect_tx_time && | |
| 349 | + msr->sample_skipped < 20) { | |
| 350 | + /* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark | |
| 351 | + * packets that have the sampling rate deferred to the | |
| 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 | 368 | /* If we're not using MRR and the sampling rate already |
| 330 | 369 | * has a probability of >95%, we shouldn't be attempting |
| 331 | 370 | * to use it, as this only wastes precious airtime */ |
| 332 | − if (!mrr_capable && rate_sampling && | |
| 371 | + if (!mrr_capable && | |
| 333 | 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 | 373 | return; |
| 347 | − } | |
| 348 | 374 | |
| 349 | − /* mrr setup for 2nd stage */ | |
| 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 | − } | |
| 375 | + mi->prev_sample = true; | |
| 358 | 376 | |
| 359 | − /* mrr setup for 3rd & 4th stage */ | |
| 360 | − mrr_ndx[1] = mi->max_prob_rate; | |
| 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 | − } | |
| 377 | + rate->idx = mi->r[ndx].rix; | |
| 378 | + rate->count = minstrel_get_retry_count(&mi->r[ndx], info); | |
| 366 | 379 | } |
| 367 | 380 | |
| 368 | 381 | |
| @@ -412,12 +425,16 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, · 43 unmodified lines | ||
| 412 | 425 | unsigned int i, n = 0; |
| 413 | 426 | unsigned int t_slot = 9; /* FIXME: get real slot time */ |
| 414 | 427 | |
| 428 | + mi->sta = sta; | |
| 415 | 429 | mi->lowest_rix = rate_lowest_index(sband, sta); |
| 416 | 430 | ctl_rate = &sband->bitrates[mi->lowest_rix]; |
| 417 | 431 | mi->sp_ack_dur = ieee80211_frame_duration(sband->band, 10, |
| 418 | 432 | ctl_rate->bitrate, |
| 419 | 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 | 438 | for (i = 0; i < sband->n_bitrates; i++) { |
| 422 | 439 | struct minstrel_rate *mr = &mi->r[n]; |
| 423 | 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, · 36 unmodified lines | ||
| 460 | 477 | } while ((tx_time < mp->segment_size) && |
| 461 | 478 | (++mr->retry_count < mp->max_retry)); |
| 462 | 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 | 484 | for (i = n; i < sband->n_bitrates; i++) { |
| @@ -471,6 +490,7 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, · 5 unmodified lines | ||
| 471 | 490 | mi->stats_update = jiffies; |
| 472 | 491 | |
| 473 | 492 | init_sample_table(mi); |
| 493 | + minstrel_update_rates(mp, mi); | |
| 474 | 494 | } |
| 475 | 495 | |
| 476 | 496 | static void * |
| @@ -9,7 +9,8 @@ · 8 unmodified lines | ||
| 9 | 9 | #ifndef __RC_MINSTREL_H |
| 10 | 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 | 14 | #define SAMPLE_COLUMNS 10 /* number of columns in sample table */ |
| 14 | 15 | |
| 15 | 16 | |
| @@ -27,7 +28,7 @@ · 11 unmodified lines | ||
| 27 | 28 | static inline int |
| 28 | 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 { · 28 unmodified lines | ||
| 62 | 63 | }; |
| 63 | 64 | |
| 64 | 65 | struct minstrel_sta_info { |
| 66 | + struct ieee80211_sta *sta; | |
| 67 | + | |
| 65 | 68 | unsigned long stats_update; |
| 66 | 69 | unsigned int sp_ack_dur; |
| 67 | 70 | unsigned int rate_avg; |
| @@ -68,7 +68,7 @@ minstrel_stats_open(struct inode *inode, struct file *file) · 67 unmodified lines | ||
| 68 | 68 | |
| 69 | 69 | file->private_data = ms; |
| 70 | 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 | 72 | "this succ/attempt success attempts\n"); |
| 73 | 73 | for (i = 0; i < mi->n_rates; i++) { |
| 74 | 74 | struct minstrel_rate *mr = &mi->r[i]; |
| @@ -86,7 +86,7 @@ minstrel_stats_open(struct inode *inode, struct file *file) · 11 unmodified lines | ||
| 86 | 86 | eprob = MINSTREL_TRUNC(mr->probability * 1000); |
| 87 | 87 | |
| 88 | 88 | p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u " |
| 89 | − "%3u(%3u) %8llu %8llu\n", | |
| 89 | + " %3u(%3u) %8llu %8llu\n", | |
| 90 | 90 | tp / 10, tp % 10, |
| 91 | 91 | eprob / 10, eprob % 10, |
| 92 | 92 | prob / 10, prob % 10, |
| @@ -126,6 +126,9 @@ const struct mcs_group minstrel_mcs_groups[] = { · 125 unmodified lines | ||
| 126 | 126 | |
| 127 | 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 | 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) · 112 unmodified lines | ||
| 244 | 247 | struct minstrel_rate_stats *mr; |
| 245 | 248 | int cur_prob, cur_prob_tp, cur_tp, cur_tp2; |
| 246 | 249 | int group, i, index; |
| 250 | + bool mi_rates_valid = false; | |
| 247 | 251 | |
| 248 | 252 | if (mi->ampdu_packets > 0) { |
| 249 | 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) · 4 unmodified lines | ||
| 254 | 258 | |
| 255 | 259 | mi->sample_slow = 0; |
| 256 | 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 | 262 | for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { |
| 263 | + bool mg_rates_valid = false; | |
| 264 | + | |
| 262 | 265 | cur_prob = 0; |
| 263 | 266 | cur_prob_tp = 0; |
| 264 | 267 | cur_tp = 0; |
| @@ -268,15 +271,24 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) · 3 unmodified lines | ||
| 268 | 271 | if (!mg->supported) |
| 269 | 272 | continue; |
| 270 | 273 | |
| 271 | − mg->max_tp_rate = 0; | |
| 272 | − mg->max_tp_rate2 = 0; | |
| 273 | − mg->max_prob_rate = 0; | |
| 274 | 274 | mi->sample_count++; |
| 275 | 275 | |
| 276 | 276 | for (i = 0; i < MCS_GROUP_RATES; i++) { |
| 277 | 277 | if (!(mg->supported & BIT(i))) |
| 278 | 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 | 292 | mr = &mg->rates[i]; |
| 281 | 293 | mr->retry_updated = false; |
| 282 | 294 | index = MCS_GROUP_RATES * group + i; |
| @@ -456,7 +468,7 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, · 173 unmodified lines | ||
| 456 | 468 | struct ieee80211_tx_rate *ar = info->status.rates; |
| 457 | 469 | struct minstrel_rate_stats *rate, *rate2; |
| 458 | 470 | struct minstrel_priv *mp = priv; |
| 459 | − bool last; | |
| 471 | + bool last, update = false; | |
| 460 | 472 | int i; |
| 461 | 473 | |
| 462 | 474 | if (!msp->is_ht) |
| @@ -505,21 +517,29 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, · 42 unmodified lines | ||
| 505 | 517 | rate = minstrel_get_ratestats(mi, mi->max_tp_rate); |
| 506 | 518 | if (rate->attempts > 30 && |
| 507 | 519 | MINSTREL_FRAC(rate->success, rate->attempts) < |
| 508 | − MINSTREL_FRAC(20, 100)) | |
| 520 | + MINSTREL_FRAC(20, 100)) { | |
| 509 | 521 | minstrel_downgrade_rate(mi, &mi->max_tp_rate, true); |
| 522 | + update = true; | |
| 523 | + } | |
| 510 | 524 | |
| 511 | 525 | rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate2); |
| 512 | 526 | if (rate2->attempts > 30 && |
| 513 | 527 | MINSTREL_FRAC(rate2->success, rate2->attempts) < |
| 514 | − MINSTREL_FRAC(20, 100)) | |
| 528 | + MINSTREL_FRAC(20, 100)) { | |
| 515 | 529 | minstrel_downgrade_rate(mi, &mi->max_tp_rate2, false); |
| 530 | + update = true; | |
| 531 | + } | |
| 516 | 532 | |
| 517 | 533 | if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) { |
| 534 | + update = true; | |
| 518 | 535 | minstrel_ht_update_stats(mp, mi); |
| 519 | 536 | if (!(info->flags & IEEE80211_TX_CTL_AMPDU) && |
| 520 | 537 | mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP) |
| 521 | 538 | minstrel_aggr_check(sta, skb); |
| 522 | 539 | } |
| 540 | + | |
| 541 | + if (update) | |
| 542 | + minstrel_ht_update_rates(mp, mi); | |
| 523 | 543 | } |
| 524 | 544 | |
| 525 | 545 | static void |
| @@ -583,36 +603,71 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, · 57 unmodified lines | ||
| 583 | 603 | |
| 584 | 604 | static void |
| 585 | 605 | minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, |
| 586 | − struct ieee80211_tx_rate *rate, int index, | |
| 587 | − bool sample, bool rtscts) | |
| 606 | + struct ieee80211_sta_rates *ratetbl, int offset, int index) | |
| 588 | 607 | { |
| 589 | 608 | const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; |
| 590 | 609 | struct minstrel_rate_stats *mr; |
| 610 | + u8 idx; | |
| 611 | + u16 flags; | |
| 591 | 612 | |
| 592 | 613 | mr = minstrel_get_ratestats(mi, index); |
| 593 | 614 | if (!mr->retry_updated) |
| 594 | 615 | minstrel_calc_retransmit(mp, mi, index); |
| 595 | 616 | |
| 596 | − if (sample) | |
| 597 | − rate->count = 1; | |
| 598 | − else if (mr->probability < MINSTREL_FRAC(20, 100)) | |
| 599 | − rate->count = 2; | |
| 600 | − else if (rtscts) | |
| 601 | − rate->count = mr->retry_count_rtscts; | |
| 602 | − else | |
| 603 | − rate->count = mr->retry_count; | |
| 604 | − | |
| 605 | − rate->flags = 0; | |
| 606 | − if (rtscts) | |
| 607 | − rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; | |
| 617 | + if (mr->probability < MINSTREL_FRAC(20, 100) || !mr->retry_count) { | |
| 618 | + ratetbl->rate[offset].count = 2; | |
| 619 | + ratetbl->rate[offset].count_rts = 2; | |
| 620 | + ratetbl->rate[offset].count_cts = 2; | |
| 621 | + } else { | |
| 622 | + ratetbl->rate[offset].count = mr->retry_count; | |
| 623 | + ratetbl->rate[offset].count_cts = mr->retry_count; | |
| 624 | + ratetbl->rate[offset].count_rts = mr->retry_count_rtscts; | |
| 625 | + } | |
| 608 | 626 | |
| 609 | 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 | 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; | |
| 615 | − rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES; | |
| 669 | + rates->rate[i].idx = -1; | |
| 670 | + rate_control_set_rates(mp->hw, mi->sta, rates); | |
| 616 | 671 | } |
| 617 | 672 | |
| 618 | 673 | static inline int |
| @@ -702,13 +757,13 @@ static void · 83 unmodified lines | ||
| 702 | 757 | minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, |
| 703 | 758 | struct ieee80211_tx_rate_control *txrc) |
| 704 | 759 | { |
| 760 | + const struct mcs_group *sample_group; | |
| 705 | 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 | 763 | struct minstrel_ht_sta_priv *msp = priv_sta; |
| 708 | 764 | struct minstrel_ht_sta *mi = &msp->ht; |
| 709 | 765 | struct minstrel_priv *mp = priv; |
| 710 | 766 | int sample_idx; |
| 711 | − bool sample = false; | |
| 712 | 767 | |
| 713 | 768 | if (rate_control_send_low(sta, priv_sta, txrc)) |
| 714 | 769 | return; |
| @@ -736,51 +791,6 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, · 21 unmodified lines | ||
| 736 | 791 | } |
| 737 | 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 | 794 | mi->total_packets++; |
| 785 | 795 | |
| 786 | 796 | /* wraparound */ |
| @@ -788,6 +798,16 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, · 1 unmodified line | ||
| 788 | 798 | mi->total_packets = 0; |
| 789 | 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 | 813 | static void |
| @@ -837,6 +857,8 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, · 43 unmodified lines | ||
| 837 | 857 | |
| 838 | 858 | msp->is_ht = true; |
| 839 | 859 | memset(mi, 0, sizeof(*mi)); |
| 860 | + | |
| 861 | + mi->sta = sta; | |
| 840 | 862 | mi->stats_update = jiffies; |
| 841 | 863 | |
| 842 | 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, · 55 unmodified lines | ||
| 898 | 920 | if (!n_supported) |
| 899 | 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 | 927 | return; |
| 902 | 928 | |
| 903 | 929 | use_legacy: |
| @@ -65,6 +65,8 @@ struct minstrel_mcs_group_data { · 64 unmodified lines | ||
| 65 | 65 | }; |
| 66 | 66 | |
| 67 | 67 | struct minstrel_ht_sta { |
| 68 | + struct ieee80211_sta *sta; | |
| 69 | + | |
| 68 | 70 | /* ampdu length (average, per sampling interval) */ |
| 69 | 71 | unsigned int ampdu_len; |
| 70 | 72 | unsigned int ampdu_packets; |
| @@ -2085,6 +2085,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) · 2084 unmodified lines | ||
| 2085 | 2085 | } |
| 2086 | 2086 | |
| 2087 | 2087 | fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; |
| 2088 | + fwd_hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_RETRY); | |
| 2088 | 2089 | info = IEEE80211_SKB_CB(fwd_skb); |
| 2089 | 2090 | memset(info, 0, sizeof(*info)); |
| 2090 | 2091 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
| @@ -2423,6 +2424,22 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) · 332 unmodified lines | ||
| 2423 | 2424 | } |
| 2424 | 2425 | |
| 2425 | 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 | 2443 | case WLAN_CATEGORY_VHT: |
| 2427 | 2444 | if (sdata->vif.type != NL80211_IFTYPE_STATION && |
| 2428 | 2445 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT && |
| @@ -2506,10 +2523,6 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) · 77 unmodified lines | ||
| 2506 | 2523 | ieee80211_process_measurement_req(sdata, mgmt, len); |
| 2507 | 2524 | goto handled; |
| 2508 | 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 | 2526 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
| 2514 | 2527 | break; |
| 2515 | 2528 | |
| @@ -3042,7 +3055,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, · 526 unmodified lines | ||
| 3042 | 3055 | !ieee80211_is_probe_resp(hdr->frame_control) && |
| 3043 | 3056 | !ieee80211_is_beacon(hdr->frame_control)) |
| 3044 | 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 | 3060 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; |
| 3047 | 3061 | break; |
| 3048 | 3062 | default: |
| @@ -181,7 +181,7 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) · 180 unmodified lines | ||
| 181 | 181 | if (baselen > skb->len) |
| 182 | 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 | 186 | channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq); |
| 187 | 187 | |
| @@ -990,23 +990,23 @@ TRACE_EVENT(drv_channel_switch, · 989 unmodified lines | ||
| 990 | 990 | |
| 991 | 991 | TP_STRUCT__entry( |
| 992 | 992 | LOCAL_ENTRY |
| 993 | + CHANDEF_ENTRY | |
| 993 | 994 | __field(u64, timestamp) |
| 994 | 995 | __field(bool, block_tx) |
| 995 | − __field(u16, freq) | |
| 996 | 996 | __field(u8, count) |
| 997 | 997 | ), |
| 998 | 998 | |
| 999 | 999 | TP_fast_assign( |
| 1000 | 1000 | LOCAL_ASSIGN; |
| 1001 | + CHANDEF_ASSIGN(&ch_switch->chandef) | |
| 1001 | 1002 | __entry->timestamp = ch_switch->timestamp; |
| 1002 | 1003 | __entry->block_tx = ch_switch->block_tx; |
| 1003 | − __entry->freq = ch_switch->channel->center_freq; | |
| 1004 | 1004 | __entry->count = ch_switch->count; |
| 1005 | 1005 | ), |
| 1006 | 1006 | |
| 1007 | 1007 | TP_printk( |
| 1008 | − LOCAL_PR_FMT " new freq:%u count:%d", | |
| 1009 | − LOCAL_PR_ARG, __entry->freq, __entry->count | |
| 1008 | + LOCAL_PR_FMT " new " CHANDEF_PR_FMT " count:%d", | |
| 1009 | + LOCAL_PR_ARG, CHANDEF_PR_ARG, __entry->count | |
| 1010 | 1010 | ) |
| 1011 | 1011 | ); |
| 1012 | 1012 | |
| @@ -48,15 +48,15 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, · 47 unmodified lines | ||
| 48 | 48 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 49 | 49 | |
| 50 | 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 | 52 | return 0; |
| 53 | 53 | |
| 54 | 54 | /* uh huh? */ |
| 55 | − if (WARN_ON_ONCE(info->control.rates[0].idx < 0)) | |
| 55 | + if (WARN_ON_ONCE(tx->rate.idx < 0)) | |
| 56 | 56 | return 0; |
| 57 | 57 | |
| 58 | 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 | 61 | erp = txrate->flags & IEEE80211_RATE_ERP_G; |
| 62 | 62 | |
| @@ -617,11 +617,9 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) · 554 unmodified lines | ||
| 617 | 617 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); |
| 618 | 618 | struct ieee80211_hdr *hdr = (void *)tx->skb->data; |
| 619 | 619 | struct ieee80211_supported_band *sband; |
| 620 | − struct ieee80211_rate *rate; | |
| 621 | − int i; | |
| 622 | 620 | u32 len; |
| 623 | − bool inval = false, rts = false, short_preamble = false; | |
| 624 | 621 | struct ieee80211_tx_rate_control txrc; |
| 622 | + struct ieee80211_sta_rates *ratetbl = NULL; | |
| 625 | 623 | bool assoc = false; |
| 626 | 624 | |
| 627 | 625 | memset(&txrc, 0, sizeof(txrc)); |
| @@ -642,18 +640,23 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) · 14 unmodified lines | ||
| 642 | 640 | txrc.max_rate_idx = -1; |
| 643 | 641 | else |
| 644 | 642 | txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; |
| 645 | − memcpy(txrc.rate_idx_mcs_mask, | |
| 646 | − tx->sdata->rc_rateidx_mcs_mask[info->band], | |
| 647 | − sizeof(txrc.rate_idx_mcs_mask)); | |
| 643 | + | |
| 644 | + if (tx->sdata->rc_has_mcs_mask[info->band]) | |
| 645 | + txrc.rate_idx_mcs_mask = | |
| 646 | + tx->sdata->rc_rateidx_mcs_mask[info->band]; | |
| 647 | + | |
| 648 | 648 | txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP || |
| 649 | 649 | tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT || |
| 650 | 650 | tx->sdata->vif.type == NL80211_IFTYPE_ADHOC); |
| 651 | 651 | |
| 652 | 652 | /* set up RTS protection if desired */ |
| 653 | 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 | 661 | * Use short preamble if the BSS can handle it, but not for |
| 659 | 662 | * management frames unless we know the receiver can handle |
| @@ -663,7 +666,9 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) · 3 unmodified lines | ||
| 663 | 666 | if (tx->sdata->vif.bss_conf.use_short_preamble && |
| 664 | 667 | (ieee80211_is_data(hdr->frame_control) || |
| 665 | 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 | 673 | if (tx->sta) |
| 669 | 674 | assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC); |
| @@ -687,16 +692,38 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) · 17 unmodified lines | ||
| 687 | 692 | */ |
| 688 | 693 | rate_control_get_rate(tx->sdata, tx->sta, &txrc); |
| 689 | 694 | |
| 690 | − if (unlikely(info->control.rates[0].idx < 0)) | |
| 691 | − return TX_DROP; | |
| 695 | + if (tx->sta && !info->control.skip_table) | |
| 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 | 717 | if (txrc.reported_rate.idx < 0) { |
| 694 | − txrc.reported_rate = info->control.rates[0]; | |
| 718 | + txrc.reported_rate = tx->rate; | |
| 695 | 719 | if (tx->sta && ieee80211_is_data(hdr->frame_control)) |
| 696 | 720 | tx->sta->last_tx_rate = txrc.reported_rate; |
| 697 | 721 | } else if (tx->sta) |
| 698 | 722 | tx->sta->last_tx_rate = txrc.reported_rate; |
| 699 | 723 | |
| 724 | + if (ratetbl) | |
| 725 | + return TX_CONTINUE; | |
| 726 | + | |
| 700 | 727 | if (unlikely(!info->control.rates[0].count)) |
| 701 | 728 | info->control.rates[0].count = 1; |
| 702 | 729 | |
| @@ -704,91 +731,6 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) · 1 unmodified line | ||
| 704 | 731 | (info->flags & IEEE80211_TX_CTL_NO_ACK))) |
| 705 | 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 | 734 | return TX_CONTINUE; |
| 793 | 735 | } |
| 794 | 736 | |
| @@ -2502,8 +2444,6 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, · 1707 unmodified lines | ||
| 2502 | 2444 | txrc.max_rate_idx = -1; |
| 2503 | 2445 | else |
| 2504 | 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 | 2447 | txrc.bss = true; |
| 2508 | 2448 | rate_control_get_rate(sdata, NULL, &txrc); |
| 2509 | 2449 | |
| @@ -485,7 +485,8 @@ int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) · 484 unmodified lines | ||
| 485 | 485 | return true; |
| 486 | 486 | |
| 487 | 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 | 490 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
| 490 | 491 | return ret; |
| 491 | 492 | } |
| @@ -660,7 +661,7 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, · 168 unmodified lines | ||
| 660 | 661 | } |
| 661 | 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 | 665 | struct ieee802_11_elems *elems, |
| 665 | 666 | u64 filter, u32 crc) |
| 666 | 667 | { |
| @@ -668,6 +669,7 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, · 1 unmodified line | ||
| 668 | 669 | u8 *pos = start; |
| 669 | 670 | bool calc_crc = filter != 0; |
| 670 | 671 | DECLARE_BITMAP(seen_elems, 256); |
| 672 | + const u8 *ie; | |
| 671 | 673 | |
| 672 | 674 | bitmap_zero(seen_elems, 256); |
| 673 | 675 | memset(elems, 0, sizeof(*elems)); |
| @@ -715,6 +717,12 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, · 41 unmodified lines | ||
| 715 | 717 | case WLAN_EID_COUNTRY: |
| 716 | 718 | case WLAN_EID_PWR_CONSTRAINT: |
| 717 | 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 | 726 | if (test_bit(id, seen_elems)) { |
| 719 | 727 | elems->parse_error = true; |
| 720 | 728 | left -= elen; |
| @@ -862,6 +870,48 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, · 141 unmodified lines | ||
| 862 | 870 | } |
| 863 | 871 | elems->ch_switch_ie = (void *)pos; |
| 864 | 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 | 915 | case WLAN_EID_COUNTRY: |
| 866 | 916 | elems->country_elem = pos; |
| 867 | 917 | elems->country_elem_len = elen; |
| @@ -131,6 +131,7 @@ static int rfkill_gpio_probe(struct platform_device *pdev) · 130 unmodified lines | ||
| 131 | 131 | rfkill->pwr_clk = clk_get(&pdev->dev, pdata->power_clk_name); |
| 132 | 132 | if (IS_ERR(rfkill->pwr_clk)) { |
| 133 | 133 | pr_warn("%s: can't find pwr_clk.\n", __func__); |
| 134 | + ret = PTR_ERR(rfkill->pwr_clk); | |
| 134 | 135 | goto fail_shutdown_name; |
| 135 | 136 | } |
| 136 | 137 | } |
| @@ -152,9 +153,11 @@ static int rfkill_gpio_probe(struct platform_device *pdev) · 15 unmodified lines | ||
| 152 | 153 | } |
| 153 | 154 | |
| 154 | 155 | rfkill->rfkill_dev = rfkill_alloc(pdata->name, &pdev->dev, pdata->type, |
| 155 | − &rfkill_gpio_ops, rfkill); | |
| 156 | − if (!rfkill->rfkill_dev) | |
| 156 | + &rfkill_gpio_ops, rfkill); | |
| 157 | + if (!rfkill->rfkill_dev) { | |
| 158 | + ret = -ENOMEM; | |
| 157 | 159 | goto fail_shutdown; |
| 160 | + } | |
| 158 | 161 | |
| 159 | 162 | ret = rfkill_register(rfkill->rfkill_dev); |
| 160 | 163 | if (ret < 0) |
| @@ -88,6 +88,9 @@ struct cfg80211_registered_device { · 87 unmodified lines | ||
| 88 | 88 | |
| 89 | 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 | 94 | /* must be last because of the way we do wiphy_priv(), |
| 92 | 95 | * and it should at least be aligned to NETDEV_ALIGN */ |
| 93 | 96 | struct wiphy wiphy __aligned(NETDEV_ALIGN); |
| @@ -648,6 +648,11 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid) · 647 unmodified lines | ||
| 648 | 648 | |
| 649 | 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 | 656 | if (nlportid == wdev->ap_unexpected_nlportid) |
| 652 | 657 | wdev->ap_unexpected_nlportid = 0; |
| 653 | 658 | } |
| @@ -447,62 +447,69 @@ nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = { · 446 unmodified lines | ||
| 447 | 447 | [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 }, |
| 448 | 448 | }; |
| 449 | 449 | |
| 450 | −/* ifidx get helper */ | |
| 451 | −static int nl80211_get_ifidx(struct netlink_callback *cb) | |
| 450 | +static int nl80211_prepare_wdev_dump(struct sk_buff *skb, | |
| 451 | + struct netlink_callback *cb, | |
| 452 | + struct cfg80211_registered_device **rdev, | |
| 453 | + struct wireless_dev **wdev) | |
| 452 | 454 | { |
| 453 | − int res; | |
| 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; | |
| 455 | + int err; | |
| 463 | 456 | |
| 464 | − res = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); | |
| 465 | − if (!res) | |
| 466 | − return -EINVAL; | |
| 467 | − return res; | |
| 468 | −} | |
| 457 | + rtnl_lock(); | |
| 458 | + mutex_lock(&cfg80211_mutex); | |
| 469 | 459 | |
| 470 | −static int nl80211_prepare_netdev_dump(struct sk_buff *skb, | |
| 471 | − struct netlink_callback *cb, | |
| 472 | − struct cfg80211_registered_device **rdev, | |
| 473 | − struct net_device **dev) | |
| 474 | −{ | |
| 475 | − int ifidx = cb->args[0]; | |
| 476 | − int err; | |
| 460 | + if (!cb->args[0]) { | |
| 461 | + err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | |
| 462 | + nl80211_fam.attrbuf, nl80211_fam.maxattr, | |
| 463 | + nl80211_policy); | |
| 464 | + if (err) | |
| 465 | + goto out_unlock; | |
| 477 | 466 | |
| 478 | − if (!ifidx) | |
| 479 | − ifidx = nl80211_get_ifidx(cb); | |
| 480 | − if (ifidx < 0) | |
| 481 | − return ifidx; | |
| 467 | + *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), | |
| 468 | + nl80211_fam.attrbuf); | |
| 469 | + if (IS_ERR(*wdev)) { | |
| 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); | |
| 488 | − if (!*dev) { | |
| 489 | − err = -ENODEV; | |
| 490 | − goto out_rtnl; | |
| 496 | + if (!*wdev) { | |
| 497 | + err = -ENODEV; | |
| 498 | + goto out_unlock; | |
| 499 | + } | |
| 491 | 500 | } |
| 492 | 501 | |
| 493 | − *rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | |
| 494 | − if (IS_ERR(*rdev)) { | |
| 495 | − err = PTR_ERR(*rdev); | |
| 496 | − goto out_rtnl; | |
| 497 | − } | |
| 502 | + cfg80211_lock_rdev(*rdev); | |
| 498 | 503 | |
| 504 | + mutex_unlock(&cfg80211_mutex); | |
| 499 | 505 | return 0; |
| 500 | − out_rtnl: | |
| 506 | + out_unlock: | |
| 507 | + mutex_unlock(&cfg80211_mutex); | |
| 501 | 508 | rtnl_unlock(); |
| 502 | 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 | 514 | cfg80211_unlock_rdev(rdev); |
| 508 | 515 | rtnl_unlock(); |
| @@ -1417,6 +1424,10 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, · 908 unmodified lines | ||
| 1417 | 1424 | } |
| 1418 | 1425 | CMD(start_p2p_device, START_P2P_DEVICE); |
| 1419 | 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 | 1432 | #ifdef CONFIG_NL80211_TESTMODE |
| 1422 | 1433 | CMD(testmode_cmd, TESTMODE); |
| @@ -3525,15 +3536,20 @@ static int nl80211_dump_station(struct sk_buff *skb, · 2102 unmodified lines | ||
| 3525 | 3536 | { |
| 3526 | 3537 | struct station_info sinfo; |
| 3527 | 3538 | struct cfg80211_registered_device *dev; |
| 3528 | − struct net_device *netdev; | |
| 3539 | + struct wireless_dev *wdev; | |
| 3529 | 3540 | u8 mac_addr[ETH_ALEN]; |
| 3530 | − int sta_idx = cb->args[1]; | |
| 3541 | + int sta_idx = cb->args[2]; | |
| 3531 | 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 | 3545 | if (err) |
| 3535 | 3546 | return err; |
| 3536 | 3547 | |
| 3548 | + if (!wdev->netdev) { | |
| 3549 | + err = -EINVAL; | |
| 3550 | + goto out_err; | |
| 3551 | + } | |
| 3552 | + | |
| 3537 | 3553 | if (!dev->ops->dump_station) { |
| 3538 | 3554 | err = -EOPNOTSUPP; |
| 3539 | 3555 | goto out_err; |
| @@ -3541,7 +3557,7 @@ static int nl80211_dump_station(struct sk_buff *skb, · 1 unmodified line | ||
| 3541 | 3557 | |
| 3542 | 3558 | while (1) { |
| 3543 | 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 | 3561 | mac_addr, &sinfo); |
| 3546 | 3562 | if (err == -ENOENT) |
| 3547 | 3563 | break; |
| @@ -3551,7 +3567,7 @@ static int nl80211_dump_station(struct sk_buff *skb, · 3 unmodified lines | ||
| 3551 | 3567 | if (nl80211_send_station(skb, |
| 3552 | 3568 | NETLINK_CB(cb->skb).portid, |
| 3553 | 3569 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
| 3554 | − dev, netdev, mac_addr, | |
| 3570 | + dev, wdev->netdev, mac_addr, | |
| 3555 | 3571 | &sinfo) < 0) |
| 3556 | 3572 | goto out; |
| 3557 | 3573 | |
| @@ -3560,10 +3576,10 @@ static int nl80211_dump_station(struct sk_buff *skb, · 2 unmodified lines | ||
| 3560 | 3576 | |
| 3561 | 3577 | |
| 3562 | 3578 | out: |
| 3563 | − cb->args[1] = sta_idx; | |
| 3579 | + cb->args[2] = sta_idx; | |
| 3564 | 3580 | err = skb->len; |
| 3565 | 3581 | out_err: |
| 3566 | − nl80211_finish_netdev_dump(dev); | |
| 3582 | + nl80211_finish_wdev_dump(dev); | |
| 3567 | 3583 | |
| 3568 | 3584 | return err; |
| 3569 | 3585 | } |
| @@ -4167,13 +4183,13 @@ static int nl80211_dump_mpath(struct sk_buff *skb, · 597 unmodified lines | ||
| 4167 | 4183 | { |
| 4168 | 4184 | struct mpath_info pinfo; |
| 4169 | 4185 | struct cfg80211_registered_device *dev; |
| 4170 | − struct net_device *netdev; | |
| 4186 | + struct wireless_dev *wdev; | |
| 4171 | 4187 | u8 dst[ETH_ALEN]; |
| 4172 | 4188 | u8 next_hop[ETH_ALEN]; |
| 4173 | − int path_idx = cb->args[1]; | |
| 4189 | + int path_idx = cb->args[2]; | |
| 4174 | 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 | 4193 | if (err) |
| 4178 | 4194 | return err; |
| 4179 | 4195 | |
| @@ -4182,14 +4198,14 @@ static int nl80211_dump_mpath(struct sk_buff *skb, · 2 unmodified lines | ||
| 4182 | 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 | 4202 | err = -EOPNOTSUPP; |
| 4187 | 4203 | goto out_err; |
| 4188 | 4204 | } |
| 4189 | 4205 | |
| 4190 | 4206 | while (1) { |
| 4191 | − err = rdev_dump_mpath(dev, netdev, path_idx, dst, next_hop, | |
| 4192 | − &pinfo); | |
| 4207 | + err = rdev_dump_mpath(dev, wdev->netdev, path_idx, dst, | |
| 4208 | + next_hop, &pinfo); | |
| 4193 | 4209 | if (err == -ENOENT) |
| 4194 | 4210 | break; |
| 4195 | 4211 | if (err) |
| @@ -4197,7 +4213,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb, · 1 unmodified line | ||
| 4197 | 4213 | |
| 4198 | 4214 | if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid, |
| 4199 | 4215 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
| 4200 | − netdev, dst, next_hop, | |
| 4216 | + wdev->netdev, dst, next_hop, | |
| 4201 | 4217 | &pinfo) < 0) |
| 4202 | 4218 | goto out; |
| 4203 | 4219 | |
| @@ -4206,10 +4222,10 @@ static int nl80211_dump_mpath(struct sk_buff *skb, · 2 unmodified lines | ||
| 4206 | 4222 | |
| 4207 | 4223 | |
| 4208 | 4224 | out: |
| 4209 | − cb->args[1] = path_idx; | |
| 4225 | + cb->args[2] = path_idx; | |
| 4210 | 4226 | err = skb->len; |
| 4211 | 4227 | out_err: |
| 4212 | − nl80211_finish_netdev_dump(dev); | |
| 4228 | + nl80211_finish_wdev_dump(dev); | |
| 4213 | 4229 | return err; |
| 4214 | 4230 | } |
| 4215 | 4231 | |
| @@ -5565,9 +5581,13 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, · 1349 unmodified lines | ||
| 5565 | 5581 | |
| 5566 | 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 | 5587 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex)) |
| 5570 | 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 | 5592 | bss = nla_nest_start(msg, NL80211_ATTR_BSS); |
| 5573 | 5593 | if (!bss) |
| @@ -5647,22 +5667,18 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, · 73 unmodified lines | ||
| 5647 | 5667 | return -EMSGSIZE; |
| 5648 | 5668 | } |
| 5649 | 5669 | |
| 5650 | −static int nl80211_dump_scan(struct sk_buff *skb, | |
| 5651 | − struct netlink_callback *cb) | |
| 5670 | +static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb) | |
| 5652 | 5671 | { |
| 5653 | 5672 | struct cfg80211_registered_device *rdev; |
| 5654 | − struct net_device *dev; | |
| 5655 | 5673 | struct cfg80211_internal_bss *scan; |
| 5656 | 5674 | struct wireless_dev *wdev; |
| 5657 | − int start = cb->args[1], idx = 0; | |
| 5675 | + int start = cb->args[2], idx = 0; | |
| 5658 | 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 | 5679 | if (err) |
| 5662 | 5680 | return err; |
| 5663 | 5681 | |
| 5664 | − wdev = dev->ieee80211_ptr; | |
| 5665 | − | |
| 5666 | 5682 | wdev_lock(wdev); |
| 5667 | 5683 | spin_lock_bh(&rdev->bss_lock); |
| 5668 | 5684 | cfg80211_bss_expire(rdev); |
| @@ -5683,8 +5699,8 @@ static int nl80211_dump_scan(struct sk_buff *skb, · 14 unmodified lines | ||
| 5683 | 5699 | spin_unlock_bh(&rdev->bss_lock); |
| 5684 | 5700 | wdev_unlock(wdev); |
| 5685 | 5701 | |
| 5686 | − cb->args[1] = idx; | |
| 5687 | − nl80211_finish_netdev_dump(rdev); | |
| 5702 | + cb->args[2] = idx; | |
| 5703 | + nl80211_finish_wdev_dump(rdev); | |
| 5688 | 5704 | |
| 5689 | 5705 | return skb->len; |
| 5690 | 5706 | } |
| @@ -5753,14 +5769,19 @@ static int nl80211_dump_survey(struct sk_buff *skb, · 62 unmodified lines | ||
| 5753 | 5769 | { |
| 5754 | 5770 | struct survey_info survey; |
| 5755 | 5771 | struct cfg80211_registered_device *dev; |
| 5756 | − struct net_device *netdev; | |
| 5757 | − int survey_idx = cb->args[1]; | |
| 5772 | + struct wireless_dev *wdev; | |
| 5773 | + int survey_idx = cb->args[2]; | |
| 5758 | 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 | 5777 | if (res) |
| 5762 | 5778 | return res; |
| 5763 | 5779 | |
| 5780 | + if (!wdev->netdev) { | |
| 5781 | + res = -EINVAL; | |
| 5782 | + goto out_err; | |
| 5783 | + } | |
| 5784 | + | |
| 5764 | 5785 | if (!dev->ops->dump_survey) { |
| 5765 | 5786 | res = -EOPNOTSUPP; |
| 5766 | 5787 | goto out_err; |
| @@ -5769,7 +5790,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, · 2 unmodified lines | ||
| 5769 | 5790 | while (1) { |
| 5770 | 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 | 5794 | if (res == -ENOENT) |
| 5774 | 5795 | break; |
| 5775 | 5796 | if (res) |
| @@ -5791,17 +5812,16 @@ static int nl80211_dump_survey(struct sk_buff *skb, · 15 unmodified lines | ||
| 5791 | 5812 | if (nl80211_send_survey(skb, |
| 5792 | 5813 | NETLINK_CB(cb->skb).portid, |
| 5793 | 5814 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
| 5794 | − netdev, | |
| 5795 | − &survey) < 0) | |
| 5815 | + wdev->netdev, &survey) < 0) | |
| 5796 | 5816 | goto out; |
| 5797 | 5817 | survey_idx++; |
| 5798 | 5818 | } |
| 5799 | 5819 | |
| 5800 | 5820 | out: |
| 5801 | − cb->args[1] = survey_idx; | |
| 5821 | + cb->args[2] = survey_idx; | |
| 5802 | 5822 | res = skb->len; |
| 5803 | 5823 | out_err: |
| 5804 | − nl80211_finish_netdev_dump(dev); | |
| 5824 | + nl80211_finish_wdev_dump(dev); | |
| 5805 | 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) · 2335 unmodified lines | ||
| 8143 | 8163 | if (!rdev->ops->stop_p2p_device) |
| 8144 | 8164 | return -EOPNOTSUPP; |
| 8145 | 8165 | |
| 8166 | + mutex_lock(&rdev->devlist_mtx); | |
| 8146 | 8167 | mutex_lock(&rdev->sched_scan_mtx); |
| 8147 | 8168 | cfg80211_stop_p2p_device(rdev, wdev); |
| 8148 | 8169 | mutex_unlock(&rdev->sched_scan_mtx); |
| 8170 | + mutex_unlock(&rdev->devlist_mtx); | |
| 8149 | 8171 | |
| 8150 | 8172 | return 0; |
| 8151 | 8173 | } |
| @@ -8198,6 +8220,64 @@ static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info) · 46 unmodified lines | ||
| 8198 | 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 | 8281 | #define NL80211_FLAG_NEED_WIPHY 0x01 |
| 8202 | 8282 | #define NL80211_FLAG_NEED_NETDEV 0x02 |
| 8203 | 8283 | #define NL80211_FLAG_NEED_RTNL 0x04 |
| @@ -8887,6 +8967,22 @@ static struct genl_ops nl80211_ops[] = { · 683 unmodified lines | ||
| 8887 | 8967 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
| 8888 | 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 | 8988 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
| @@ -10632,6 +10728,45 @@ void cfg80211_ft_event(struct net_device *netdev, · 1739 unmodified lines | ||
| 10632 | 10728 | } |
| 10633 | 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 | 10770 | /* initialisation/exit functions */ |
| 10636 | 10771 | |
| 10637 | 10772 | int nl80211_init(void) |
| @@ -875,7 +875,7 @@ static inline void rdev_stop_p2p_device(struct cfg80211_registered_device *rdev, · 874 unmodified lines | ||
| 875 | 875 | trace_rdev_stop_p2p_device(&rdev->wiphy, wdev); |
| 876 | 876 | rdev->ops->stop_p2p_device(&rdev->wiphy, wdev); |
| 877 | 877 | trace_rdev_return_void(&rdev->wiphy); |
| 878 | −} | |
| 878 | +} | |
| 879 | 879 | |
| 880 | 880 | static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev, |
| 881 | 881 | struct net_device *dev, |
| @@ -901,4 +901,26 @@ static inline int rdev_update_ft_ies(struct cfg80211_registered_device *rdev, · 19 unmodified lines | ||
| 901 | 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 | 926 | #endif /* __CFG80211_RDEV_OPS */ |
| @@ -855,7 +855,7 @@ static void handle_channel(struct wiphy *wiphy, · 854 unmodified lines | ||
| 855 | 855 | return; |
| 856 | 856 | |
| 857 | 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 | 859 | return; |
| 860 | 860 | } |
| 861 | 861 | |
| @@ -1806,6 +1806,41 @@ TRACE_EVENT(rdev_update_ft_ies, · 1805 unmodified lines | ||
| 1806 | 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 | 1845 | * cfg80211 exported functions traces * |
| 1811 | 1846 | *************************************************************/ |
| @@ -1155,6 +1155,26 @@ int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len, · 1154 unmodified lines | ||
| 1155 | 1155 | } |
| 1156 | 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 | 1178 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, |
| 1159 | 1179 | u32 beacon_int) |
| 1160 | 1180 | { |
| @@ -1258,12 +1278,12 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, · 97 unmodified lines | ||
| 1258 | 1278 | list_for_each_entry(wdev_iter, &rdev->wdev_list, list) { |
| 1259 | 1279 | if (wdev_iter == wdev) |
| 1260 | 1280 | continue; |
| 1261 | − if (wdev_iter->netdev) { | |
| 1262 | − if (!netif_running(wdev_iter->netdev)) | |
| 1263 | − continue; | |
| 1264 | − } else if (wdev_iter->iftype == NL80211_IFTYPE_P2P_DEVICE) { | |
| 1281 | + if (wdev_iter->iftype == NL80211_IFTYPE_P2P_DEVICE) { | |
| 1265 | 1282 | if (!wdev_iter->p2p_started) |
| 1266 | 1283 | continue; |
| 1284 | + } else if (wdev_iter->netdev) { | |
| 1285 | + if (!netif_running(wdev_iter->netdev)) | |
| 1286 | + continue; | |
| 1267 | 1287 | } else { |
| 1268 | 1288 | WARN_ON(1); |
| 1269 | 1289 | } |