diff options
author | John W. Linville <linville@tuxdriver.com> | 2014-06-25 15:15:14 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-06-25 15:26:36 -0400 |
commit | 855df36de365fb3b49eb06c352015e3d215b43fe (patch) | |
tree | 2a76f128eb457e1bacb585260b3e03f72b03cc1e | |
parent | d6067f0e17eb1de7d9b1d792f67d17c6e894b770 (diff) | |
parent | 97dc94f1d933c9df2c0b327066ea130c0e92083f (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
65 files changed, 2337 insertions, 2312 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 134483f206e4..54ba0e643c39 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -5629,16 +5629,6 @@ F: Documentation/networking/mac80211-injection.txt | |||
5629 | F: include/net/mac80211.h | 5629 | F: include/net/mac80211.h |
5630 | F: net/mac80211/ | 5630 | F: net/mac80211/ |
5631 | 5631 | ||
5632 | MAC80211 PID RATE CONTROL | ||
5633 | M: Stefano Brivio <stefano.brivio@polimi.it> | ||
5634 | M: Mattias Nissler <mattias.nissler@gmx.de> | ||
5635 | L: linux-wireless@vger.kernel.org | ||
5636 | W: http://wireless.kernel.org/en/developers/Documentation/mac80211/RateControl/PID | ||
5637 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git | ||
5638 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git | ||
5639 | S: Maintained | ||
5640 | F: net/mac80211/rc80211_pid* | ||
5641 | |||
5642 | MACVLAN DRIVER | 5632 | MACVLAN DRIVER |
5643 | M: Patrick McHardy <kaber@trash.net> | 5633 | M: Patrick McHardy <kaber@trash.net> |
5644 | L: netdev@vger.kernel.org | 5634 | L: netdev@vger.kernel.org |
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index d48776e4f343..334c2ece855a 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c | |||
@@ -1955,8 +1955,9 @@ static void at76_dwork_hw_scan(struct work_struct *work) | |||
1955 | 1955 | ||
1956 | static int at76_hw_scan(struct ieee80211_hw *hw, | 1956 | static int at76_hw_scan(struct ieee80211_hw *hw, |
1957 | struct ieee80211_vif *vif, | 1957 | struct ieee80211_vif *vif, |
1958 | struct cfg80211_scan_request *req) | 1958 | struct ieee80211_scan_request *hw_req) |
1959 | { | 1959 | { |
1960 | struct cfg80211_scan_request *req = &hw_req->req; | ||
1960 | struct at76_priv *priv = hw->priv; | 1961 | struct at76_priv *priv = hw->priv; |
1961 | struct at76_req_scan scan; | 1962 | struct at76_req_scan scan; |
1962 | u8 *ssid = NULL; | 1963 | u8 *ssid = NULL; |
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index a21080028c54..b8314a534972 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c | |||
@@ -3137,10 +3137,11 @@ exit: | |||
3137 | 3137 | ||
3138 | static int ath10k_hw_scan(struct ieee80211_hw *hw, | 3138 | static int ath10k_hw_scan(struct ieee80211_hw *hw, |
3139 | struct ieee80211_vif *vif, | 3139 | struct ieee80211_vif *vif, |
3140 | struct cfg80211_scan_request *req) | 3140 | struct ieee80211_scan_request *hw_req) |
3141 | { | 3141 | { |
3142 | struct ath10k *ar = hw->priv; | 3142 | struct ath10k *ar = hw->priv; |
3143 | struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); | 3143 | struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); |
3144 | struct cfg80211_scan_request *req = &hw_req->req; | ||
3144 | struct wmi_start_scan_arg arg; | 3145 | struct wmi_start_scan_arg arg; |
3145 | int ret = 0; | 3146 | int ret = 0; |
3146 | int i; | 3147 | int i; |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 83cb39efb636..f5727c7a53b8 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -2409,8 +2409,9 @@ void ath_offchannel_timer(unsigned long data) | |||
2409 | } | 2409 | } |
2410 | 2410 | ||
2411 | static int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 2411 | static int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
2412 | struct cfg80211_scan_request *req) | 2412 | struct ieee80211_scan_request *hw_req) |
2413 | { | 2413 | { |
2414 | struct cfg80211_scan_request *req = &hw_req->req; | ||
2414 | struct ath_softc *sc = hw->priv; | 2415 | struct ath_softc *sc = hw->priv; |
2415 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 2416 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
2416 | int ret = 0; | 2417 | int ret = 0; |
diff --git a/drivers/net/wireless/cw1200/scan.c b/drivers/net/wireless/cw1200/scan.c index 9afcd4ce3368..b2fb6c632092 100644 --- a/drivers/net/wireless/cw1200/scan.c +++ b/drivers/net/wireless/cw1200/scan.c | |||
@@ -53,9 +53,10 @@ static int cw1200_scan_start(struct cw1200_common *priv, struct wsm_scan *scan) | |||
53 | 53 | ||
54 | int cw1200_hw_scan(struct ieee80211_hw *hw, | 54 | int cw1200_hw_scan(struct ieee80211_hw *hw, |
55 | struct ieee80211_vif *vif, | 55 | struct ieee80211_vif *vif, |
56 | struct cfg80211_scan_request *req) | 56 | struct ieee80211_scan_request *hw_req) |
57 | { | 57 | { |
58 | struct cw1200_common *priv = hw->priv; | 58 | struct cw1200_common *priv = hw->priv; |
59 | struct cfg80211_scan_request *req = &hw_req->req; | ||
59 | struct wsm_template_frame frame = { | 60 | struct wsm_template_frame frame = { |
60 | .frame_type = WSM_FRAME_TYPE_PROBE_REQUEST, | 61 | .frame_type = WSM_FRAME_TYPE_PROBE_REQUEST, |
61 | }; | 62 | }; |
diff --git a/drivers/net/wireless/cw1200/scan.h b/drivers/net/wireless/cw1200/scan.h index 5a8296ccfa82..cc75459e5784 100644 --- a/drivers/net/wireless/cw1200/scan.h +++ b/drivers/net/wireless/cw1200/scan.h | |||
@@ -41,7 +41,7 @@ struct cw1200_scan { | |||
41 | 41 | ||
42 | int cw1200_hw_scan(struct ieee80211_hw *hw, | 42 | int cw1200_hw_scan(struct ieee80211_hw *hw, |
43 | struct ieee80211_vif *vif, | 43 | struct ieee80211_vif *vif, |
44 | struct cfg80211_scan_request *req); | 44 | struct ieee80211_scan_request *hw_req); |
45 | void cw1200_scan_work(struct work_struct *work); | 45 | void cw1200_scan_work(struct work_struct *work); |
46 | void cw1200_scan_timeout(struct work_struct *work); | 46 | void cw1200_scan_timeout(struct work_struct *work); |
47 | void cw1200_clear_recent_scan_work(struct work_struct *work); | 47 | void cw1200_clear_recent_scan_work(struct work_struct *work); |
diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index ecc674627e6e..03de7467aecf 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c | |||
@@ -1572,8 +1572,9 @@ il_scan_initiate(struct il_priv *il, struct ieee80211_vif *vif) | |||
1572 | 1572 | ||
1573 | int | 1573 | int |
1574 | il_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 1574 | il_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
1575 | struct cfg80211_scan_request *req) | 1575 | struct ieee80211_scan_request *hw_req) |
1576 | { | 1576 | { |
1577 | struct cfg80211_scan_request *req = &hw_req->req; | ||
1577 | struct il_priv *il = hw->priv; | 1578 | struct il_priv *il = hw->priv; |
1578 | int ret; | 1579 | int ret; |
1579 | 1580 | ||
diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h index ea5c0f863c4e..5b972798bdff 100644 --- a/drivers/net/wireless/iwlegacy/common.h +++ b/drivers/net/wireless/iwlegacy/common.h | |||
@@ -1787,7 +1787,7 @@ int il_scan_cancel(struct il_priv *il); | |||
1787 | int il_scan_cancel_timeout(struct il_priv *il, unsigned long ms); | 1787 | int il_scan_cancel_timeout(struct il_priv *il, unsigned long ms); |
1788 | void il_force_scan_end(struct il_priv *il); | 1788 | void il_force_scan_end(struct il_priv *il); |
1789 | int il_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 1789 | int il_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
1790 | struct cfg80211_scan_request *req); | 1790 | struct ieee80211_scan_request *hw_req); |
1791 | void il_internal_short_hw_scan(struct il_priv *il); | 1791 | void il_internal_short_hw_scan(struct il_priv *il); |
1792 | int il_force_reset(struct il_priv *il, bool external); | 1792 | int il_force_reset(struct il_priv *il, bool external); |
1793 | u16 il_fill_probe_req(struct il_priv *il, struct ieee80211_mgmt *frame, | 1793 | u16 il_fill_probe_req(struct il_priv *il, struct ieee80211_mgmt *frame, |
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index 29af7b51e370..afb98f4fdaf3 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c | |||
@@ -1495,9 +1495,10 @@ static int iwlagn_mac_change_interface(struct ieee80211_hw *hw, | |||
1495 | 1495 | ||
1496 | static int iwlagn_mac_hw_scan(struct ieee80211_hw *hw, | 1496 | static int iwlagn_mac_hw_scan(struct ieee80211_hw *hw, |
1497 | struct ieee80211_vif *vif, | 1497 | struct ieee80211_vif *vif, |
1498 | struct cfg80211_scan_request *req) | 1498 | struct ieee80211_scan_request *hw_req) |
1499 | { | 1499 | { |
1500 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); | 1500 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); |
1501 | struct cfg80211_scan_request *req = &hw_req->req; | ||
1501 | int ret; | 1502 | int ret; |
1502 | 1503 | ||
1503 | IWL_DEBUG_MAC80211(priv, "enter\n"); | 1504 | IWL_DEBUG_MAC80211(priv, "enter\n"); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 7215f5980186..7dd363dd3ad3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -1537,9 +1537,10 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, | |||
1537 | 1537 | ||
1538 | static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, | 1538 | static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, |
1539 | struct ieee80211_vif *vif, | 1539 | struct ieee80211_vif *vif, |
1540 | struct cfg80211_scan_request *req) | 1540 | struct ieee80211_scan_request *hw_req) |
1541 | { | 1541 | { |
1542 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1542 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1543 | struct cfg80211_scan_request *req = &hw_req->req; | ||
1543 | int ret; | 1544 | int ret; |
1544 | 1545 | ||
1545 | if (req->n_channels == 0 || req->n_channels > MAX_NUM_SCAN_CHANNELS) | 1546 | if (req->n_channels == 0 || req->n_channels > MAX_NUM_SCAN_CHANNELS) |
@@ -1827,7 +1828,7 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, | |||
1827 | static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, | 1828 | static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, |
1828 | struct ieee80211_vif *vif, | 1829 | struct ieee80211_vif *vif, |
1829 | struct cfg80211_sched_scan_request *req, | 1830 | struct cfg80211_sched_scan_request *req, |
1830 | struct ieee80211_sched_scan_ies *ies) | 1831 | struct ieee80211_scan_ies *ies) |
1831 | { | 1832 | { |
1832 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1833 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1833 | int ret; | 1834 | int ret; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index fcc6c29482d0..97630f9a7cb9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -854,7 +854,7 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, | |||
854 | int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, | 854 | int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, |
855 | struct ieee80211_vif *vif, | 855 | struct ieee80211_vif *vif, |
856 | struct cfg80211_sched_scan_request *req, | 856 | struct cfg80211_sched_scan_request *req, |
857 | struct ieee80211_sched_scan_ies *ies); | 857 | struct ieee80211_scan_ies *ies); |
858 | int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm, | 858 | int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm, |
859 | struct cfg80211_sched_scan_request *req); | 859 | struct cfg80211_sched_scan_request *req); |
860 | int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, | 860 | int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 4b6c7d4bd199..3206fa097255 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c | |||
@@ -204,7 +204,8 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd, | |||
204 | */ | 204 | */ |
205 | static u16 iwl_mvm_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta, | 205 | static u16 iwl_mvm_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta, |
206 | int n_ssids, const u8 *ssid, int ssid_len, | 206 | int n_ssids, const u8 *ssid, int ssid_len, |
207 | const u8 *ie, int ie_len, | 207 | const u8 *band_ie, int band_ie_len, |
208 | const u8 *common_ie, int common_ie_len, | ||
208 | int left) | 209 | int left) |
209 | { | 210 | { |
210 | int len = 0; | 211 | int len = 0; |
@@ -244,12 +245,19 @@ static u16 iwl_mvm_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta, | |||
244 | 245 | ||
245 | len += ssid_len + 2; | 246 | len += ssid_len + 2; |
246 | 247 | ||
247 | if (WARN_ON(left < ie_len)) | 248 | if (WARN_ON(left < band_ie_len + common_ie_len)) |
248 | return len; | 249 | return len; |
249 | 250 | ||
250 | if (ie && ie_len) { | 251 | if (band_ie && band_ie_len) { |
251 | memcpy(pos, ie, ie_len); | 252 | memcpy(pos, band_ie, band_ie_len); |
252 | len += ie_len; | 253 | pos += band_ie_len; |
254 | len += band_ie_len; | ||
255 | } | ||
256 | |||
257 | if (common_ie && common_ie_len) { | ||
258 | memcpy(pos, common_ie, common_ie_len); | ||
259 | pos += common_ie_len; | ||
260 | len += common_ie_len; | ||
253 | } | 261 | } |
254 | 262 | ||
255 | return (u16)len; | 263 | return (u16)len; |
@@ -382,7 +390,7 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, | |||
382 | (struct ieee80211_mgmt *)cmd->data, | 390 | (struct ieee80211_mgmt *)cmd->data, |
383 | vif->addr, | 391 | vif->addr, |
384 | req->n_ssids, ssid, ssid_len, | 392 | req->n_ssids, ssid, ssid_len, |
385 | req->ie, req->ie_len, | 393 | req->ie, req->ie_len, NULL, 0, |
386 | mvm->fw->ucode_capa.max_probe_length)); | 394 | mvm->fw->ucode_capa.max_probe_length)); |
387 | 395 | ||
388 | iwl_mvm_scan_fill_channels(cmd, req, basic_ssid, ¶ms); | 396 | iwl_mvm_scan_fill_channels(cmd, req, basic_ssid, ¶ms); |
@@ -561,7 +569,7 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, | |||
561 | 569 | ||
562 | static void iwl_scan_offload_build_tx_cmd(struct iwl_mvm *mvm, | 570 | static void iwl_scan_offload_build_tx_cmd(struct iwl_mvm *mvm, |
563 | struct ieee80211_vif *vif, | 571 | struct ieee80211_vif *vif, |
564 | struct ieee80211_sched_scan_ies *ies, | 572 | struct ieee80211_scan_ies *ies, |
565 | enum ieee80211_band band, | 573 | enum ieee80211_band band, |
566 | struct iwl_tx_cmd *cmd, | 574 | struct iwl_tx_cmd *cmd, |
567 | u8 *data) | 575 | u8 *data) |
@@ -577,7 +585,8 @@ static void iwl_scan_offload_build_tx_cmd(struct iwl_mvm *mvm, | |||
577 | cmd_len = iwl_mvm_fill_probe_req((struct ieee80211_mgmt *)data, | 585 | cmd_len = iwl_mvm_fill_probe_req((struct ieee80211_mgmt *)data, |
578 | vif->addr, | 586 | vif->addr, |
579 | 1, NULL, 0, | 587 | 1, NULL, 0, |
580 | ies->ie[band], ies->len[band], | 588 | ies->ies[band], ies->len[band], |
589 | ies->common_ies, ies->common_ie_len, | ||
581 | SCAN_OFFLOAD_PROBE_REQ_SIZE); | 590 | SCAN_OFFLOAD_PROBE_REQ_SIZE); |
582 | cmd->len = cpu_to_le16(cmd_len); | 591 | cmd->len = cpu_to_le16(cmd_len); |
583 | } | 592 | } |
@@ -735,7 +744,7 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm, | |||
735 | int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, | 744 | int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, |
736 | struct ieee80211_vif *vif, | 745 | struct ieee80211_vif *vif, |
737 | struct cfg80211_sched_scan_request *req, | 746 | struct cfg80211_sched_scan_request *req, |
738 | struct ieee80211_sched_scan_ies *ies) | 747 | struct ieee80211_scan_ies *ies) |
739 | { | 748 | { |
740 | int band_2ghz = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels; | 749 | int band_2ghz = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels; |
741 | int band_5ghz = mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; | 750 | int band_5ghz = mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; |
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index a312c653d116..eba51460a5de 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -781,6 +781,36 @@ static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan, | |||
781 | netif_rx(skb); | 781 | netif_rx(skb); |
782 | } | 782 | } |
783 | 783 | ||
784 | struct mac80211_hwsim_addr_match_data { | ||
785 | u8 addr[ETH_ALEN]; | ||
786 | bool ret; | ||
787 | }; | ||
788 | |||
789 | static void mac80211_hwsim_addr_iter(void *data, u8 *mac, | ||
790 | struct ieee80211_vif *vif) | ||
791 | { | ||
792 | struct mac80211_hwsim_addr_match_data *md = data; | ||
793 | |||
794 | if (memcmp(mac, md->addr, ETH_ALEN) == 0) | ||
795 | md->ret = true; | ||
796 | } | ||
797 | |||
798 | static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data, | ||
799 | const u8 *addr) | ||
800 | { | ||
801 | struct mac80211_hwsim_addr_match_data md = { | ||
802 | .ret = false, | ||
803 | }; | ||
804 | |||
805 | memcpy(md.addr, addr, ETH_ALEN); | ||
806 | |||
807 | ieee80211_iterate_active_interfaces_atomic(data->hw, | ||
808 | IEEE80211_IFACE_ITER_NORMAL, | ||
809 | mac80211_hwsim_addr_iter, | ||
810 | &md); | ||
811 | |||
812 | return md.ret; | ||
813 | } | ||
784 | 814 | ||
785 | static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, | 815 | static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, |
786 | struct sk_buff *skb) | 816 | struct sk_buff *skb) |
@@ -798,8 +828,7 @@ static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, | |||
798 | /* Allow unicast frames to own address if there is a pending | 828 | /* Allow unicast frames to own address if there is a pending |
799 | * PS-Poll */ | 829 | * PS-Poll */ |
800 | if (data->ps_poll_pending && | 830 | if (data->ps_poll_pending && |
801 | memcmp(data->hw->wiphy->perm_addr, skb->data + 4, | 831 | mac80211_hwsim_addr_match(data, skb->data + 4)) { |
802 | ETH_ALEN) == 0) { | ||
803 | data->ps_poll_pending = false; | 832 | data->ps_poll_pending = false; |
804 | return true; | 833 | return true; |
805 | } | 834 | } |
@@ -809,39 +838,6 @@ static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, | |||
809 | return true; | 838 | return true; |
810 | } | 839 | } |
811 | 840 | ||
812 | |||
813 | struct mac80211_hwsim_addr_match_data { | ||
814 | bool ret; | ||
815 | const u8 *addr; | ||
816 | }; | ||
817 | |||
818 | static void mac80211_hwsim_addr_iter(void *data, u8 *mac, | ||
819 | struct ieee80211_vif *vif) | ||
820 | { | ||
821 | struct mac80211_hwsim_addr_match_data *md = data; | ||
822 | if (memcmp(mac, md->addr, ETH_ALEN) == 0) | ||
823 | md->ret = true; | ||
824 | } | ||
825 | |||
826 | |||
827 | static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data, | ||
828 | const u8 *addr) | ||
829 | { | ||
830 | struct mac80211_hwsim_addr_match_data md; | ||
831 | |||
832 | if (memcmp(addr, data->hw->wiphy->perm_addr, ETH_ALEN) == 0) | ||
833 | return true; | ||
834 | |||
835 | md.ret = false; | ||
836 | md.addr = addr; | ||
837 | ieee80211_iterate_active_interfaces_atomic(data->hw, | ||
838 | IEEE80211_IFACE_ITER_NORMAL, | ||
839 | mac80211_hwsim_addr_iter, | ||
840 | &md); | ||
841 | |||
842 | return md.ret; | ||
843 | } | ||
844 | |||
845 | static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, | 841 | static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, |
846 | struct sk_buff *my_skb, | 842 | struct sk_buff *my_skb, |
847 | int dst_portid) | 843 | int dst_portid) |
@@ -1740,9 +1736,10 @@ static void hw_scan_work(struct work_struct *work) | |||
1740 | 1736 | ||
1741 | static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, | 1737 | static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, |
1742 | struct ieee80211_vif *vif, | 1738 | struct ieee80211_vif *vif, |
1743 | struct cfg80211_scan_request *req) | 1739 | struct ieee80211_scan_request *hw_req) |
1744 | { | 1740 | { |
1745 | struct mac80211_hwsim_data *hwsim = hw->priv; | 1741 | struct mac80211_hwsim_data *hwsim = hw->priv; |
1742 | struct cfg80211_scan_request *req = &hw_req->req; | ||
1746 | 1743 | ||
1747 | mutex_lock(&hwsim->mutex); | 1744 | mutex_lock(&hwsim->mutex); |
1748 | if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { | 1745 | if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { |
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 8e7b9c9696f6..e33a0347d3e2 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c | |||
@@ -2609,7 +2609,8 @@ static int | |||
2609 | mwifiex_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | 2609 | mwifiex_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, |
2610 | const u8 *peer, u8 action_code, u8 dialog_token, | 2610 | const u8 *peer, u8 action_code, u8 dialog_token, |
2611 | u16 status_code, u32 peer_capability, | 2611 | u16 status_code, u32 peer_capability, |
2612 | const u8 *extra_ies, size_t extra_ies_len) | 2612 | bool initiator, const u8 *extra_ies, |
2613 | size_t extra_ies_len) | ||
2613 | { | 2614 | { |
2614 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | 2615 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); |
2615 | int ret; | 2616 | int ret; |
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index 4e782f18ae34..38234851457e 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c | |||
@@ -991,8 +991,9 @@ out: | |||
991 | 991 | ||
992 | static int wl1251_op_hw_scan(struct ieee80211_hw *hw, | 992 | static int wl1251_op_hw_scan(struct ieee80211_hw *hw, |
993 | struct ieee80211_vif *vif, | 993 | struct ieee80211_vif *vif, |
994 | struct cfg80211_scan_request *req) | 994 | struct ieee80211_scan_request *hw_req) |
995 | { | 995 | { |
996 | struct cfg80211_scan_request *req = &hw_req->req; | ||
996 | struct wl1251 *wl = hw->priv; | 997 | struct wl1251 *wl = hw->priv; |
997 | struct sk_buff *skb; | 998 | struct sk_buff *skb; |
998 | size_t ssid_len = 0; | 999 | size_t ssid_len = 0; |
diff --git a/drivers/net/wireless/ti/wl12xx/scan.c b/drivers/net/wireless/ti/wl12xx/scan.c index 7541bd1a4a4b..0c0d5cd98514 100644 --- a/drivers/net/wireless/ti/wl12xx/scan.c +++ b/drivers/net/wireless/ti/wl12xx/scan.c | |||
@@ -156,7 +156,7 @@ static int wl1271_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
156 | cmd->params.role_id, band, | 156 | cmd->params.role_id, band, |
157 | wl->scan.ssid, wl->scan.ssid_len, | 157 | wl->scan.ssid, wl->scan.ssid_len, |
158 | wl->scan.req->ie, | 158 | wl->scan.req->ie, |
159 | wl->scan.req->ie_len, false); | 159 | wl->scan.req->ie_len, NULL, 0, false); |
160 | if (ret < 0) { | 160 | if (ret < 0) { |
161 | wl1271_error("PROBE request template failed"); | 161 | wl1271_error("PROBE request template failed"); |
162 | goto out; | 162 | goto out; |
@@ -317,7 +317,7 @@ static void wl12xx_adjust_channels(struct wl1271_cmd_sched_scan_config *cmd, | |||
317 | int wl1271_scan_sched_scan_config(struct wl1271 *wl, | 317 | int wl1271_scan_sched_scan_config(struct wl1271 *wl, |
318 | struct wl12xx_vif *wlvif, | 318 | struct wl12xx_vif *wlvif, |
319 | struct cfg80211_sched_scan_request *req, | 319 | struct cfg80211_sched_scan_request *req, |
320 | struct ieee80211_sched_scan_ies *ies) | 320 | struct ieee80211_scan_ies *ies) |
321 | { | 321 | { |
322 | struct wl1271_cmd_sched_scan_config *cfg = NULL; | 322 | struct wl1271_cmd_sched_scan_config *cfg = NULL; |
323 | struct wlcore_scan_channels *cfg_channels = NULL; | 323 | struct wlcore_scan_channels *cfg_channels = NULL; |
@@ -378,8 +378,11 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, | |||
378 | wlvif->role_id, band, | 378 | wlvif->role_id, band, |
379 | req->ssids[0].ssid, | 379 | req->ssids[0].ssid, |
380 | req->ssids[0].ssid_len, | 380 | req->ssids[0].ssid_len, |
381 | ies->ie[band], | 381 | ies->ies[band], |
382 | ies->len[band], true); | 382 | ies->len[band], |
383 | ies->common_ies, | ||
384 | ies->common_ie_len, | ||
385 | true); | ||
383 | if (ret < 0) { | 386 | if (ret < 0) { |
384 | wl1271_error("2.4GHz PROBE request template failed"); | 387 | wl1271_error("2.4GHz PROBE request template failed"); |
385 | goto out; | 388 | goto out; |
@@ -392,8 +395,11 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, | |||
392 | wlvif->role_id, band, | 395 | wlvif->role_id, band, |
393 | req->ssids[0].ssid, | 396 | req->ssids[0].ssid, |
394 | req->ssids[0].ssid_len, | 397 | req->ssids[0].ssid_len, |
395 | ies->ie[band], | 398 | ies->ies[band], |
396 | ies->len[band], true); | 399 | ies->len[band], |
400 | ies->common_ies, | ||
401 | ies->common_ie_len, | ||
402 | true); | ||
397 | if (ret < 0) { | 403 | if (ret < 0) { |
398 | wl1271_error("5GHz PROBE request template failed"); | 404 | wl1271_error("5GHz PROBE request template failed"); |
399 | goto out; | 405 | goto out; |
@@ -449,7 +455,7 @@ out_free: | |||
449 | 455 | ||
450 | int wl12xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, | 456 | int wl12xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
451 | struct cfg80211_sched_scan_request *req, | 457 | struct cfg80211_sched_scan_request *req, |
452 | struct ieee80211_sched_scan_ies *ies) | 458 | struct ieee80211_scan_ies *ies) |
453 | { | 459 | { |
454 | int ret; | 460 | int ret; |
455 | 461 | ||
diff --git a/drivers/net/wireless/ti/wl12xx/scan.h b/drivers/net/wireless/ti/wl12xx/scan.h index 264af7ac2785..427f9af85a00 100644 --- a/drivers/net/wireless/ti/wl12xx/scan.h +++ b/drivers/net/wireless/ti/wl12xx/scan.h | |||
@@ -135,6 +135,6 @@ int wl12xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif); | |||
135 | void wl12xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif); | 135 | void wl12xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif); |
136 | int wl12xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, | 136 | int wl12xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
137 | struct cfg80211_sched_scan_request *req, | 137 | struct cfg80211_sched_scan_request *req, |
138 | struct ieee80211_sched_scan_ies *ies); | 138 | struct ieee80211_scan_ies *ies); |
139 | void wl12xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif); | 139 | void wl12xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif); |
140 | #endif | 140 | #endif |
diff --git a/drivers/net/wireless/ti/wl18xx/scan.c b/drivers/net/wireless/ti/wl18xx/scan.c index 2b642f8c9266..98666f235a12 100644 --- a/drivers/net/wireless/ti/wl18xx/scan.c +++ b/drivers/net/wireless/ti/wl18xx/scan.c | |||
@@ -113,6 +113,8 @@ static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
113 | req->ssids ? req->ssids[0].ssid_len : 0, | 113 | req->ssids ? req->ssids[0].ssid_len : 0, |
114 | req->ie, | 114 | req->ie, |
115 | req->ie_len, | 115 | req->ie_len, |
116 | NULL, | ||
117 | 0, | ||
116 | false); | 118 | false); |
117 | if (ret < 0) { | 119 | if (ret < 0) { |
118 | wl1271_error("2.4GHz PROBE request template failed"); | 120 | wl1271_error("2.4GHz PROBE request template failed"); |
@@ -128,6 +130,8 @@ static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
128 | req->ssids ? req->ssids[0].ssid_len : 0, | 130 | req->ssids ? req->ssids[0].ssid_len : 0, |
129 | req->ie, | 131 | req->ie, |
130 | req->ie_len, | 132 | req->ie_len, |
133 | NULL, | ||
134 | 0, | ||
131 | false); | 135 | false); |
132 | if (ret < 0) { | 136 | if (ret < 0) { |
133 | wl1271_error("5GHz PROBE request template failed"); | 137 | wl1271_error("5GHz PROBE request template failed"); |
@@ -161,7 +165,7 @@ static | |||
161 | int wl18xx_scan_sched_scan_config(struct wl1271 *wl, | 165 | int wl18xx_scan_sched_scan_config(struct wl1271 *wl, |
162 | struct wl12xx_vif *wlvif, | 166 | struct wl12xx_vif *wlvif, |
163 | struct cfg80211_sched_scan_request *req, | 167 | struct cfg80211_sched_scan_request *req, |
164 | struct ieee80211_sched_scan_ies *ies) | 168 | struct ieee80211_scan_ies *ies) |
165 | { | 169 | { |
166 | struct wl18xx_cmd_scan_params *cmd; | 170 | struct wl18xx_cmd_scan_params *cmd; |
167 | struct wlcore_scan_channels *cmd_channels = NULL; | 171 | struct wlcore_scan_channels *cmd_channels = NULL; |
@@ -237,8 +241,10 @@ int wl18xx_scan_sched_scan_config(struct wl1271 *wl, | |||
237 | cmd->role_id, band, | 241 | cmd->role_id, band, |
238 | req->ssids ? req->ssids[0].ssid : NULL, | 242 | req->ssids ? req->ssids[0].ssid : NULL, |
239 | req->ssids ? req->ssids[0].ssid_len : 0, | 243 | req->ssids ? req->ssids[0].ssid_len : 0, |
240 | ies->ie[band], | 244 | ies->ies[band], |
241 | ies->len[band], | 245 | ies->len[band], |
246 | ies->common_ies, | ||
247 | ies->common_ie_len, | ||
242 | true); | 248 | true); |
243 | if (ret < 0) { | 249 | if (ret < 0) { |
244 | wl1271_error("2.4GHz PROBE request template failed"); | 250 | wl1271_error("2.4GHz PROBE request template failed"); |
@@ -252,8 +258,10 @@ int wl18xx_scan_sched_scan_config(struct wl1271 *wl, | |||
252 | cmd->role_id, band, | 258 | cmd->role_id, band, |
253 | req->ssids ? req->ssids[0].ssid : NULL, | 259 | req->ssids ? req->ssids[0].ssid : NULL, |
254 | req->ssids ? req->ssids[0].ssid_len : 0, | 260 | req->ssids ? req->ssids[0].ssid_len : 0, |
255 | ies->ie[band], | 261 | ies->ies[band], |
256 | ies->len[band], | 262 | ies->len[band], |
263 | ies->common_ies, | ||
264 | ies->common_ie_len, | ||
257 | true); | 265 | true); |
258 | if (ret < 0) { | 266 | if (ret < 0) { |
259 | wl1271_error("5GHz PROBE request template failed"); | 267 | wl1271_error("5GHz PROBE request template failed"); |
@@ -277,7 +285,7 @@ out: | |||
277 | 285 | ||
278 | int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, | 286 | int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
279 | struct cfg80211_sched_scan_request *req, | 287 | struct cfg80211_sched_scan_request *req, |
280 | struct ieee80211_sched_scan_ies *ies) | 288 | struct ieee80211_scan_ies *ies) |
281 | { | 289 | { |
282 | return wl18xx_scan_sched_scan_config(wl, wlvif, req, ies); | 290 | return wl18xx_scan_sched_scan_config(wl, wlvif, req, ies); |
283 | } | 291 | } |
diff --git a/drivers/net/wireless/ti/wl18xx/scan.h b/drivers/net/wireless/ti/wl18xx/scan.h index eadee42689d1..2e636aa5dba9 100644 --- a/drivers/net/wireless/ti/wl18xx/scan.h +++ b/drivers/net/wireless/ti/wl18xx/scan.h | |||
@@ -122,6 +122,6 @@ int wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif); | |||
122 | void wl18xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif); | 122 | void wl18xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif); |
123 | int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, | 123 | int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
124 | struct cfg80211_sched_scan_request *req, | 124 | struct cfg80211_sched_scan_request *req, |
125 | struct ieee80211_sched_scan_ies *ies); | 125 | struct ieee80211_scan_ies *ies); |
126 | void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif); | 126 | void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif); |
127 | #endif | 127 | #endif |
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 40dc30f4faaa..e269c0a57017 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c | |||
@@ -1124,7 +1124,8 @@ out: | |||
1124 | int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, | 1124 | int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
1125 | u8 role_id, u8 band, | 1125 | u8 role_id, u8 band, |
1126 | const u8 *ssid, size_t ssid_len, | 1126 | const u8 *ssid, size_t ssid_len, |
1127 | const u8 *ie, size_t ie_len, bool sched_scan) | 1127 | const u8 *ie0, size_t ie0_len, const u8 *ie1, |
1128 | size_t ie1_len, bool sched_scan) | ||
1128 | { | 1129 | { |
1129 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | 1130 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); |
1130 | struct sk_buff *skb; | 1131 | struct sk_buff *skb; |
@@ -1136,13 +1137,15 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
1136 | wl1271_debug(DEBUG_SCAN, "build probe request band %d", band); | 1137 | wl1271_debug(DEBUG_SCAN, "build probe request band %d", band); |
1137 | 1138 | ||
1138 | skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, | 1139 | skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, |
1139 | ie_len); | 1140 | ie0_len + ie1_len); |
1140 | if (!skb) { | 1141 | if (!skb) { |
1141 | ret = -ENOMEM; | 1142 | ret = -ENOMEM; |
1142 | goto out; | 1143 | goto out; |
1143 | } | 1144 | } |
1144 | if (ie_len) | 1145 | if (ie0_len) |
1145 | memcpy(skb_put(skb, ie_len), ie, ie_len); | 1146 | memcpy(skb_put(skb, ie0_len), ie0, ie0_len); |
1147 | if (ie1_len) | ||
1148 | memcpy(skb_put(skb, ie1_len), ie1, ie1_len); | ||
1146 | 1149 | ||
1147 | if (sched_scan && | 1150 | if (sched_scan && |
1148 | (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) { | 1151 | (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) { |
diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h index b084830a61cf..6788d7356ca5 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.h +++ b/drivers/net/wireless/ti/wlcore/cmd.h | |||
@@ -64,7 +64,8 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
64 | int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, | 64 | int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
65 | u8 role_id, u8 band, | 65 | u8 role_id, u8 band, |
66 | const u8 *ssid, size_t ssid_len, | 66 | const u8 *ssid, size_t ssid_len, |
67 | const u8 *ie, size_t ie_len, bool sched_scan); | 67 | const u8 *ie, size_t ie_len, const u8 *common_ie, |
68 | size_t common_ie_len, bool sched_scan); | ||
68 | struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, | 69 | struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, |
69 | struct wl12xx_vif *wlvif, | 70 | struct wl12xx_vif *wlvif, |
70 | struct sk_buff *skb); | 71 | struct sk_buff *skb); |
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 3d6028e62750..48f83868f9cb 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c | |||
@@ -3540,8 +3540,9 @@ out: | |||
3540 | 3540 | ||
3541 | static int wl1271_op_hw_scan(struct ieee80211_hw *hw, | 3541 | static int wl1271_op_hw_scan(struct ieee80211_hw *hw, |
3542 | struct ieee80211_vif *vif, | 3542 | struct ieee80211_vif *vif, |
3543 | struct cfg80211_scan_request *req) | 3543 | struct ieee80211_scan_request *hw_req) |
3544 | { | 3544 | { |
3545 | struct cfg80211_scan_request *req = &hw_req->req; | ||
3545 | struct wl1271 *wl = hw->priv; | 3546 | struct wl1271 *wl = hw->priv; |
3546 | int ret; | 3547 | int ret; |
3547 | u8 *ssid = NULL; | 3548 | u8 *ssid = NULL; |
@@ -3636,7 +3637,7 @@ out: | |||
3636 | static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw, | 3637 | static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw, |
3637 | struct ieee80211_vif *vif, | 3638 | struct ieee80211_vif *vif, |
3638 | struct cfg80211_sched_scan_request *req, | 3639 | struct cfg80211_sched_scan_request *req, |
3639 | struct ieee80211_sched_scan_ies *ies) | 3640 | struct ieee80211_scan_ies *ies) |
3640 | { | 3641 | { |
3641 | struct wl1271 *wl = hw->priv; | 3642 | struct wl1271 *wl = hw->priv; |
3642 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | 3643 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); |
diff --git a/drivers/net/wireless/ti/wlcore/scan.h b/drivers/net/wireless/ti/wlcore/scan.h index a6ab24b5c0f9..4dadd0c62cde 100644 --- a/drivers/net/wireless/ti/wlcore/scan.h +++ b/drivers/net/wireless/ti/wlcore/scan.h | |||
@@ -37,7 +37,7 @@ void wl1271_scan_complete_work(struct work_struct *work); | |||
37 | int wl1271_scan_sched_scan_config(struct wl1271 *wl, | 37 | int wl1271_scan_sched_scan_config(struct wl1271 *wl, |
38 | struct wl12xx_vif *wlvif, | 38 | struct wl12xx_vif *wlvif, |
39 | struct cfg80211_sched_scan_request *req, | 39 | struct cfg80211_sched_scan_request *req, |
40 | struct ieee80211_sched_scan_ies *ies); | 40 | struct ieee80211_scan_ies *ies); |
41 | int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif); | 41 | int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif); |
42 | void wlcore_scan_sched_scan_results(struct wl1271 *wl); | 42 | void wlcore_scan_sched_scan_results(struct wl1271 *wl); |
43 | 43 | ||
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index 95a54504f0cc..71320509b56d 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h | |||
@@ -95,7 +95,7 @@ struct wlcore_ops { | |||
95 | int (*scan_stop)(struct wl1271 *wl, struct wl12xx_vif *wlvif); | 95 | int (*scan_stop)(struct wl1271 *wl, struct wl12xx_vif *wlvif); |
96 | int (*sched_scan_start)(struct wl1271 *wl, struct wl12xx_vif *wlvif, | 96 | int (*sched_scan_start)(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
97 | struct cfg80211_sched_scan_request *req, | 97 | struct cfg80211_sched_scan_request *req, |
98 | struct ieee80211_sched_scan_ies *ies); | 98 | struct ieee80211_scan_ies *ies); |
99 | void (*sched_scan_stop)(struct wl1271 *wl, struct wl12xx_vif *wlvif); | 99 | void (*sched_scan_stop)(struct wl1271 *wl, struct wl12xx_vif *wlvif); |
100 | int (*get_spare_blocks)(struct wl1271 *wl, bool is_gem); | 100 | int (*get_spare_blocks)(struct wl1271 *wl, bool is_gem); |
101 | int (*set_key)(struct wl1271 *wl, enum set_key_cmd cmd, | 101 | int (*set_key)(struct wl1271 *wl, enum set_key_cmd cmd, |
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 6bff13f74050..75d17e15da33 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -1621,6 +1621,9 @@ enum ieee80211_reasoncode { | |||
1621 | WLAN_REASON_INVALID_RSN_IE_CAP = 22, | 1621 | WLAN_REASON_INVALID_RSN_IE_CAP = 22, |
1622 | WLAN_REASON_IEEE8021X_FAILED = 23, | 1622 | WLAN_REASON_IEEE8021X_FAILED = 23, |
1623 | WLAN_REASON_CIPHER_SUITE_REJECTED = 24, | 1623 | WLAN_REASON_CIPHER_SUITE_REJECTED = 24, |
1624 | /* TDLS (802.11z) */ | ||
1625 | WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE = 25, | ||
1626 | WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED = 26, | ||
1624 | /* 802.11e */ | 1627 | /* 802.11e */ |
1625 | WLAN_REASON_DISASSOC_UNSPECIFIED_QOS = 32, | 1628 | WLAN_REASON_DISASSOC_UNSPECIFIED_QOS = 32, |
1626 | WLAN_REASON_DISASSOC_QAP_NO_BANDWIDTH = 33, | 1629 | WLAN_REASON_DISASSOC_QAP_NO_BANDWIDTH = 33, |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e46c437944f7..0a080c4de275 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -2266,10 +2266,6 @@ struct cfg80211_qos_map { | |||
2266 | * | 2266 | * |
2267 | * @get_antenna: Get current antenna configuration from device (tx_ant, rx_ant). | 2267 | * @get_antenna: Get current antenna configuration from device (tx_ant, rx_ant). |
2268 | * | 2268 | * |
2269 | * @set_ringparam: Set tx and rx ring sizes. | ||
2270 | * | ||
2271 | * @get_ringparam: Get tx and rx ring current and maximum sizes. | ||
2272 | * | ||
2273 | * @tdls_mgmt: Transmit a TDLS management frame. | 2269 | * @tdls_mgmt: Transmit a TDLS management frame. |
2274 | * @tdls_oper: Perform a high-level TDLS operation (e.g. TDLS link setup). | 2270 | * @tdls_oper: Perform a high-level TDLS operation (e.g. TDLS link setup). |
2275 | * | 2271 | * |
@@ -2278,16 +2274,6 @@ struct cfg80211_qos_map { | |||
2278 | * | 2274 | * |
2279 | * @set_noack_map: Set the NoAck Map for the TIDs. | 2275 | * @set_noack_map: Set the NoAck Map for the TIDs. |
2280 | * | 2276 | * |
2281 | * @get_et_sset_count: Ethtool API to get string-set count. | ||
2282 | * See @ethtool_ops.get_sset_count | ||
2283 | * | ||
2284 | * @get_et_stats: Ethtool API to get a set of u64 stats. | ||
2285 | * See @ethtool_ops.get_ethtool_stats | ||
2286 | * | ||
2287 | * @get_et_strings: Ethtool API to get a set of strings to describe stats | ||
2288 | * and perhaps other supported types of ethtool data-sets. | ||
2289 | * See @ethtool_ops.get_strings | ||
2290 | * | ||
2291 | * @get_channel: Get the current operating channel for the virtual interface. | 2277 | * @get_channel: Get the current operating channel for the virtual interface. |
2292 | * For monitor interfaces, it should return %NULL unless there's a single | 2278 | * For monitor interfaces, it should return %NULL unless there's a single |
2293 | * current monitoring channel. | 2279 | * current monitoring channel. |
@@ -2315,7 +2301,12 @@ struct cfg80211_qos_map { | |||
2315 | * reliability. This operation can not fail. | 2301 | * reliability. This operation can not fail. |
2316 | * @set_coalesce: Set coalesce parameters. | 2302 | * @set_coalesce: Set coalesce parameters. |
2317 | * | 2303 | * |
2318 | * @channel_switch: initiate channel-switch procedure (with CSA) | 2304 | * @channel_switch: initiate channel-switch procedure (with CSA). Driver is |
2305 | * responsible for veryfing if the switch is possible. Since this is | ||
2306 | * inherently tricky driver may decide to disconnect an interface later | ||
2307 | * with cfg80211_stop_iface(). This doesn't mean driver can accept | ||
2308 | * everything. It should do it's best to verify requests and reject them | ||
2309 | * as soon as possible. | ||
2319 | * | 2310 | * |
2320 | * @set_qos_map: Set QoS mapping information to the driver | 2311 | * @set_qos_map: Set QoS mapping information to the driver |
2321 | * | 2312 | * |
@@ -2503,10 +2494,6 @@ struct cfg80211_ops { | |||
2503 | int (*set_antenna)(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant); | 2494 | int (*set_antenna)(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant); |
2504 | int (*get_antenna)(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant); | 2495 | int (*get_antenna)(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant); |
2505 | 2496 | ||
2506 | int (*set_ringparam)(struct wiphy *wiphy, u32 tx, u32 rx); | ||
2507 | void (*get_ringparam)(struct wiphy *wiphy, | ||
2508 | u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max); | ||
2509 | |||
2510 | int (*sched_scan_start)(struct wiphy *wiphy, | 2497 | int (*sched_scan_start)(struct wiphy *wiphy, |
2511 | struct net_device *dev, | 2498 | struct net_device *dev, |
2512 | struct cfg80211_sched_scan_request *request); | 2499 | struct cfg80211_sched_scan_request *request); |
@@ -2518,7 +2505,7 @@ struct cfg80211_ops { | |||
2518 | int (*tdls_mgmt)(struct wiphy *wiphy, struct net_device *dev, | 2505 | int (*tdls_mgmt)(struct wiphy *wiphy, struct net_device *dev, |
2519 | const u8 *peer, u8 action_code, u8 dialog_token, | 2506 | const u8 *peer, u8 action_code, u8 dialog_token, |
2520 | u16 status_code, u32 peer_capability, | 2507 | u16 status_code, u32 peer_capability, |
2521 | const u8 *buf, size_t len); | 2508 | bool initiator, const u8 *buf, size_t len); |
2522 | int (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev, | 2509 | int (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev, |
2523 | const u8 *peer, enum nl80211_tdls_operation oper); | 2510 | const u8 *peer, enum nl80211_tdls_operation oper); |
2524 | 2511 | ||
@@ -2529,13 +2516,6 @@ struct cfg80211_ops { | |||
2529 | struct net_device *dev, | 2516 | struct net_device *dev, |
2530 | u16 noack_map); | 2517 | u16 noack_map); |
2531 | 2518 | ||
2532 | int (*get_et_sset_count)(struct wiphy *wiphy, | ||
2533 | struct net_device *dev, int sset); | ||
2534 | void (*get_et_stats)(struct wiphy *wiphy, struct net_device *dev, | ||
2535 | struct ethtool_stats *stats, u64 *data); | ||
2536 | void (*get_et_strings)(struct wiphy *wiphy, struct net_device *dev, | ||
2537 | u32 sset, u8 *data); | ||
2538 | |||
2539 | int (*get_channel)(struct wiphy *wiphy, | 2519 | int (*get_channel)(struct wiphy *wiphy, |
2540 | struct wireless_dev *wdev, | 2520 | struct wireless_dev *wdev, |
2541 | struct cfg80211_chan_def *chandef); | 2521 | struct cfg80211_chan_def *chandef); |
@@ -4843,6 +4823,10 @@ void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
4843 | */ | 4823 | */ |
4844 | void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy); | 4824 | void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy); |
4845 | 4825 | ||
4826 | |||
4827 | /* ethtool helper */ | ||
4828 | void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info); | ||
4829 | |||
4846 | /* Logging, debugging and troubleshooting/diagnostic helpers. */ | 4830 | /* Logging, debugging and troubleshooting/diagnostic helpers. */ |
4847 | 4831 | ||
4848 | /* wiphy_printk helpers, similar to dev_printk */ | 4832 | /* wiphy_printk helpers, similar to dev_printk */ |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 421b6ecb4b2c..9ce5cb17ed82 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -754,20 +754,25 @@ struct ieee80211_tx_info { | |||
754 | }; | 754 | }; |
755 | 755 | ||
756 | /** | 756 | /** |
757 | * struct ieee80211_sched_scan_ies - scheduled scan IEs | 757 | * struct ieee80211_scan_ies - descriptors for different blocks of IEs |
758 | * | 758 | * |
759 | * This structure is used to pass the appropriate IEs to be used in scheduled | 759 | * This structure is used to point to different blocks of IEs in HW scan |
760 | * scans for all bands. It contains both the IEs passed from the userspace | 760 | * and scheduled scan. These blocks contain the IEs passed by userspace |
761 | * and the ones generated by mac80211. | 761 | * and the ones generated by mac80211. |
762 | * | 762 | * |
763 | * @ie: array with the IEs for each supported band | 763 | * @ies: pointers to band specific IEs. |
764 | * @len: array with the total length of the IEs for each band | 764 | * @len: lengths of band_specific IEs. |
765 | * @common_ies: IEs for all bands (especially vendor specific ones) | ||
766 | * @common_ie_len: length of the common_ies | ||
765 | */ | 767 | */ |
766 | struct ieee80211_sched_scan_ies { | 768 | struct ieee80211_scan_ies { |
767 | u8 *ie[IEEE80211_NUM_BANDS]; | 769 | const u8 *ies[IEEE80211_NUM_BANDS]; |
768 | size_t len[IEEE80211_NUM_BANDS]; | 770 | size_t len[IEEE80211_NUM_BANDS]; |
771 | const u8 *common_ies; | ||
772 | size_t common_ie_len; | ||
769 | }; | 773 | }; |
770 | 774 | ||
775 | |||
771 | static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb) | 776 | static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb) |
772 | { | 777 | { |
773 | return (struct ieee80211_tx_info *)skb->cb; | 778 | return (struct ieee80211_tx_info *)skb->cb; |
@@ -1601,11 +1606,8 @@ struct ieee80211_tx_control { | |||
1601 | * is not enabled the default action is to disconnect when getting the | 1606 | * is not enabled the default action is to disconnect when getting the |
1602 | * CSA frame. | 1607 | * CSA frame. |
1603 | * | 1608 | * |
1604 | * @IEEE80211_HW_CHANGE_RUNNING_CHANCTX: The hardware can change a | 1609 | * @IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS: The HW supports scanning on all bands |
1605 | * channel context on-the-fly. This is needed for channel switch | 1610 | * in one command, mac80211 doesn't have to run separate scans per band. |
1606 | * on single-channel hardware. It can also be used as an | ||
1607 | * optimization in certain channel switch cases with | ||
1608 | * multi-channel. | ||
1609 | */ | 1611 | */ |
1610 | enum ieee80211_hw_flags { | 1612 | enum ieee80211_hw_flags { |
1611 | IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, | 1613 | IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, |
@@ -1637,7 +1639,8 @@ enum ieee80211_hw_flags { | |||
1637 | IEEE80211_HW_TIMING_BEACON_ONLY = 1<<26, | 1639 | IEEE80211_HW_TIMING_BEACON_ONLY = 1<<26, |
1638 | IEEE80211_HW_SUPPORTS_HT_CCK_RATES = 1<<27, | 1640 | IEEE80211_HW_SUPPORTS_HT_CCK_RATES = 1<<27, |
1639 | IEEE80211_HW_CHANCTX_STA_CSA = 1<<28, | 1641 | IEEE80211_HW_CHANCTX_STA_CSA = 1<<28, |
1640 | IEEE80211_HW_CHANGE_RUNNING_CHANCTX = 1<<29, | 1642 | /* bit 29 unused */ |
1643 | IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS = 1<<30, | ||
1641 | }; | 1644 | }; |
1642 | 1645 | ||
1643 | /** | 1646 | /** |
@@ -1764,6 +1767,19 @@ struct ieee80211_hw { | |||
1764 | }; | 1767 | }; |
1765 | 1768 | ||
1766 | /** | 1769 | /** |
1770 | * struct ieee80211_scan_request - hw scan request | ||
1771 | * | ||
1772 | * @ies: pointers different parts of IEs (in req.ie) | ||
1773 | * @req: cfg80211 request. | ||
1774 | */ | ||
1775 | struct ieee80211_scan_request { | ||
1776 | struct ieee80211_scan_ies ies; | ||
1777 | |||
1778 | /* Keep last */ | ||
1779 | struct cfg80211_scan_request req; | ||
1780 | }; | ||
1781 | |||
1782 | /** | ||
1767 | * wiphy_to_ieee80211_hw - return a mac80211 driver hw struct from a wiphy | 1783 | * wiphy_to_ieee80211_hw - return a mac80211 driver hw struct from a wiphy |
1768 | * | 1784 | * |
1769 | * @wiphy: the &struct wiphy which we want to query | 1785 | * @wiphy: the &struct wiphy which we want to query |
@@ -2764,6 +2780,15 @@ enum ieee80211_roc_type { | |||
2764 | * mac80211 will transmit the frame right away. | 2780 | * mac80211 will transmit the frame right away. |
2765 | * The callback is optional and can (should!) sleep. | 2781 | * The callback is optional and can (should!) sleep. |
2766 | * | 2782 | * |
2783 | * @mgd_protect_tdls_discover: Protect a TDLS discovery session. After sending | ||
2784 | * a TDLS discovery-request, we expect a reply to arrive on the AP's | ||
2785 | * channel. We must stay on the channel (no PSM, scan, etc.), since a TDLS | ||
2786 | * setup-response is a direct packet not buffered by the AP. | ||
2787 | * mac80211 will call this function just before the transmission of a TDLS | ||
2788 | * discovery-request. The recommended period of protection is at least | ||
2789 | * 2 * (DTIM period). | ||
2790 | * The callback is optional and can sleep. | ||
2791 | * | ||
2767 | * @add_chanctx: Notifies device driver about new channel context creation. | 2792 | * @add_chanctx: Notifies device driver about new channel context creation. |
2768 | * @remove_chanctx: Notifies device driver about channel context destruction. | 2793 | * @remove_chanctx: Notifies device driver about channel context destruction. |
2769 | * @change_chanctx: Notifies device driver about channel context changes that | 2794 | * @change_chanctx: Notifies device driver about channel context changes that |
@@ -2865,13 +2890,13 @@ struct ieee80211_ops { | |||
2865 | void (*set_default_unicast_key)(struct ieee80211_hw *hw, | 2890 | void (*set_default_unicast_key)(struct ieee80211_hw *hw, |
2866 | struct ieee80211_vif *vif, int idx); | 2891 | struct ieee80211_vif *vif, int idx); |
2867 | int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 2892 | int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
2868 | struct cfg80211_scan_request *req); | 2893 | struct ieee80211_scan_request *req); |
2869 | void (*cancel_hw_scan)(struct ieee80211_hw *hw, | 2894 | void (*cancel_hw_scan)(struct ieee80211_hw *hw, |
2870 | struct ieee80211_vif *vif); | 2895 | struct ieee80211_vif *vif); |
2871 | int (*sched_scan_start)(struct ieee80211_hw *hw, | 2896 | int (*sched_scan_start)(struct ieee80211_hw *hw, |
2872 | struct ieee80211_vif *vif, | 2897 | struct ieee80211_vif *vif, |
2873 | struct cfg80211_sched_scan_request *req, | 2898 | struct cfg80211_sched_scan_request *req, |
2874 | struct ieee80211_sched_scan_ies *ies); | 2899 | struct ieee80211_scan_ies *ies); |
2875 | int (*sched_scan_stop)(struct ieee80211_hw *hw, | 2900 | int (*sched_scan_stop)(struct ieee80211_hw *hw, |
2876 | struct ieee80211_vif *vif); | 2901 | struct ieee80211_vif *vif); |
2877 | void (*sw_scan_start)(struct ieee80211_hw *hw); | 2902 | void (*sw_scan_start)(struct ieee80211_hw *hw); |
@@ -2981,6 +3006,9 @@ struct ieee80211_ops { | |||
2981 | void (*mgd_prepare_tx)(struct ieee80211_hw *hw, | 3006 | void (*mgd_prepare_tx)(struct ieee80211_hw *hw, |
2982 | struct ieee80211_vif *vif); | 3007 | struct ieee80211_vif *vif); |
2983 | 3008 | ||
3009 | void (*mgd_protect_tdls_discover)(struct ieee80211_hw *hw, | ||
3010 | struct ieee80211_vif *vif); | ||
3011 | |||
2984 | int (*add_chanctx)(struct ieee80211_hw *hw, | 3012 | int (*add_chanctx)(struct ieee80211_hw *hw, |
2985 | struct ieee80211_chanctx_conf *ctx); | 3013 | struct ieee80211_chanctx_conf *ctx); |
2986 | void (*remove_chanctx)(struct ieee80211_hw *hw, | 3014 | void (*remove_chanctx)(struct ieee80211_hw *hw, |
@@ -4815,4 +4843,17 @@ int ieee80211_parse_p2p_noa(const struct ieee80211_p2p_noa_attr *attr, | |||
4815 | */ | 4843 | */ |
4816 | void ieee80211_update_p2p_noa(struct ieee80211_noa_data *data, u32 tsf); | 4844 | void ieee80211_update_p2p_noa(struct ieee80211_noa_data *data, u32 tsf); |
4817 | 4845 | ||
4846 | /** | ||
4847 | * ieee80211_tdls_oper - request userspace to perform a TDLS operation | ||
4848 | * @vif: virtual interface | ||
4849 | * @peer: the peer's destination address | ||
4850 | * @oper: the requested TDLS operation | ||
4851 | * @reason_code: reason code for the operation, valid for TDLS teardown | ||
4852 | * @gfp: allocation flags | ||
4853 | * | ||
4854 | * See cfg80211_tdls_oper_request(). | ||
4855 | */ | ||
4856 | void ieee80211_tdls_oper_request(struct ieee80211_vif *vif, const u8 *peer, | ||
4857 | enum nl80211_tdls_operation oper, | ||
4858 | u16 reason_code, gfp_t gfp); | ||
4818 | #endif /* MAC80211_H */ | 4859 | #endif /* MAC80211_H */ |
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index be9519b52bb1..f1db15b9c041 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h | |||
@@ -1591,6 +1591,9 @@ enum nl80211_commands { | |||
1591 | * creation then the new interface will be owned by the netlink socket | 1591 | * creation then the new interface will be owned by the netlink socket |
1592 | * that created it and will be destroyed when the socket is closed | 1592 | * that created it and will be destroyed when the socket is closed |
1593 | * | 1593 | * |
1594 | * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is | ||
1595 | * the TDLS link initiator. | ||
1596 | * | ||
1594 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 1597 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
1595 | * @__NL80211_ATTR_AFTER_LAST: internal use | 1598 | * @__NL80211_ATTR_AFTER_LAST: internal use |
1596 | */ | 1599 | */ |
@@ -1931,6 +1934,8 @@ enum nl80211_attrs { | |||
1931 | NL80211_ATTR_CSA_C_OFFSETS_TX, | 1934 | NL80211_ATTR_CSA_C_OFFSETS_TX, |
1932 | NL80211_ATTR_MAX_CSA_COUNTERS, | 1935 | NL80211_ATTR_MAX_CSA_COUNTERS, |
1933 | 1936 | ||
1937 | NL80211_ATTR_TDLS_INITIATOR, | ||
1938 | |||
1934 | /* add attributes here, update the policy in nl80211.c */ | 1939 | /* add attributes here, update the policy in nl80211.c */ |
1935 | 1940 | ||
1936 | __NL80211_ATTR_AFTER_LAST, | 1941 | __NL80211_ATTR_AFTER_LAST, |
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 97b5dcad5025..aeb6a483b3bc 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -19,14 +19,6 @@ if MAC80211 != n | |||
19 | config MAC80211_HAS_RC | 19 | config MAC80211_HAS_RC |
20 | bool | 20 | bool |
21 | 21 | ||
22 | config MAC80211_RC_PID | ||
23 | bool "PID controller based rate control algorithm" if EXPERT | ||
24 | select MAC80211_HAS_RC | ||
25 | ---help--- | ||
26 | This option enables a TX rate control algorithm for | ||
27 | mac80211 that uses a PID controller to select the TX | ||
28 | rate. | ||
29 | |||
30 | config MAC80211_RC_MINSTREL | 22 | config MAC80211_RC_MINSTREL |
31 | bool "Minstrel" if EXPERT | 23 | bool "Minstrel" if EXPERT |
32 | select MAC80211_HAS_RC | 24 | select MAC80211_HAS_RC |
@@ -51,14 +43,6 @@ choice | |||
51 | overridden through the ieee80211_default_rc_algo module | 43 | overridden through the ieee80211_default_rc_algo module |
52 | parameter if different algorithms are available. | 44 | parameter if different algorithms are available. |
53 | 45 | ||
54 | config MAC80211_RC_DEFAULT_PID | ||
55 | bool "PID controller based rate control algorithm" | ||
56 | depends on MAC80211_RC_PID | ||
57 | ---help--- | ||
58 | Select the PID controller based rate control as the | ||
59 | default rate control algorithm. You should choose | ||
60 | this unless you know what you are doing. | ||
61 | |||
62 | config MAC80211_RC_DEFAULT_MINSTREL | 46 | config MAC80211_RC_DEFAULT_MINSTREL |
63 | bool "Minstrel" | 47 | bool "Minstrel" |
64 | depends on MAC80211_RC_MINSTREL | 48 | depends on MAC80211_RC_MINSTREL |
@@ -72,7 +56,6 @@ config MAC80211_RC_DEFAULT | |||
72 | string | 56 | string |
73 | default "minstrel_ht" if MAC80211_RC_DEFAULT_MINSTREL && MAC80211_RC_MINSTREL_HT | 57 | default "minstrel_ht" if MAC80211_RC_DEFAULT_MINSTREL && MAC80211_RC_MINSTREL_HT |
74 | default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL | 58 | default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL |
75 | default "pid" if MAC80211_RC_DEFAULT_PID | ||
76 | default "" | 59 | default "" |
77 | 60 | ||
78 | endif | 61 | endif |
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 1e46ffa69167..7273d2796dd1 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile | |||
@@ -17,6 +17,7 @@ mac80211-y := \ | |||
17 | aes_ccm.o \ | 17 | aes_ccm.o \ |
18 | aes_cmac.o \ | 18 | aes_cmac.o \ |
19 | cfg.o \ | 19 | cfg.o \ |
20 | ethtool.o \ | ||
20 | rx.o \ | 21 | rx.o \ |
21 | spectmgmt.o \ | 22 | spectmgmt.o \ |
22 | tx.o \ | 23 | tx.o \ |
@@ -47,17 +48,12 @@ mac80211-$(CONFIG_PM) += pm.o | |||
47 | 48 | ||
48 | CFLAGS_trace.o := -I$(src) | 49 | CFLAGS_trace.o := -I$(src) |
49 | 50 | ||
50 | # objects for PID algorithm | ||
51 | rc80211_pid-y := rc80211_pid_algo.o | ||
52 | rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o | ||
53 | |||
54 | rc80211_minstrel-y := rc80211_minstrel.o | 51 | rc80211_minstrel-y := rc80211_minstrel.o |
55 | rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_debugfs.o | 52 | rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_debugfs.o |
56 | 53 | ||
57 | rc80211_minstrel_ht-y := rc80211_minstrel_ht.o | 54 | rc80211_minstrel_ht-y := rc80211_minstrel_ht.o |
58 | rc80211_minstrel_ht-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_ht_debugfs.o | 55 | rc80211_minstrel_ht-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_ht_debugfs.o |
59 | 56 | ||
60 | mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc80211_pid-y) | ||
61 | mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y) | 57 | mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y) |
62 | mac80211-$(CONFIG_MAC80211_RC_MINSTREL_HT) += $(rc80211_minstrel_ht-y) | 58 | mac80211-$(CONFIG_MAC80211_RC_MINSTREL_HT) += $(rc80211_minstrel_ht-y) |
63 | 59 | ||
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index ce9633a3cfb0..d6986f3aa5c4 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -170,10 +170,13 @@ ieee80211_stop_queue_agg(struct ieee80211_sub_if_data *sdata, int tid) | |||
170 | { | 170 | { |
171 | int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)]; | 171 | int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)]; |
172 | 172 | ||
173 | /* we do refcounting here, so don't use the queue reason refcounting */ | ||
174 | |||
173 | if (atomic_inc_return(&sdata->local->agg_queue_stop[queue]) == 1) | 175 | if (atomic_inc_return(&sdata->local->agg_queue_stop[queue]) == 1) |
174 | ieee80211_stop_queue_by_reason( | 176 | ieee80211_stop_queue_by_reason( |
175 | &sdata->local->hw, queue, | 177 | &sdata->local->hw, queue, |
176 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | 178 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION, |
179 | false); | ||
177 | __acquire(agg_queue); | 180 | __acquire(agg_queue); |
178 | } | 181 | } |
179 | 182 | ||
@@ -185,7 +188,8 @@ ieee80211_wake_queue_agg(struct ieee80211_sub_if_data *sdata, int tid) | |||
185 | if (atomic_dec_return(&sdata->local->agg_queue_stop[queue]) == 0) | 188 | if (atomic_dec_return(&sdata->local->agg_queue_stop[queue]) == 0) |
186 | ieee80211_wake_queue_by_reason( | 189 | ieee80211_wake_queue_by_reason( |
187 | &sdata->local->hw, queue, | 190 | &sdata->local->hw, queue, |
188 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | 191 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION, |
192 | false); | ||
189 | __release(agg_queue); | 193 | __release(agg_queue); |
190 | } | 194 | } |
191 | 195 | ||
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d7513a503be1..927b4ea0128b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -468,327 +468,6 @@ void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo) | |||
468 | rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; | 468 | rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; |
469 | } | 469 | } |
470 | 470 | ||
471 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | ||
472 | { | ||
473 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
474 | struct ieee80211_local *local = sdata->local; | ||
475 | struct rate_control_ref *ref = local->rate_ctrl; | ||
476 | struct timespec uptime; | ||
477 | u64 packets = 0; | ||
478 | u32 thr = 0; | ||
479 | int i, ac; | ||
480 | |||
481 | sinfo->generation = sdata->local->sta_generation; | ||
482 | |||
483 | sinfo->filled = STATION_INFO_INACTIVE_TIME | | ||
484 | STATION_INFO_RX_BYTES64 | | ||
485 | STATION_INFO_TX_BYTES64 | | ||
486 | STATION_INFO_RX_PACKETS | | ||
487 | STATION_INFO_TX_PACKETS | | ||
488 | STATION_INFO_TX_RETRIES | | ||
489 | STATION_INFO_TX_FAILED | | ||
490 | STATION_INFO_TX_BITRATE | | ||
491 | STATION_INFO_RX_BITRATE | | ||
492 | STATION_INFO_RX_DROP_MISC | | ||
493 | STATION_INFO_BSS_PARAM | | ||
494 | STATION_INFO_CONNECTED_TIME | | ||
495 | STATION_INFO_STA_FLAGS | | ||
496 | STATION_INFO_BEACON_LOSS_COUNT; | ||
497 | |||
498 | do_posix_clock_monotonic_gettime(&uptime); | ||
499 | sinfo->connected_time = uptime.tv_sec - sta->last_connected; | ||
500 | |||
501 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | ||
502 | sinfo->tx_bytes = 0; | ||
503 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
504 | sinfo->tx_bytes += sta->tx_bytes[ac]; | ||
505 | packets += sta->tx_packets[ac]; | ||
506 | } | ||
507 | sinfo->tx_packets = packets; | ||
508 | sinfo->rx_bytes = sta->rx_bytes; | ||
509 | sinfo->rx_packets = sta->rx_packets; | ||
510 | sinfo->tx_retries = sta->tx_retry_count; | ||
511 | sinfo->tx_failed = sta->tx_retry_failed; | ||
512 | sinfo->rx_dropped_misc = sta->rx_dropped; | ||
513 | sinfo->beacon_loss_count = sta->beacon_loss_count; | ||
514 | |||
515 | if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || | ||
516 | (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { | ||
517 | sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; | ||
518 | if (!local->ops->get_rssi || | ||
519 | drv_get_rssi(local, sdata, &sta->sta, &sinfo->signal)) | ||
520 | sinfo->signal = (s8)sta->last_signal; | ||
521 | sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); | ||
522 | } | ||
523 | if (sta->chains) { | ||
524 | sinfo->filled |= STATION_INFO_CHAIN_SIGNAL | | ||
525 | STATION_INFO_CHAIN_SIGNAL_AVG; | ||
526 | |||
527 | sinfo->chains = sta->chains; | ||
528 | for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) { | ||
529 | sinfo->chain_signal[i] = sta->chain_signal_last[i]; | ||
530 | sinfo->chain_signal_avg[i] = | ||
531 | (s8) -ewma_read(&sta->chain_signal_avg[i]); | ||
532 | } | ||
533 | } | ||
534 | |||
535 | sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); | ||
536 | sta_set_rate_info_rx(sta, &sinfo->rxrate); | ||
537 | |||
538 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
539 | #ifdef CONFIG_MAC80211_MESH | ||
540 | sinfo->filled |= STATION_INFO_LLID | | ||
541 | STATION_INFO_PLID | | ||
542 | STATION_INFO_PLINK_STATE | | ||
543 | STATION_INFO_LOCAL_PM | | ||
544 | STATION_INFO_PEER_PM | | ||
545 | STATION_INFO_NONPEER_PM; | ||
546 | |||
547 | sinfo->llid = sta->llid; | ||
548 | sinfo->plid = sta->plid; | ||
549 | sinfo->plink_state = sta->plink_state; | ||
550 | if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { | ||
551 | sinfo->filled |= STATION_INFO_T_OFFSET; | ||
552 | sinfo->t_offset = sta->t_offset; | ||
553 | } | ||
554 | sinfo->local_pm = sta->local_pm; | ||
555 | sinfo->peer_pm = sta->peer_pm; | ||
556 | sinfo->nonpeer_pm = sta->nonpeer_pm; | ||
557 | #endif | ||
558 | } | ||
559 | |||
560 | sinfo->bss_param.flags = 0; | ||
561 | if (sdata->vif.bss_conf.use_cts_prot) | ||
562 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT; | ||
563 | if (sdata->vif.bss_conf.use_short_preamble) | ||
564 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE; | ||
565 | if (sdata->vif.bss_conf.use_short_slot) | ||
566 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME; | ||
567 | sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period; | ||
568 | sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int; | ||
569 | |||
570 | sinfo->sta_flags.set = 0; | ||
571 | sinfo->sta_flags.mask = BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
572 | BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | | ||
573 | BIT(NL80211_STA_FLAG_WME) | | ||
574 | BIT(NL80211_STA_FLAG_MFP) | | ||
575 | BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
576 | BIT(NL80211_STA_FLAG_ASSOCIATED) | | ||
577 | BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
578 | if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) | ||
579 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED); | ||
580 | if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE)) | ||
581 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); | ||
582 | if (test_sta_flag(sta, WLAN_STA_WME)) | ||
583 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_WME); | ||
584 | if (test_sta_flag(sta, WLAN_STA_MFP)) | ||
585 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP); | ||
586 | if (test_sta_flag(sta, WLAN_STA_AUTH)) | ||
587 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED); | ||
588 | if (test_sta_flag(sta, WLAN_STA_ASSOC)) | ||
589 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED); | ||
590 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | ||
591 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
592 | |||
593 | /* check if the driver has a SW RC implementation */ | ||
594 | if (ref && ref->ops->get_expected_throughput) | ||
595 | thr = ref->ops->get_expected_throughput(sta->rate_ctrl_priv); | ||
596 | else | ||
597 | thr = drv_get_expected_throughput(local, &sta->sta); | ||
598 | |||
599 | if (thr != 0) { | ||
600 | sinfo->filled |= STATION_INFO_EXPECTED_THROUGHPUT; | ||
601 | sinfo->expected_throughput = thr; | ||
602 | } | ||
603 | } | ||
604 | |||
605 | static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = { | ||
606 | "rx_packets", "rx_bytes", "wep_weak_iv_count", | ||
607 | "rx_duplicates", "rx_fragments", "rx_dropped", | ||
608 | "tx_packets", "tx_bytes", "tx_fragments", | ||
609 | "tx_filtered", "tx_retry_failed", "tx_retries", | ||
610 | "beacon_loss", "sta_state", "txrate", "rxrate", "signal", | ||
611 | "channel", "noise", "ch_time", "ch_time_busy", | ||
612 | "ch_time_ext_busy", "ch_time_rx", "ch_time_tx" | ||
613 | }; | ||
614 | #define STA_STATS_LEN ARRAY_SIZE(ieee80211_gstrings_sta_stats) | ||
615 | |||
616 | static int ieee80211_get_et_sset_count(struct wiphy *wiphy, | ||
617 | struct net_device *dev, | ||
618 | int sset) | ||
619 | { | ||
620 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
621 | int rv = 0; | ||
622 | |||
623 | if (sset == ETH_SS_STATS) | ||
624 | rv += STA_STATS_LEN; | ||
625 | |||
626 | rv += drv_get_et_sset_count(sdata, sset); | ||
627 | |||
628 | if (rv == 0) | ||
629 | return -EOPNOTSUPP; | ||
630 | return rv; | ||
631 | } | ||
632 | |||
633 | static void ieee80211_get_et_stats(struct wiphy *wiphy, | ||
634 | struct net_device *dev, | ||
635 | struct ethtool_stats *stats, | ||
636 | u64 *data) | ||
637 | { | ||
638 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
639 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
640 | struct ieee80211_channel *channel; | ||
641 | struct sta_info *sta; | ||
642 | struct ieee80211_local *local = sdata->local; | ||
643 | struct station_info sinfo; | ||
644 | struct survey_info survey; | ||
645 | int i, q; | ||
646 | #define STA_STATS_SURVEY_LEN 7 | ||
647 | |||
648 | memset(data, 0, sizeof(u64) * STA_STATS_LEN); | ||
649 | |||
650 | #define ADD_STA_STATS(sta) \ | ||
651 | do { \ | ||
652 | data[i++] += sta->rx_packets; \ | ||
653 | data[i++] += sta->rx_bytes; \ | ||
654 | data[i++] += sta->wep_weak_iv_count; \ | ||
655 | data[i++] += sta->num_duplicates; \ | ||
656 | data[i++] += sta->rx_fragments; \ | ||
657 | data[i++] += sta->rx_dropped; \ | ||
658 | \ | ||
659 | data[i++] += sinfo.tx_packets; \ | ||
660 | data[i++] += sinfo.tx_bytes; \ | ||
661 | data[i++] += sta->tx_fragments; \ | ||
662 | data[i++] += sta->tx_filtered_count; \ | ||
663 | data[i++] += sta->tx_retry_failed; \ | ||
664 | data[i++] += sta->tx_retry_count; \ | ||
665 | data[i++] += sta->beacon_loss_count; \ | ||
666 | } while (0) | ||
667 | |||
668 | /* For Managed stations, find the single station based on BSSID | ||
669 | * and use that. For interface types, iterate through all available | ||
670 | * stations and add stats for any station that is assigned to this | ||
671 | * network device. | ||
672 | */ | ||
673 | |||
674 | mutex_lock(&local->sta_mtx); | ||
675 | |||
676 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
677 | sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid); | ||
678 | |||
679 | if (!(sta && !WARN_ON(sta->sdata->dev != dev))) | ||
680 | goto do_survey; | ||
681 | |||
682 | sinfo.filled = 0; | ||
683 | sta_set_sinfo(sta, &sinfo); | ||
684 | |||
685 | i = 0; | ||
686 | ADD_STA_STATS(sta); | ||
687 | |||
688 | data[i++] = sta->sta_state; | ||
689 | |||
690 | |||
691 | if (sinfo.filled & STATION_INFO_TX_BITRATE) | ||
692 | data[i] = 100000 * | ||
693 | cfg80211_calculate_bitrate(&sinfo.txrate); | ||
694 | i++; | ||
695 | if (sinfo.filled & STATION_INFO_RX_BITRATE) | ||
696 | data[i] = 100000 * | ||
697 | cfg80211_calculate_bitrate(&sinfo.rxrate); | ||
698 | i++; | ||
699 | |||
700 | if (sinfo.filled & STATION_INFO_SIGNAL_AVG) | ||
701 | data[i] = (u8)sinfo.signal_avg; | ||
702 | i++; | ||
703 | } else { | ||
704 | list_for_each_entry(sta, &local->sta_list, list) { | ||
705 | /* Make sure this station belongs to the proper dev */ | ||
706 | if (sta->sdata->dev != dev) | ||
707 | continue; | ||
708 | |||
709 | sinfo.filled = 0; | ||
710 | sta_set_sinfo(sta, &sinfo); | ||
711 | i = 0; | ||
712 | ADD_STA_STATS(sta); | ||
713 | } | ||
714 | } | ||
715 | |||
716 | do_survey: | ||
717 | i = STA_STATS_LEN - STA_STATS_SURVEY_LEN; | ||
718 | /* Get survey stats for current channel */ | ||
719 | survey.filled = 0; | ||
720 | |||
721 | rcu_read_lock(); | ||
722 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
723 | if (chanctx_conf) | ||
724 | channel = chanctx_conf->def.chan; | ||
725 | else | ||
726 | channel = NULL; | ||
727 | rcu_read_unlock(); | ||
728 | |||
729 | if (channel) { | ||
730 | q = 0; | ||
731 | do { | ||
732 | survey.filled = 0; | ||
733 | if (drv_get_survey(local, q, &survey) != 0) { | ||
734 | survey.filled = 0; | ||
735 | break; | ||
736 | } | ||
737 | q++; | ||
738 | } while (channel != survey.channel); | ||
739 | } | ||
740 | |||
741 | if (survey.filled) | ||
742 | data[i++] = survey.channel->center_freq; | ||
743 | else | ||
744 | data[i++] = 0; | ||
745 | if (survey.filled & SURVEY_INFO_NOISE_DBM) | ||
746 | data[i++] = (u8)survey.noise; | ||
747 | else | ||
748 | data[i++] = -1LL; | ||
749 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME) | ||
750 | data[i++] = survey.channel_time; | ||
751 | else | ||
752 | data[i++] = -1LL; | ||
753 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_BUSY) | ||
754 | data[i++] = survey.channel_time_busy; | ||
755 | else | ||
756 | data[i++] = -1LL; | ||
757 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) | ||
758 | data[i++] = survey.channel_time_ext_busy; | ||
759 | else | ||
760 | data[i++] = -1LL; | ||
761 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_RX) | ||
762 | data[i++] = survey.channel_time_rx; | ||
763 | else | ||
764 | data[i++] = -1LL; | ||
765 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_TX) | ||
766 | data[i++] = survey.channel_time_tx; | ||
767 | else | ||
768 | data[i++] = -1LL; | ||
769 | |||
770 | mutex_unlock(&local->sta_mtx); | ||
771 | |||
772 | if (WARN_ON(i != STA_STATS_LEN)) | ||
773 | return; | ||
774 | |||
775 | drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN])); | ||
776 | } | ||
777 | |||
778 | static void ieee80211_get_et_strings(struct wiphy *wiphy, | ||
779 | struct net_device *dev, | ||
780 | u32 sset, u8 *data) | ||
781 | { | ||
782 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
783 | int sz_sta_stats = 0; | ||
784 | |||
785 | if (sset == ETH_SS_STATS) { | ||
786 | sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats); | ||
787 | memcpy(data, ieee80211_gstrings_sta_stats, sz_sta_stats); | ||
788 | } | ||
789 | drv_get_et_strings(sdata, sset, &(data[sz_sta_stats])); | ||
790 | } | ||
791 | |||
792 | static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, | 471 | static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, |
793 | int idx, u8 *mac, struct station_info *sinfo) | 472 | int idx, u8 *mac, struct station_info *sinfo) |
794 | { | 473 | { |
@@ -875,7 +554,8 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, | |||
875 | } | 554 | } |
876 | 555 | ||
877 | static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | 556 | static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, |
878 | const u8 *resp, size_t resp_len) | 557 | const u8 *resp, size_t resp_len, |
558 | const struct ieee80211_csa_settings *csa) | ||
879 | { | 559 | { |
880 | struct probe_resp *new, *old; | 560 | struct probe_resp *new, *old; |
881 | 561 | ||
@@ -891,6 +571,11 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
891 | new->len = resp_len; | 571 | new->len = resp_len; |
892 | memcpy(new->data, resp, resp_len); | 572 | memcpy(new->data, resp, resp_len); |
893 | 573 | ||
574 | if (csa) | ||
575 | memcpy(new->csa_counter_offsets, csa->counter_offsets_presp, | ||
576 | csa->n_counter_offsets_presp * | ||
577 | sizeof(new->csa_counter_offsets[0])); | ||
578 | |||
894 | rcu_assign_pointer(sdata->u.ap.probe_resp, new); | 579 | rcu_assign_pointer(sdata->u.ap.probe_resp, new); |
895 | if (old) | 580 | if (old) |
896 | kfree_rcu(old, rcu_head); | 581 | kfree_rcu(old, rcu_head); |
@@ -899,7 +584,8 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
899 | } | 584 | } |
900 | 585 | ||
901 | static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | 586 | static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, |
902 | struct cfg80211_beacon_data *params) | 587 | struct cfg80211_beacon_data *params, |
588 | const struct ieee80211_csa_settings *csa) | ||
903 | { | 589 | { |
904 | struct beacon_data *new, *old; | 590 | struct beacon_data *new, *old; |
905 | int new_head_len, new_tail_len; | 591 | int new_head_len, new_tail_len; |
@@ -943,6 +629,13 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | |||
943 | new->head_len = new_head_len; | 629 | new->head_len = new_head_len; |
944 | new->tail_len = new_tail_len; | 630 | new->tail_len = new_tail_len; |
945 | 631 | ||
632 | if (csa) { | ||
633 | new->csa_current_counter = csa->count; | ||
634 | memcpy(new->csa_counter_offsets, csa->counter_offsets_beacon, | ||
635 | csa->n_counter_offsets_beacon * | ||
636 | sizeof(new->csa_counter_offsets[0])); | ||
637 | } | ||
638 | |||
946 | /* copy in head */ | 639 | /* copy in head */ |
947 | if (params->head) | 640 | if (params->head) |
948 | memcpy(new->head, params->head, new_head_len); | 641 | memcpy(new->head, params->head, new_head_len); |
@@ -957,7 +650,7 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | |||
957 | memcpy(new->tail, old->tail, new_tail_len); | 650 | memcpy(new->tail, old->tail, new_tail_len); |
958 | 651 | ||
959 | err = ieee80211_set_probe_resp(sdata, params->probe_resp, | 652 | err = ieee80211_set_probe_resp(sdata, params->probe_resp, |
960 | params->probe_resp_len); | 653 | params->probe_resp_len, csa); |
961 | if (err < 0) | 654 | if (err < 0) |
962 | return err; | 655 | return err; |
963 | if (err == 0) | 656 | if (err == 0) |
@@ -1042,7 +735,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
1042 | sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |= | 735 | sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |= |
1043 | IEEE80211_P2P_OPPPS_ENABLE_BIT; | 736 | IEEE80211_P2P_OPPPS_ENABLE_BIT; |
1044 | 737 | ||
1045 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon); | 738 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon, NULL); |
1046 | if (err < 0) { | 739 | if (err < 0) { |
1047 | ieee80211_vif_release_channel(sdata); | 740 | ieee80211_vif_release_channel(sdata); |
1048 | return err; | 741 | return err; |
@@ -1090,38 +783,13 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
1090 | if (!old) | 783 | if (!old) |
1091 | return -ENOENT; | 784 | return -ENOENT; |
1092 | 785 | ||
1093 | err = ieee80211_assign_beacon(sdata, params); | 786 | err = ieee80211_assign_beacon(sdata, params, NULL); |
1094 | if (err < 0) | 787 | if (err < 0) |
1095 | return err; | 788 | return err; |
1096 | ieee80211_bss_info_change_notify(sdata, err); | 789 | ieee80211_bss_info_change_notify(sdata, err); |
1097 | return 0; | 790 | return 0; |
1098 | } | 791 | } |
1099 | 792 | ||
1100 | bool ieee80211_csa_needs_block_tx(struct ieee80211_local *local) | ||
1101 | { | ||
1102 | struct ieee80211_sub_if_data *sdata; | ||
1103 | |||
1104 | lockdep_assert_held(&local->mtx); | ||
1105 | |||
1106 | rcu_read_lock(); | ||
1107 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
1108 | if (!ieee80211_sdata_running(sdata)) | ||
1109 | continue; | ||
1110 | |||
1111 | if (!sdata->vif.csa_active) | ||
1112 | continue; | ||
1113 | |||
1114 | if (!sdata->csa_block_tx) | ||
1115 | continue; | ||
1116 | |||
1117 | rcu_read_unlock(); | ||
1118 | return true; | ||
1119 | } | ||
1120 | rcu_read_unlock(); | ||
1121 | |||
1122 | return false; | ||
1123 | } | ||
1124 | |||
1125 | static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | 793 | static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) |
1126 | { | 794 | { |
1127 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 795 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
@@ -1141,10 +809,12 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
1141 | /* abort any running channel switch */ | 809 | /* abort any running channel switch */ |
1142 | mutex_lock(&local->mtx); | 810 | mutex_lock(&local->mtx); |
1143 | sdata->vif.csa_active = false; | 811 | sdata->vif.csa_active = false; |
1144 | if (!ieee80211_csa_needs_block_tx(local)) | 812 | if (sdata->csa_block_tx) { |
1145 | ieee80211_wake_queues_by_reason(&local->hw, | 813 | ieee80211_wake_vif_queues(local, sdata, |
1146 | IEEE80211_MAX_QUEUE_MAP, | 814 | IEEE80211_QUEUE_STOP_REASON_CSA); |
1147 | IEEE80211_QUEUE_STOP_REASON_CSA); | 815 | sdata->csa_block_tx = false; |
816 | } | ||
817 | |||
1148 | mutex_unlock(&local->mtx); | 818 | mutex_unlock(&local->mtx); |
1149 | 819 | ||
1150 | kfree(sdata->u.ap.next_beacon); | 820 | kfree(sdata->u.ap.next_beacon); |
@@ -1327,9 +997,12 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1327 | } | 997 | } |
1328 | } | 998 | } |
1329 | 999 | ||
1330 | ret = sta_apply_auth_flags(local, sta, mask, set); | 1000 | /* auth flags will be set later for TDLS stations */ |
1331 | if (ret) | 1001 | if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { |
1332 | return ret; | 1002 | ret = sta_apply_auth_flags(local, sta, mask, set); |
1003 | if (ret) | ||
1004 | return ret; | ||
1005 | } | ||
1333 | 1006 | ||
1334 | if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) { | 1007 | if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) { |
1335 | if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) | 1008 | if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) |
@@ -1466,6 +1139,13 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1466 | #endif | 1139 | #endif |
1467 | } | 1140 | } |
1468 | 1141 | ||
1142 | /* set the STA state after all sta info from usermode has been set */ | ||
1143 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { | ||
1144 | ret = sta_apply_auth_flags(local, sta, mask, set); | ||
1145 | if (ret) | ||
1146 | return ret; | ||
1147 | } | ||
1148 | |||
1469 | return 0; | 1149 | return 0; |
1470 | } | 1150 | } |
1471 | 1151 | ||
@@ -3073,7 +2753,8 @@ static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata, | |||
3073 | 2753 | ||
3074 | switch (sdata->vif.type) { | 2754 | switch (sdata->vif.type) { |
3075 | case NL80211_IFTYPE_AP: | 2755 | case NL80211_IFTYPE_AP: |
3076 | err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); | 2756 | err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon, |
2757 | NULL); | ||
3077 | kfree(sdata->u.ap.next_beacon); | 2758 | kfree(sdata->u.ap.next_beacon); |
3078 | sdata->u.ap.next_beacon = NULL; | 2759 | sdata->u.ap.next_beacon = NULL; |
3079 | 2760 | ||
@@ -3111,17 +2792,35 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) | |||
3111 | 2792 | ||
3112 | sdata_assert_lock(sdata); | 2793 | sdata_assert_lock(sdata); |
3113 | lockdep_assert_held(&local->mtx); | 2794 | lockdep_assert_held(&local->mtx); |
2795 | lockdep_assert_held(&local->chanctx_mtx); | ||
3114 | 2796 | ||
3115 | sdata->radar_required = sdata->csa_radar_required; | 2797 | /* |
3116 | err = ieee80211_vif_change_channel(sdata, &changed); | 2798 | * using reservation isn't immediate as it may be deferred until later |
3117 | if (err < 0) | 2799 | * with multi-vif. once reservation is complete it will re-schedule the |
3118 | return err; | 2800 | * work with no reserved_chanctx so verify chandef to check if it |
2801 | * completed successfully | ||
2802 | */ | ||
3119 | 2803 | ||
3120 | if (!local->use_chanctx) { | 2804 | if (sdata->reserved_chanctx) { |
3121 | local->_oper_chandef = sdata->csa_chandef; | 2805 | /* |
3122 | ieee80211_hw_config(local, 0); | 2806 | * with multi-vif csa driver may call ieee80211_csa_finish() |
2807 | * many times while waiting for other interfaces to use their | ||
2808 | * reservations | ||
2809 | */ | ||
2810 | if (sdata->reserved_ready) | ||
2811 | return 0; | ||
2812 | |||
2813 | err = ieee80211_vif_use_reserved_context(sdata); | ||
2814 | if (err) | ||
2815 | return err; | ||
2816 | |||
2817 | return 0; | ||
3123 | } | 2818 | } |
3124 | 2819 | ||
2820 | if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef, | ||
2821 | &sdata->csa_chandef)) | ||
2822 | return -EINVAL; | ||
2823 | |||
3125 | sdata->vif.csa_active = false; | 2824 | sdata->vif.csa_active = false; |
3126 | 2825 | ||
3127 | err = ieee80211_set_after_csa_beacon(sdata, &changed); | 2826 | err = ieee80211_set_after_csa_beacon(sdata, &changed); |
@@ -3131,10 +2830,11 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) | |||
3131 | ieee80211_bss_info_change_notify(sdata, changed); | 2830 | ieee80211_bss_info_change_notify(sdata, changed); |
3132 | cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); | 2831 | cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); |
3133 | 2832 | ||
3134 | if (!ieee80211_csa_needs_block_tx(local)) | 2833 | if (sdata->csa_block_tx) { |
3135 | ieee80211_wake_queues_by_reason(&local->hw, | 2834 | ieee80211_wake_vif_queues(local, sdata, |
3136 | IEEE80211_MAX_QUEUE_MAP, | 2835 | IEEE80211_QUEUE_STOP_REASON_CSA); |
3137 | IEEE80211_QUEUE_STOP_REASON_CSA); | 2836 | sdata->csa_block_tx = false; |
2837 | } | ||
3138 | 2838 | ||
3139 | return 0; | 2839 | return 0; |
3140 | } | 2840 | } |
@@ -3157,6 +2857,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work) | |||
3157 | 2857 | ||
3158 | sdata_lock(sdata); | 2858 | sdata_lock(sdata); |
3159 | mutex_lock(&local->mtx); | 2859 | mutex_lock(&local->mtx); |
2860 | mutex_lock(&local->chanctx_mtx); | ||
3160 | 2861 | ||
3161 | /* AP might have been stopped while waiting for the lock. */ | 2862 | /* AP might have been stopped while waiting for the lock. */ |
3162 | if (!sdata->vif.csa_active) | 2863 | if (!sdata->vif.csa_active) |
@@ -3168,6 +2869,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work) | |||
3168 | ieee80211_csa_finalize(sdata); | 2869 | ieee80211_csa_finalize(sdata); |
3169 | 2870 | ||
3170 | unlock: | 2871 | unlock: |
2872 | mutex_unlock(&local->chanctx_mtx); | ||
3171 | mutex_unlock(&local->mtx); | 2873 | mutex_unlock(&local->mtx); |
3172 | sdata_unlock(sdata); | 2874 | sdata_unlock(sdata); |
3173 | } | 2875 | } |
@@ -3176,6 +2878,7 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, | |||
3176 | struct cfg80211_csa_settings *params, | 2878 | struct cfg80211_csa_settings *params, |
3177 | u32 *changed) | 2879 | u32 *changed) |
3178 | { | 2880 | { |
2881 | struct ieee80211_csa_settings csa = {}; | ||
3179 | int err; | 2882 | int err; |
3180 | 2883 | ||
3181 | switch (sdata->vif.type) { | 2884 | switch (sdata->vif.type) { |
@@ -3210,20 +2913,13 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, | |||
3210 | IEEE80211_MAX_CSA_COUNTERS_NUM)) | 2913 | IEEE80211_MAX_CSA_COUNTERS_NUM)) |
3211 | return -EINVAL; | 2914 | return -EINVAL; |
3212 | 2915 | ||
3213 | /* make sure we don't have garbage in other counters */ | 2916 | csa.counter_offsets_beacon = params->counter_offsets_beacon; |
3214 | memset(sdata->csa_counter_offset_beacon, 0, | 2917 | csa.counter_offsets_presp = params->counter_offsets_presp; |
3215 | sizeof(sdata->csa_counter_offset_beacon)); | 2918 | csa.n_counter_offsets_beacon = params->n_counter_offsets_beacon; |
3216 | memset(sdata->csa_counter_offset_presp, 0, | 2919 | csa.n_counter_offsets_presp = params->n_counter_offsets_presp; |
3217 | sizeof(sdata->csa_counter_offset_presp)); | 2920 | csa.count = params->count; |
3218 | |||
3219 | memcpy(sdata->csa_counter_offset_beacon, | ||
3220 | params->counter_offsets_beacon, | ||
3221 | params->n_counter_offsets_beacon * sizeof(u16)); | ||
3222 | memcpy(sdata->csa_counter_offset_presp, | ||
3223 | params->counter_offsets_presp, | ||
3224 | params->n_counter_offsets_presp * sizeof(u16)); | ||
3225 | 2921 | ||
3226 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa); | 2922 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa, &csa); |
3227 | if (err < 0) { | 2923 | if (err < 0) { |
3228 | kfree(sdata->u.ap.next_beacon); | 2924 | kfree(sdata->u.ap.next_beacon); |
3229 | return err; | 2925 | return err; |
@@ -3319,7 +3015,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3319 | struct ieee80211_local *local = sdata->local; | 3015 | struct ieee80211_local *local = sdata->local; |
3320 | struct ieee80211_chanctx_conf *conf; | 3016 | struct ieee80211_chanctx_conf *conf; |
3321 | struct ieee80211_chanctx *chanctx; | 3017 | struct ieee80211_chanctx *chanctx; |
3322 | int err, num_chanctx, changed = 0; | 3018 | int err, changed = 0; |
3323 | 3019 | ||
3324 | sdata_assert_lock(sdata); | 3020 | sdata_assert_lock(sdata); |
3325 | lockdep_assert_held(&local->mtx); | 3021 | lockdep_assert_held(&local->mtx); |
@@ -3334,46 +3030,50 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3334 | &sdata->vif.bss_conf.chandef)) | 3030 | &sdata->vif.bss_conf.chandef)) |
3335 | return -EINVAL; | 3031 | return -EINVAL; |
3336 | 3032 | ||
3033 | /* don't allow another channel switch if one is already active. */ | ||
3034 | if (sdata->vif.csa_active) | ||
3035 | return -EBUSY; | ||
3036 | |||
3337 | mutex_lock(&local->chanctx_mtx); | 3037 | mutex_lock(&local->chanctx_mtx); |
3338 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | 3038 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, |
3339 | lockdep_is_held(&local->chanctx_mtx)); | 3039 | lockdep_is_held(&local->chanctx_mtx)); |
3340 | if (!conf) { | 3040 | if (!conf) { |
3341 | mutex_unlock(&local->chanctx_mtx); | 3041 | err = -EBUSY; |
3342 | return -EBUSY; | 3042 | goto out; |
3343 | } | 3043 | } |
3344 | 3044 | ||
3345 | /* don't handle for multi-VIF cases */ | ||
3346 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); | 3045 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); |
3347 | if (ieee80211_chanctx_refcount(local, chanctx) > 1) { | 3046 | if (!chanctx) { |
3348 | mutex_unlock(&local->chanctx_mtx); | 3047 | err = -EBUSY; |
3349 | return -EBUSY; | 3048 | goto out; |
3350 | } | 3049 | } |
3351 | num_chanctx = 0; | ||
3352 | list_for_each_entry_rcu(chanctx, &local->chanctx_list, list) | ||
3353 | num_chanctx++; | ||
3354 | mutex_unlock(&local->chanctx_mtx); | ||
3355 | 3050 | ||
3356 | if (num_chanctx > 1) | 3051 | err = ieee80211_vif_reserve_chanctx(sdata, ¶ms->chandef, |
3357 | return -EBUSY; | 3052 | chanctx->mode, |
3053 | params->radar_required); | ||
3054 | if (err) | ||
3055 | goto out; | ||
3358 | 3056 | ||
3359 | /* don't allow another channel switch if one is already active. */ | 3057 | /* if reservation is invalid then this will fail */ |
3360 | if (sdata->vif.csa_active) | 3058 | err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0); |
3361 | return -EBUSY; | 3059 | if (err) { |
3060 | ieee80211_vif_unreserve_chanctx(sdata); | ||
3061 | goto out; | ||
3062 | } | ||
3362 | 3063 | ||
3363 | err = ieee80211_set_csa_beacon(sdata, params, &changed); | 3064 | err = ieee80211_set_csa_beacon(sdata, params, &changed); |
3364 | if (err) | 3065 | if (err) { |
3365 | return err; | 3066 | ieee80211_vif_unreserve_chanctx(sdata); |
3067 | goto out; | ||
3068 | } | ||
3366 | 3069 | ||
3367 | sdata->csa_radar_required = params->radar_required; | ||
3368 | sdata->csa_chandef = params->chandef; | 3070 | sdata->csa_chandef = params->chandef; |
3369 | sdata->csa_block_tx = params->block_tx; | 3071 | sdata->csa_block_tx = params->block_tx; |
3370 | sdata->csa_current_counter = params->count; | ||
3371 | sdata->vif.csa_active = true; | 3072 | sdata->vif.csa_active = true; |
3372 | 3073 | ||
3373 | if (sdata->csa_block_tx) | 3074 | if (sdata->csa_block_tx) |
3374 | ieee80211_stop_queues_by_reason(&local->hw, | 3075 | ieee80211_stop_vif_queues(local, sdata, |
3375 | IEEE80211_MAX_QUEUE_MAP, | 3076 | IEEE80211_QUEUE_STOP_REASON_CSA); |
3376 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
3377 | 3077 | ||
3378 | if (changed) { | 3078 | if (changed) { |
3379 | ieee80211_bss_info_change_notify(sdata, changed); | 3079 | ieee80211_bss_info_change_notify(sdata, changed); |
@@ -3383,7 +3083,9 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3383 | ieee80211_csa_finalize(sdata); | 3083 | ieee80211_csa_finalize(sdata); |
3384 | } | 3084 | } |
3385 | 3085 | ||
3386 | return 0; | 3086 | out: |
3087 | mutex_unlock(&local->chanctx_mtx); | ||
3088 | return err; | ||
3387 | } | 3089 | } |
3388 | 3090 | ||
3389 | int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | 3091 | int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, |
@@ -3515,10 +3217,23 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
3515 | sdata->vif.type == NL80211_IFTYPE_ADHOC) && | 3217 | sdata->vif.type == NL80211_IFTYPE_ADHOC) && |
3516 | params->n_csa_offsets) { | 3218 | params->n_csa_offsets) { |
3517 | int i; | 3219 | int i; |
3518 | u8 c = sdata->csa_current_counter; | 3220 | struct beacon_data *beacon = NULL; |
3519 | 3221 | ||
3520 | for (i = 0; i < params->n_csa_offsets; i++) | 3222 | rcu_read_lock(); |
3521 | data[params->csa_offsets[i]] = c; | 3223 | |
3224 | if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
3225 | beacon = rcu_dereference(sdata->u.ap.beacon); | ||
3226 | else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
3227 | beacon = rcu_dereference(sdata->u.ibss.presp); | ||
3228 | else if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
3229 | beacon = rcu_dereference(sdata->u.mesh.beacon); | ||
3230 | |||
3231 | if (beacon) | ||
3232 | for (i = 0; i < params->n_csa_offsets; i++) | ||
3233 | data[params->csa_offsets[i]] = | ||
3234 | beacon->csa_current_counter; | ||
3235 | |||
3236 | rcu_read_unlock(); | ||
3522 | } | 3237 | } |
3523 | 3238 | ||
3524 | IEEE80211_SKB_CB(skb)->flags = flags; | 3239 | IEEE80211_SKB_CB(skb)->flags = flags; |
@@ -3598,21 +3313,6 @@ static int ieee80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant) | |||
3598 | return drv_get_antenna(local, tx_ant, rx_ant); | 3313 | return drv_get_antenna(local, tx_ant, rx_ant); |
3599 | } | 3314 | } |
3600 | 3315 | ||
3601 | static int ieee80211_set_ringparam(struct wiphy *wiphy, u32 tx, u32 rx) | ||
3602 | { | ||
3603 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
3604 | |||
3605 | return drv_set_ringparam(local, tx, rx); | ||
3606 | } | ||
3607 | |||
3608 | static void ieee80211_get_ringparam(struct wiphy *wiphy, | ||
3609 | u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max) | ||
3610 | { | ||
3611 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
3612 | |||
3613 | drv_get_ringparam(local, tx, tx_max, rx, rx_max); | ||
3614 | } | ||
3615 | |||
3616 | static int ieee80211_set_rekey_data(struct wiphy *wiphy, | 3316 | static int ieee80211_set_rekey_data(struct wiphy *wiphy, |
3617 | struct net_device *dev, | 3317 | struct net_device *dev, |
3618 | struct cfg80211_gtk_rekey_data *data) | 3318 | struct cfg80211_gtk_rekey_data *data) |
@@ -3844,8 +3544,6 @@ const struct cfg80211_ops mac80211_config_ops = { | |||
3844 | .mgmt_frame_register = ieee80211_mgmt_frame_register, | 3544 | .mgmt_frame_register = ieee80211_mgmt_frame_register, |
3845 | .set_antenna = ieee80211_set_antenna, | 3545 | .set_antenna = ieee80211_set_antenna, |
3846 | .get_antenna = ieee80211_get_antenna, | 3546 | .get_antenna = ieee80211_get_antenna, |
3847 | .set_ringparam = ieee80211_set_ringparam, | ||
3848 | .get_ringparam = ieee80211_get_ringparam, | ||
3849 | .set_rekey_data = ieee80211_set_rekey_data, | 3547 | .set_rekey_data = ieee80211_set_rekey_data, |
3850 | .tdls_oper = ieee80211_tdls_oper, | 3548 | .tdls_oper = ieee80211_tdls_oper, |
3851 | .tdls_mgmt = ieee80211_tdls_mgmt, | 3549 | .tdls_mgmt = ieee80211_tdls_mgmt, |
@@ -3854,9 +3552,6 @@ const struct cfg80211_ops mac80211_config_ops = { | |||
3854 | #ifdef CONFIG_PM | 3552 | #ifdef CONFIG_PM |
3855 | .set_wakeup = ieee80211_set_wakeup, | 3553 | .set_wakeup = ieee80211_set_wakeup, |
3856 | #endif | 3554 | #endif |
3857 | .get_et_sset_count = ieee80211_get_et_sset_count, | ||
3858 | .get_et_stats = ieee80211_get_et_stats, | ||
3859 | .get_et_strings = ieee80211_get_et_strings, | ||
3860 | .get_channel = ieee80211_cfg_get_channel, | 3555 | .get_channel = ieee80211_cfg_get_channel, |
3861 | .start_radar_detection = ieee80211_start_radar_detection, | 3556 | .start_radar_detection = ieee80211_start_radar_detection, |
3862 | .channel_switch = ieee80211_channel_switch, | 3557 | .channel_switch = ieee80211_channel_switch, |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index a310e33972de..c3fd4d275bf4 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -63,6 +63,20 @@ static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local) | |||
63 | return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local); | 63 | return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local); |
64 | } | 64 | } |
65 | 65 | ||
66 | static struct ieee80211_chanctx * | ||
67 | ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata) | ||
68 | { | ||
69 | struct ieee80211_local *local = sdata->local; | ||
70 | struct ieee80211_chanctx_conf *conf; | ||
71 | |||
72 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
73 | lockdep_is_held(&local->chanctx_mtx)); | ||
74 | if (!conf) | ||
75 | return NULL; | ||
76 | |||
77 | return container_of(conf, struct ieee80211_chanctx, conf); | ||
78 | } | ||
79 | |||
66 | static const struct cfg80211_chan_def * | 80 | static const struct cfg80211_chan_def * |
67 | ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local, | 81 | ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local, |
68 | struct ieee80211_chanctx *ctx, | 82 | struct ieee80211_chanctx *ctx, |
@@ -160,6 +174,9 @@ ieee80211_find_reservation_chanctx(struct ieee80211_local *local, | |||
160 | return NULL; | 174 | return NULL; |
161 | 175 | ||
162 | list_for_each_entry(ctx, &local->chanctx_list, list) { | 176 | list_for_each_entry(ctx, &local->chanctx_list, list) { |
177 | if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) | ||
178 | continue; | ||
179 | |||
163 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) | 180 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) |
164 | continue; | 181 | continue; |
165 | 182 | ||
@@ -347,6 +364,9 @@ ieee80211_find_chanctx(struct ieee80211_local *local, | |||
347 | list_for_each_entry(ctx, &local->chanctx_list, list) { | 364 | list_for_each_entry(ctx, &local->chanctx_list, list) { |
348 | const struct cfg80211_chan_def *compat; | 365 | const struct cfg80211_chan_def *compat; |
349 | 366 | ||
367 | if (ctx->replace_state != IEEE80211_CHANCTX_REPLACE_NONE) | ||
368 | continue; | ||
369 | |||
350 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) | 370 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) |
351 | continue; | 371 | continue; |
352 | 372 | ||
@@ -622,6 +642,7 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) | |||
622 | struct ieee80211_local *local = sdata->local; | 642 | struct ieee80211_local *local = sdata->local; |
623 | struct ieee80211_chanctx_conf *conf; | 643 | struct ieee80211_chanctx_conf *conf; |
624 | struct ieee80211_chanctx *ctx; | 644 | struct ieee80211_chanctx *ctx; |
645 | bool use_reserved_switch = false; | ||
625 | 646 | ||
626 | lockdep_assert_held(&local->chanctx_mtx); | 647 | lockdep_assert_held(&local->chanctx_mtx); |
627 | 648 | ||
@@ -632,12 +653,23 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) | |||
632 | 653 | ||
633 | ctx = container_of(conf, struct ieee80211_chanctx, conf); | 654 | ctx = container_of(conf, struct ieee80211_chanctx, conf); |
634 | 655 | ||
635 | if (sdata->reserved_chanctx) | 656 | if (sdata->reserved_chanctx) { |
657 | if (sdata->reserved_chanctx->replace_state == | ||
658 | IEEE80211_CHANCTX_REPLACES_OTHER && | ||
659 | ieee80211_chanctx_num_reserved(local, | ||
660 | sdata->reserved_chanctx) > 1) | ||
661 | use_reserved_switch = true; | ||
662 | |||
636 | ieee80211_vif_unreserve_chanctx(sdata); | 663 | ieee80211_vif_unreserve_chanctx(sdata); |
664 | } | ||
637 | 665 | ||
638 | ieee80211_assign_vif_chanctx(sdata, NULL); | 666 | ieee80211_assign_vif_chanctx(sdata, NULL); |
639 | if (ieee80211_chanctx_refcount(local, ctx) == 0) | 667 | if (ieee80211_chanctx_refcount(local, ctx) == 0) |
640 | ieee80211_free_chanctx(local, ctx); | 668 | ieee80211_free_chanctx(local, ctx); |
669 | |||
670 | /* Unreserving may ready an in-place reservation. */ | ||
671 | if (use_reserved_switch) | ||
672 | ieee80211_vif_use_reserved_switch(local); | ||
641 | } | 673 | } |
642 | 674 | ||
643 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | 675 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, |
@@ -787,70 +819,6 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
787 | return ret; | 819 | return ret; |
788 | } | 820 | } |
789 | 821 | ||
790 | static int __ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, | ||
791 | struct ieee80211_chanctx *ctx, | ||
792 | u32 *changed) | ||
793 | { | ||
794 | struct ieee80211_local *local = sdata->local; | ||
795 | const struct cfg80211_chan_def *chandef = &sdata->csa_chandef; | ||
796 | u32 chanctx_changed = 0; | ||
797 | |||
798 | if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, | ||
799 | IEEE80211_CHAN_DISABLED)) | ||
800 | return -EINVAL; | ||
801 | |||
802 | if (ieee80211_chanctx_refcount(local, ctx) != 1) | ||
803 | return -EINVAL; | ||
804 | |||
805 | if (sdata->vif.bss_conf.chandef.width != chandef->width) { | ||
806 | chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH; | ||
807 | *changed |= BSS_CHANGED_BANDWIDTH; | ||
808 | } | ||
809 | |||
810 | sdata->vif.bss_conf.chandef = *chandef; | ||
811 | ctx->conf.def = *chandef; | ||
812 | |||
813 | chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL; | ||
814 | drv_change_chanctx(local, ctx, chanctx_changed); | ||
815 | |||
816 | ieee80211_recalc_chanctx_chantype(local, ctx); | ||
817 | ieee80211_recalc_smps_chanctx(local, ctx); | ||
818 | ieee80211_recalc_radar_chanctx(local, ctx); | ||
819 | ieee80211_recalc_chanctx_min_def(local, ctx); | ||
820 | |||
821 | return 0; | ||
822 | } | ||
823 | |||
824 | int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, | ||
825 | u32 *changed) | ||
826 | { | ||
827 | struct ieee80211_local *local = sdata->local; | ||
828 | struct ieee80211_chanctx_conf *conf; | ||
829 | struct ieee80211_chanctx *ctx; | ||
830 | int ret; | ||
831 | |||
832 | lockdep_assert_held(&local->mtx); | ||
833 | |||
834 | /* should never be called if not performing a channel switch. */ | ||
835 | if (WARN_ON(!sdata->vif.csa_active)) | ||
836 | return -EINVAL; | ||
837 | |||
838 | mutex_lock(&local->chanctx_mtx); | ||
839 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
840 | lockdep_is_held(&local->chanctx_mtx)); | ||
841 | if (!conf) { | ||
842 | ret = -EINVAL; | ||
843 | goto out; | ||
844 | } | ||
845 | |||
846 | ctx = container_of(conf, struct ieee80211_chanctx, conf); | ||
847 | |||
848 | ret = __ieee80211_vif_change_channel(sdata, ctx, changed); | ||
849 | out: | ||
850 | mutex_unlock(&local->chanctx_mtx); | ||
851 | return ret; | ||
852 | } | ||
853 | |||
854 | static void | 822 | static void |
855 | __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, | 823 | __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, |
856 | bool clear) | 824 | bool clear) |
@@ -905,8 +873,25 @@ int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata) | |||
905 | list_del(&sdata->reserved_chanctx_list); | 873 | list_del(&sdata->reserved_chanctx_list); |
906 | sdata->reserved_chanctx = NULL; | 874 | sdata->reserved_chanctx = NULL; |
907 | 875 | ||
908 | if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) | 876 | if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) { |
909 | ieee80211_free_chanctx(sdata->local, ctx); | 877 | if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) { |
878 | if (WARN_ON(!ctx->replace_ctx)) | ||
879 | return -EINVAL; | ||
880 | |||
881 | WARN_ON(ctx->replace_ctx->replace_state != | ||
882 | IEEE80211_CHANCTX_WILL_BE_REPLACED); | ||
883 | WARN_ON(ctx->replace_ctx->replace_ctx != ctx); | ||
884 | |||
885 | ctx->replace_ctx->replace_ctx = NULL; | ||
886 | ctx->replace_ctx->replace_state = | ||
887 | IEEE80211_CHANCTX_REPLACE_NONE; | ||
888 | |||
889 | list_del_rcu(&ctx->list); | ||
890 | kfree_rcu(ctx, rcu_head); | ||
891 | } else { | ||
892 | ieee80211_free_chanctx(sdata->local, ctx); | ||
893 | } | ||
894 | } | ||
910 | 895 | ||
911 | return 0; | 896 | return 0; |
912 | } | 897 | } |
@@ -917,40 +902,84 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, | |||
917 | bool radar_required) | 902 | bool radar_required) |
918 | { | 903 | { |
919 | struct ieee80211_local *local = sdata->local; | 904 | struct ieee80211_local *local = sdata->local; |
920 | struct ieee80211_chanctx_conf *conf; | 905 | struct ieee80211_chanctx *new_ctx, *curr_ctx, *ctx; |
921 | struct ieee80211_chanctx *new_ctx, *curr_ctx; | ||
922 | int ret = 0; | ||
923 | 906 | ||
924 | mutex_lock(&local->chanctx_mtx); | 907 | lockdep_assert_held(&local->chanctx_mtx); |
925 | |||
926 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
927 | lockdep_is_held(&local->chanctx_mtx)); | ||
928 | if (!conf) { | ||
929 | ret = -EINVAL; | ||
930 | goto out; | ||
931 | } | ||
932 | 908 | ||
933 | curr_ctx = container_of(conf, struct ieee80211_chanctx, conf); | 909 | curr_ctx = ieee80211_vif_get_chanctx(sdata); |
910 | if (curr_ctx && local->use_chanctx && !local->ops->switch_vif_chanctx) | ||
911 | return -ENOTSUPP; | ||
934 | 912 | ||
935 | new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode); | 913 | new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode); |
936 | if (!new_ctx) { | 914 | if (!new_ctx) { |
937 | if (ieee80211_chanctx_refcount(local, curr_ctx) == 1 && | 915 | if (ieee80211_can_create_new_chanctx(local)) { |
938 | (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) { | ||
939 | /* if we're the only users of the chanctx and | ||
940 | * the driver supports changing a running | ||
941 | * context, reserve our current context | ||
942 | */ | ||
943 | new_ctx = curr_ctx; | ||
944 | } else if (ieee80211_can_create_new_chanctx(local)) { | ||
945 | /* create a new context and reserve it */ | ||
946 | new_ctx = ieee80211_new_chanctx(local, chandef, mode); | 916 | new_ctx = ieee80211_new_chanctx(local, chandef, mode); |
947 | if (IS_ERR(new_ctx)) { | 917 | if (IS_ERR(new_ctx)) |
948 | ret = PTR_ERR(new_ctx); | 918 | return PTR_ERR(new_ctx); |
949 | goto out; | ||
950 | } | ||
951 | } else { | 919 | } else { |
952 | ret = -EBUSY; | 920 | if (!curr_ctx || |
953 | goto out; | 921 | (curr_ctx->replace_state == |
922 | IEEE80211_CHANCTX_WILL_BE_REPLACED) || | ||
923 | !list_empty(&curr_ctx->reserved_vifs)) { | ||
924 | /* | ||
925 | * Another vif already requested this context | ||
926 | * for a reservation. Find another one hoping | ||
927 | * all vifs assigned to it will also switch | ||
928 | * soon enough. | ||
929 | * | ||
930 | * TODO: This needs a little more work as some | ||
931 | * cases (more than 2 chanctx capable devices) | ||
932 | * may fail which could otherwise succeed | ||
933 | * provided some channel context juggling was | ||
934 | * performed. | ||
935 | * | ||
936 | * Consider ctx1..3, vif1..6, each ctx has 2 | ||
937 | * vifs. vif1 and vif2 from ctx1 request new | ||
938 | * different chandefs starting 2 in-place | ||
939 | * reserations with ctx4 and ctx5 replacing | ||
940 | * ctx1 and ctx2 respectively. Next vif5 and | ||
941 | * vif6 from ctx3 reserve ctx4. If vif3 and | ||
942 | * vif4 remain on ctx2 as they are then this | ||
943 | * fails unless `replace_ctx` from ctx5 is | ||
944 | * replaced with ctx3. | ||
945 | */ | ||
946 | list_for_each_entry(ctx, &local->chanctx_list, | ||
947 | list) { | ||
948 | if (ctx->replace_state != | ||
949 | IEEE80211_CHANCTX_REPLACE_NONE) | ||
950 | continue; | ||
951 | |||
952 | if (!list_empty(&ctx->reserved_vifs)) | ||
953 | continue; | ||
954 | |||
955 | curr_ctx = ctx; | ||
956 | break; | ||
957 | } | ||
958 | } | ||
959 | |||
960 | /* | ||
961 | * If that's true then all available contexts already | ||
962 | * have reservations and cannot be used. | ||
963 | */ | ||
964 | if (!curr_ctx || | ||
965 | (curr_ctx->replace_state == | ||
966 | IEEE80211_CHANCTX_WILL_BE_REPLACED) || | ||
967 | !list_empty(&curr_ctx->reserved_vifs)) | ||
968 | return -EBUSY; | ||
969 | |||
970 | new_ctx = ieee80211_alloc_chanctx(local, chandef, mode); | ||
971 | if (!new_ctx) | ||
972 | return -ENOMEM; | ||
973 | |||
974 | new_ctx->replace_ctx = curr_ctx; | ||
975 | new_ctx->replace_state = | ||
976 | IEEE80211_CHANCTX_REPLACES_OTHER; | ||
977 | |||
978 | curr_ctx->replace_ctx = new_ctx; | ||
979 | curr_ctx->replace_state = | ||
980 | IEEE80211_CHANCTX_WILL_BE_REPLACED; | ||
981 | |||
982 | list_add_rcu(&new_ctx->list, &local->chanctx_list); | ||
954 | } | 983 | } |
955 | } | 984 | } |
956 | 985 | ||
@@ -958,82 +987,601 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, | |||
958 | sdata->reserved_chanctx = new_ctx; | 987 | sdata->reserved_chanctx = new_ctx; |
959 | sdata->reserved_chandef = *chandef; | 988 | sdata->reserved_chandef = *chandef; |
960 | sdata->reserved_radar_required = radar_required; | 989 | sdata->reserved_radar_required = radar_required; |
961 | out: | 990 | sdata->reserved_ready = false; |
962 | mutex_unlock(&local->chanctx_mtx); | 991 | |
963 | return ret; | 992 | return 0; |
964 | } | 993 | } |
965 | 994 | ||
966 | int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata, | 995 | static void |
967 | u32 *changed) | 996 | ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata) |
968 | { | 997 | { |
969 | struct ieee80211_local *local = sdata->local; | 998 | switch (sdata->vif.type) { |
970 | struct ieee80211_chanctx *ctx; | 999 | case NL80211_IFTYPE_ADHOC: |
971 | struct ieee80211_chanctx *old_ctx; | 1000 | case NL80211_IFTYPE_AP: |
972 | struct ieee80211_chanctx_conf *conf; | 1001 | case NL80211_IFTYPE_MESH_POINT: |
973 | int ret; | 1002 | ieee80211_queue_work(&sdata->local->hw, |
974 | u32 tmp_changed = *changed; | 1003 | &sdata->csa_finalize_work); |
1004 | break; | ||
1005 | case NL80211_IFTYPE_STATION: | ||
1006 | ieee80211_queue_work(&sdata->local->hw, | ||
1007 | &sdata->u.mgd.chswitch_work); | ||
1008 | break; | ||
1009 | case NL80211_IFTYPE_UNSPECIFIED: | ||
1010 | case NL80211_IFTYPE_AP_VLAN: | ||
1011 | case NL80211_IFTYPE_WDS: | ||
1012 | case NL80211_IFTYPE_MONITOR: | ||
1013 | case NL80211_IFTYPE_P2P_CLIENT: | ||
1014 | case NL80211_IFTYPE_P2P_GO: | ||
1015 | case NL80211_IFTYPE_P2P_DEVICE: | ||
1016 | case NUM_NL80211_IFTYPES: | ||
1017 | WARN_ON(1); | ||
1018 | break; | ||
1019 | } | ||
1020 | } | ||
975 | 1021 | ||
976 | /* TODO: need to recheck if the chandef is usable etc.? */ | 1022 | static int |
1023 | ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) | ||
1024 | { | ||
1025 | struct ieee80211_local *local = sdata->local; | ||
1026 | struct ieee80211_vif_chanctx_switch vif_chsw[1] = {}; | ||
1027 | struct ieee80211_chanctx *old_ctx, *new_ctx; | ||
1028 | const struct cfg80211_chan_def *chandef; | ||
1029 | u32 changed = 0; | ||
1030 | int err; | ||
977 | 1031 | ||
978 | lockdep_assert_held(&local->mtx); | 1032 | lockdep_assert_held(&local->mtx); |
1033 | lockdep_assert_held(&local->chanctx_mtx); | ||
979 | 1034 | ||
980 | mutex_lock(&local->chanctx_mtx); | 1035 | new_ctx = sdata->reserved_chanctx; |
1036 | old_ctx = ieee80211_vif_get_chanctx(sdata); | ||
981 | 1037 | ||
982 | ctx = sdata->reserved_chanctx; | 1038 | if (WARN_ON(!sdata->reserved_ready)) |
983 | if (WARN_ON(!ctx)) { | 1039 | return -EBUSY; |
984 | ret = -EINVAL; | 1040 | |
985 | goto out; | 1041 | if (WARN_ON(!new_ctx)) |
986 | } | 1042 | return -EINVAL; |
1043 | |||
1044 | if (WARN_ON(!old_ctx)) | ||
1045 | return -EINVAL; | ||
1046 | |||
1047 | if (WARN_ON(new_ctx->replace_state == | ||
1048 | IEEE80211_CHANCTX_REPLACES_OTHER)) | ||
1049 | return -EINVAL; | ||
1050 | |||
1051 | chandef = ieee80211_chanctx_non_reserved_chandef(local, new_ctx, | ||
1052 | &sdata->reserved_chandef); | ||
1053 | if (WARN_ON(!chandef)) | ||
1054 | return -EINVAL; | ||
1055 | |||
1056 | vif_chsw[0].vif = &sdata->vif; | ||
1057 | vif_chsw[0].old_ctx = &old_ctx->conf; | ||
1058 | vif_chsw[0].new_ctx = &new_ctx->conf; | ||
1059 | |||
1060 | list_del(&sdata->reserved_chanctx_list); | ||
1061 | sdata->reserved_chanctx = NULL; | ||
1062 | |||
1063 | err = drv_switch_vif_chanctx(local, vif_chsw, 1, | ||
1064 | CHANCTX_SWMODE_REASSIGN_VIF); | ||
1065 | if (err) { | ||
1066 | if (ieee80211_chanctx_refcount(local, new_ctx) == 0) | ||
1067 | ieee80211_free_chanctx(local, new_ctx); | ||
987 | 1068 | ||
988 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
989 | lockdep_is_held(&local->chanctx_mtx)); | ||
990 | if (!conf) { | ||
991 | ret = -EINVAL; | ||
992 | goto out; | 1069 | goto out; |
993 | } | 1070 | } |
994 | 1071 | ||
995 | old_ctx = container_of(conf, struct ieee80211_chanctx, conf); | 1072 | list_move(&sdata->assigned_chanctx_list, &new_ctx->assigned_vifs); |
1073 | rcu_assign_pointer(sdata->vif.chanctx_conf, &new_ctx->conf); | ||
1074 | |||
1075 | if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
1076 | __ieee80211_vif_copy_chanctx_to_vlans(sdata, false); | ||
1077 | |||
1078 | if (ieee80211_chanctx_refcount(local, old_ctx) == 0) | ||
1079 | ieee80211_free_chanctx(local, old_ctx); | ||
996 | 1080 | ||
997 | if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width) | 1081 | if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width) |
998 | tmp_changed |= BSS_CHANGED_BANDWIDTH; | 1082 | changed = BSS_CHANGED_BANDWIDTH; |
999 | 1083 | ||
1000 | sdata->vif.bss_conf.chandef = sdata->reserved_chandef; | 1084 | sdata->vif.bss_conf.chandef = sdata->reserved_chandef; |
1001 | 1085 | ||
1002 | /* unref our reservation */ | 1086 | if (changed) |
1003 | sdata->reserved_chanctx = NULL; | 1087 | ieee80211_bss_info_change_notify(sdata, changed); |
1004 | sdata->radar_required = sdata->reserved_radar_required; | 1088 | |
1089 | out: | ||
1090 | ieee80211_vif_chanctx_reservation_complete(sdata); | ||
1091 | return err; | ||
1092 | } | ||
1093 | |||
1094 | static int | ||
1095 | ieee80211_vif_use_reserved_assign(struct ieee80211_sub_if_data *sdata) | ||
1096 | { | ||
1097 | struct ieee80211_local *local = sdata->local; | ||
1098 | struct ieee80211_chanctx *old_ctx, *new_ctx; | ||
1099 | const struct cfg80211_chan_def *chandef; | ||
1100 | int err; | ||
1101 | |||
1102 | old_ctx = ieee80211_vif_get_chanctx(sdata); | ||
1103 | new_ctx = sdata->reserved_chanctx; | ||
1104 | |||
1105 | if (WARN_ON(!sdata->reserved_ready)) | ||
1106 | return -EINVAL; | ||
1107 | |||
1108 | if (WARN_ON(old_ctx)) | ||
1109 | return -EINVAL; | ||
1110 | |||
1111 | if (WARN_ON(!new_ctx)) | ||
1112 | return -EINVAL; | ||
1113 | |||
1114 | if (WARN_ON(new_ctx->replace_state == | ||
1115 | IEEE80211_CHANCTX_REPLACES_OTHER)) | ||
1116 | return -EINVAL; | ||
1117 | |||
1118 | chandef = ieee80211_chanctx_non_reserved_chandef(local, new_ctx, | ||
1119 | &sdata->reserved_chandef); | ||
1120 | if (WARN_ON(!chandef)) | ||
1121 | return -EINVAL; | ||
1122 | |||
1005 | list_del(&sdata->reserved_chanctx_list); | 1123 | list_del(&sdata->reserved_chanctx_list); |
1124 | sdata->reserved_chanctx = NULL; | ||
1006 | 1125 | ||
1007 | if (old_ctx == ctx) { | 1126 | err = ieee80211_assign_vif_chanctx(sdata, new_ctx); |
1008 | /* This is our own context, just change it */ | 1127 | if (err) { |
1009 | ret = __ieee80211_vif_change_channel(sdata, old_ctx, | 1128 | if (ieee80211_chanctx_refcount(local, new_ctx) == 0) |
1010 | &tmp_changed); | 1129 | ieee80211_free_chanctx(local, new_ctx); |
1011 | if (ret) | 1130 | |
1012 | goto out; | 1131 | goto out; |
1013 | } else { | 1132 | } |
1014 | ret = ieee80211_assign_vif_chanctx(sdata, ctx); | 1133 | |
1015 | if (ieee80211_chanctx_refcount(local, old_ctx) == 0) | 1134 | out: |
1016 | ieee80211_free_chanctx(local, old_ctx); | 1135 | ieee80211_vif_chanctx_reservation_complete(sdata); |
1017 | if (ret) { | 1136 | return err; |
1018 | /* if assign fails refcount stays the same */ | 1137 | } |
1019 | if (ieee80211_chanctx_refcount(local, ctx) == 0) | 1138 | |
1020 | ieee80211_free_chanctx(local, ctx); | 1139 | static bool |
1140 | ieee80211_vif_has_in_place_reservation(struct ieee80211_sub_if_data *sdata) | ||
1141 | { | ||
1142 | struct ieee80211_chanctx *old_ctx, *new_ctx; | ||
1143 | |||
1144 | lockdep_assert_held(&sdata->local->chanctx_mtx); | ||
1145 | |||
1146 | new_ctx = sdata->reserved_chanctx; | ||
1147 | old_ctx = ieee80211_vif_get_chanctx(sdata); | ||
1148 | |||
1149 | if (!old_ctx) | ||
1150 | return false; | ||
1151 | |||
1152 | if (WARN_ON(!new_ctx)) | ||
1153 | return false; | ||
1154 | |||
1155 | if (old_ctx->replace_state != IEEE80211_CHANCTX_WILL_BE_REPLACED) | ||
1156 | return false; | ||
1157 | |||
1158 | if (new_ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) | ||
1159 | return false; | ||
1160 | |||
1161 | return true; | ||
1162 | } | ||
1163 | |||
1164 | static int ieee80211_chsw_switch_hwconf(struct ieee80211_local *local, | ||
1165 | struct ieee80211_chanctx *new_ctx) | ||
1166 | { | ||
1167 | const struct cfg80211_chan_def *chandef; | ||
1168 | |||
1169 | lockdep_assert_held(&local->mtx); | ||
1170 | lockdep_assert_held(&local->chanctx_mtx); | ||
1171 | |||
1172 | chandef = ieee80211_chanctx_reserved_chandef(local, new_ctx, NULL); | ||
1173 | if (WARN_ON(!chandef)) | ||
1174 | return -EINVAL; | ||
1175 | |||
1176 | local->hw.conf.radar_enabled = new_ctx->conf.radar_enabled; | ||
1177 | local->_oper_chandef = *chandef; | ||
1178 | ieee80211_hw_config(local, 0); | ||
1179 | |||
1180 | return 0; | ||
1181 | } | ||
1182 | |||
1183 | static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local, | ||
1184 | int n_vifs) | ||
1185 | { | ||
1186 | struct ieee80211_vif_chanctx_switch *vif_chsw; | ||
1187 | struct ieee80211_sub_if_data *sdata; | ||
1188 | struct ieee80211_chanctx *ctx, *old_ctx; | ||
1189 | int i, err; | ||
1190 | |||
1191 | lockdep_assert_held(&local->mtx); | ||
1192 | lockdep_assert_held(&local->chanctx_mtx); | ||
1193 | |||
1194 | vif_chsw = kzalloc(sizeof(vif_chsw[0]) * n_vifs, GFP_KERNEL); | ||
1195 | if (!vif_chsw) | ||
1196 | return -ENOMEM; | ||
1197 | |||
1198 | i = 0; | ||
1199 | list_for_each_entry(ctx, &local->chanctx_list, list) { | ||
1200 | if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) | ||
1201 | continue; | ||
1202 | |||
1203 | if (WARN_ON(!ctx->replace_ctx)) { | ||
1204 | err = -EINVAL; | ||
1021 | goto out; | 1205 | goto out; |
1022 | } | 1206 | } |
1023 | 1207 | ||
1024 | if (sdata->vif.type == NL80211_IFTYPE_AP) | 1208 | list_for_each_entry(sdata, &ctx->reserved_vifs, |
1025 | __ieee80211_vif_copy_chanctx_to_vlans(sdata, false); | 1209 | reserved_chanctx_list) { |
1210 | if (!ieee80211_vif_has_in_place_reservation( | ||
1211 | sdata)) | ||
1212 | continue; | ||
1213 | |||
1214 | old_ctx = ieee80211_vif_get_chanctx(sdata); | ||
1215 | vif_chsw[i].vif = &sdata->vif; | ||
1216 | vif_chsw[i].old_ctx = &old_ctx->conf; | ||
1217 | vif_chsw[i].new_ctx = &ctx->conf; | ||
1218 | |||
1219 | i++; | ||
1220 | } | ||
1026 | } | 1221 | } |
1027 | 1222 | ||
1028 | *changed = tmp_changed; | 1223 | err = drv_switch_vif_chanctx(local, vif_chsw, n_vifs, |
1224 | CHANCTX_SWMODE_SWAP_CONTEXTS); | ||
1029 | 1225 | ||
1030 | ieee80211_recalc_chanctx_chantype(local, ctx); | ||
1031 | ieee80211_recalc_smps_chanctx(local, ctx); | ||
1032 | ieee80211_recalc_radar_chanctx(local, ctx); | ||
1033 | ieee80211_recalc_chanctx_min_def(local, ctx); | ||
1034 | out: | 1226 | out: |
1035 | mutex_unlock(&local->chanctx_mtx); | 1227 | kfree(vif_chsw); |
1036 | return ret; | 1228 | return err; |
1229 | } | ||
1230 | |||
1231 | static int ieee80211_chsw_switch_ctxs(struct ieee80211_local *local) | ||
1232 | { | ||
1233 | struct ieee80211_chanctx *ctx; | ||
1234 | int err; | ||
1235 | |||
1236 | lockdep_assert_held(&local->mtx); | ||
1237 | lockdep_assert_held(&local->chanctx_mtx); | ||
1238 | |||
1239 | list_for_each_entry(ctx, &local->chanctx_list, list) { | ||
1240 | if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) | ||
1241 | continue; | ||
1242 | |||
1243 | if (!list_empty(&ctx->replace_ctx->assigned_vifs)) | ||
1244 | continue; | ||
1245 | |||
1246 | ieee80211_del_chanctx(local, ctx->replace_ctx); | ||
1247 | err = ieee80211_add_chanctx(local, ctx); | ||
1248 | if (err) | ||
1249 | goto err; | ||
1250 | } | ||
1251 | |||
1252 | return 0; | ||
1253 | |||
1254 | err: | ||
1255 | WARN_ON(ieee80211_add_chanctx(local, ctx)); | ||
1256 | list_for_each_entry_continue_reverse(ctx, &local->chanctx_list, list) { | ||
1257 | if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) | ||
1258 | continue; | ||
1259 | |||
1260 | if (!list_empty(&ctx->replace_ctx->assigned_vifs)) | ||
1261 | continue; | ||
1262 | |||
1263 | ieee80211_del_chanctx(local, ctx); | ||
1264 | WARN_ON(ieee80211_add_chanctx(local, ctx->replace_ctx)); | ||
1265 | } | ||
1266 | |||
1267 | return err; | ||
1268 | } | ||
1269 | |||
1270 | int | ||
1271 | ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) | ||
1272 | { | ||
1273 | struct ieee80211_sub_if_data *sdata, *sdata_tmp; | ||
1274 | struct ieee80211_chanctx *ctx, *ctx_tmp, *old_ctx; | ||
1275 | struct ieee80211_chanctx *new_ctx = NULL; | ||
1276 | int i, err, n_assigned, n_reserved, n_ready; | ||
1277 | int n_ctx = 0, n_vifs_switch = 0, n_vifs_assign = 0, n_vifs_ctxless = 0; | ||
1278 | |||
1279 | lockdep_assert_held(&local->mtx); | ||
1280 | lockdep_assert_held(&local->chanctx_mtx); | ||
1281 | |||
1282 | /* | ||
1283 | * If there are 2 independent pairs of channel contexts performing | ||
1284 | * cross-switch of their vifs this code will still wait until both are | ||
1285 | * ready even though it could be possible to switch one before the | ||
1286 | * other is ready. | ||
1287 | * | ||
1288 | * For practical reasons and code simplicity just do a single huge | ||
1289 | * switch. | ||
1290 | */ | ||
1291 | |||
1292 | /* | ||
1293 | * Verify if the reservation is still feasible. | ||
1294 | * - if it's not then disconnect | ||
1295 | * - if it is but not all vifs necessary are ready then defer | ||
1296 | */ | ||
1297 | |||
1298 | list_for_each_entry(ctx, &local->chanctx_list, list) { | ||
1299 | if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) | ||
1300 | continue; | ||
1301 | |||
1302 | if (WARN_ON(!ctx->replace_ctx)) { | ||
1303 | err = -EINVAL; | ||
1304 | goto err; | ||
1305 | } | ||
1306 | |||
1307 | if (!local->use_chanctx) | ||
1308 | new_ctx = ctx; | ||
1309 | |||
1310 | n_ctx++; | ||
1311 | |||
1312 | n_assigned = 0; | ||
1313 | n_reserved = 0; | ||
1314 | n_ready = 0; | ||
1315 | |||
1316 | list_for_each_entry(sdata, &ctx->replace_ctx->assigned_vifs, | ||
1317 | assigned_chanctx_list) { | ||
1318 | n_assigned++; | ||
1319 | if (sdata->reserved_chanctx) { | ||
1320 | n_reserved++; | ||
1321 | if (sdata->reserved_ready) | ||
1322 | n_ready++; | ||
1323 | } | ||
1324 | } | ||
1325 | |||
1326 | if (n_assigned != n_reserved) { | ||
1327 | if (n_ready == n_reserved) { | ||
1328 | wiphy_info(local->hw.wiphy, | ||
1329 | "channel context reservation cannot be finalized because some interfaces aren't switching\n"); | ||
1330 | err = -EBUSY; | ||
1331 | goto err; | ||
1332 | } | ||
1333 | |||
1334 | return -EAGAIN; | ||
1335 | } | ||
1336 | |||
1337 | ctx->conf.radar_enabled = false; | ||
1338 | list_for_each_entry(sdata, &ctx->reserved_vifs, | ||
1339 | reserved_chanctx_list) { | ||
1340 | if (ieee80211_vif_has_in_place_reservation(sdata) && | ||
1341 | !sdata->reserved_ready) | ||
1342 | return -EAGAIN; | ||
1343 | |||
1344 | old_ctx = ieee80211_vif_get_chanctx(sdata); | ||
1345 | if (old_ctx) { | ||
1346 | if (old_ctx->replace_state == | ||
1347 | IEEE80211_CHANCTX_WILL_BE_REPLACED) | ||
1348 | n_vifs_switch++; | ||
1349 | else | ||
1350 | n_vifs_assign++; | ||
1351 | } else { | ||
1352 | n_vifs_ctxless++; | ||
1353 | } | ||
1354 | |||
1355 | if (sdata->reserved_radar_required) | ||
1356 | ctx->conf.radar_enabled = true; | ||
1357 | } | ||
1358 | } | ||
1359 | |||
1360 | if (WARN_ON(n_ctx == 0) || | ||
1361 | WARN_ON(n_vifs_switch == 0 && | ||
1362 | n_vifs_assign == 0 && | ||
1363 | n_vifs_ctxless == 0) || | ||
1364 | WARN_ON(n_ctx > 1 && !local->use_chanctx) || | ||
1365 | WARN_ON(!new_ctx && !local->use_chanctx)) { | ||
1366 | err = -EINVAL; | ||
1367 | goto err; | ||
1368 | } | ||
1369 | |||
1370 | /* | ||
1371 | * All necessary vifs are ready. Perform the switch now depending on | ||
1372 | * reservations and driver capabilities. | ||
1373 | */ | ||
1374 | |||
1375 | if (local->use_chanctx) { | ||
1376 | if (n_vifs_switch > 0) { | ||
1377 | err = ieee80211_chsw_switch_vifs(local, n_vifs_switch); | ||
1378 | if (err) | ||
1379 | goto err; | ||
1380 | } | ||
1381 | |||
1382 | if (n_vifs_assign > 0 || n_vifs_ctxless > 0) { | ||
1383 | err = ieee80211_chsw_switch_ctxs(local); | ||
1384 | if (err) | ||
1385 | goto err; | ||
1386 | } | ||
1387 | } else { | ||
1388 | err = ieee80211_chsw_switch_hwconf(local, new_ctx); | ||
1389 | if (err) | ||
1390 | goto err; | ||
1391 | } | ||
1392 | |||
1393 | /* | ||
1394 | * Update all structures, values and pointers to point to new channel | ||
1395 | * context(s). | ||
1396 | */ | ||
1397 | |||
1398 | i = 0; | ||
1399 | list_for_each_entry(ctx, &local->chanctx_list, list) { | ||
1400 | if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) | ||
1401 | continue; | ||
1402 | |||
1403 | if (WARN_ON(!ctx->replace_ctx)) { | ||
1404 | err = -EINVAL; | ||
1405 | goto err; | ||
1406 | } | ||
1407 | |||
1408 | list_for_each_entry(sdata, &ctx->reserved_vifs, | ||
1409 | reserved_chanctx_list) { | ||
1410 | u32 changed = 0; | ||
1411 | |||
1412 | if (!ieee80211_vif_has_in_place_reservation(sdata)) | ||
1413 | continue; | ||
1414 | |||
1415 | rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf); | ||
1416 | |||
1417 | if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
1418 | __ieee80211_vif_copy_chanctx_to_vlans(sdata, | ||
1419 | false); | ||
1420 | |||
1421 | sdata->radar_required = sdata->reserved_radar_required; | ||
1422 | |||
1423 | if (sdata->vif.bss_conf.chandef.width != | ||
1424 | sdata->reserved_chandef.width) | ||
1425 | changed = BSS_CHANGED_BANDWIDTH; | ||
1426 | |||
1427 | sdata->vif.bss_conf.chandef = sdata->reserved_chandef; | ||
1428 | if (changed) | ||
1429 | ieee80211_bss_info_change_notify(sdata, | ||
1430 | changed); | ||
1431 | |||
1432 | ieee80211_recalc_txpower(sdata); | ||
1433 | } | ||
1434 | |||
1435 | ieee80211_recalc_chanctx_chantype(local, ctx); | ||
1436 | ieee80211_recalc_smps_chanctx(local, ctx); | ||
1437 | ieee80211_recalc_radar_chanctx(local, ctx); | ||
1438 | ieee80211_recalc_chanctx_min_def(local, ctx); | ||
1439 | |||
1440 | list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs, | ||
1441 | reserved_chanctx_list) { | ||
1442 | if (ieee80211_vif_get_chanctx(sdata) != ctx) | ||
1443 | continue; | ||
1444 | |||
1445 | list_del(&sdata->reserved_chanctx_list); | ||
1446 | list_move(&sdata->assigned_chanctx_list, | ||
1447 | &new_ctx->assigned_vifs); | ||
1448 | sdata->reserved_chanctx = NULL; | ||
1449 | |||
1450 | ieee80211_vif_chanctx_reservation_complete(sdata); | ||
1451 | } | ||
1452 | |||
1453 | /* | ||
1454 | * This context might have been a dependency for an already | ||
1455 | * ready re-assign reservation interface that was deferred. Do | ||
1456 | * not propagate error to the caller though. The in-place | ||
1457 | * reservation for originally requested interface has already | ||
1458 | * succeeded at this point. | ||
1459 | */ | ||
1460 | list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs, | ||
1461 | reserved_chanctx_list) { | ||
1462 | if (WARN_ON(ieee80211_vif_has_in_place_reservation( | ||
1463 | sdata))) | ||
1464 | continue; | ||
1465 | |||
1466 | if (WARN_ON(sdata->reserved_chanctx != ctx)) | ||
1467 | continue; | ||
1468 | |||
1469 | if (!sdata->reserved_ready) | ||
1470 | continue; | ||
1471 | |||
1472 | if (ieee80211_vif_get_chanctx(sdata)) | ||
1473 | err = ieee80211_vif_use_reserved_reassign( | ||
1474 | sdata); | ||
1475 | else | ||
1476 | err = ieee80211_vif_use_reserved_assign(sdata); | ||
1477 | |||
1478 | if (err) { | ||
1479 | sdata_info(sdata, | ||
1480 | "failed to finalize (re-)assign reservation (err=%d)\n", | ||
1481 | err); | ||
1482 | ieee80211_vif_unreserve_chanctx(sdata); | ||
1483 | cfg80211_stop_iface(local->hw.wiphy, | ||
1484 | &sdata->wdev, | ||
1485 | GFP_KERNEL); | ||
1486 | } | ||
1487 | } | ||
1488 | } | ||
1489 | |||
1490 | /* | ||
1491 | * Finally free old contexts | ||
1492 | */ | ||
1493 | |||
1494 | list_for_each_entry_safe(ctx, ctx_tmp, &local->chanctx_list, list) { | ||
1495 | if (ctx->replace_state != IEEE80211_CHANCTX_WILL_BE_REPLACED) | ||
1496 | continue; | ||
1497 | |||
1498 | ctx->replace_ctx->replace_ctx = NULL; | ||
1499 | ctx->replace_ctx->replace_state = | ||
1500 | IEEE80211_CHANCTX_REPLACE_NONE; | ||
1501 | |||
1502 | list_del_rcu(&ctx->list); | ||
1503 | kfree_rcu(ctx, rcu_head); | ||
1504 | } | ||
1505 | |||
1506 | return 0; | ||
1507 | |||
1508 | err: | ||
1509 | list_for_each_entry(ctx, &local->chanctx_list, list) { | ||
1510 | if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) | ||
1511 | continue; | ||
1512 | |||
1513 | list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs, | ||
1514 | reserved_chanctx_list) { | ||
1515 | ieee80211_vif_unreserve_chanctx(sdata); | ||
1516 | ieee80211_vif_chanctx_reservation_complete(sdata); | ||
1517 | } | ||
1518 | } | ||
1519 | |||
1520 | return err; | ||
1521 | } | ||
1522 | |||
1523 | int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata) | ||
1524 | { | ||
1525 | struct ieee80211_local *local = sdata->local; | ||
1526 | struct ieee80211_chanctx *new_ctx; | ||
1527 | struct ieee80211_chanctx *old_ctx; | ||
1528 | int err; | ||
1529 | |||
1530 | lockdep_assert_held(&local->mtx); | ||
1531 | lockdep_assert_held(&local->chanctx_mtx); | ||
1532 | |||
1533 | new_ctx = sdata->reserved_chanctx; | ||
1534 | old_ctx = ieee80211_vif_get_chanctx(sdata); | ||
1535 | |||
1536 | if (WARN_ON(!new_ctx)) | ||
1537 | return -EINVAL; | ||
1538 | |||
1539 | if (WARN_ON(new_ctx->replace_state == | ||
1540 | IEEE80211_CHANCTX_WILL_BE_REPLACED)) | ||
1541 | return -EINVAL; | ||
1542 | |||
1543 | if (WARN_ON(sdata->reserved_ready)) | ||
1544 | return -EINVAL; | ||
1545 | |||
1546 | sdata->reserved_ready = true; | ||
1547 | |||
1548 | if (new_ctx->replace_state == IEEE80211_CHANCTX_REPLACE_NONE) { | ||
1549 | if (old_ctx) | ||
1550 | err = ieee80211_vif_use_reserved_reassign(sdata); | ||
1551 | else | ||
1552 | err = ieee80211_vif_use_reserved_assign(sdata); | ||
1553 | |||
1554 | if (err) | ||
1555 | return err; | ||
1556 | } | ||
1557 | |||
1558 | /* | ||
1559 | * In-place reservation may need to be finalized now either if: | ||
1560 | * a) sdata is taking part in the swapping itself and is the last one | ||
1561 | * b) sdata has switched with a re-assign reservation to an existing | ||
1562 | * context readying in-place switching of old_ctx | ||
1563 | * | ||
1564 | * In case of (b) do not propagate the error up because the requested | ||
1565 | * sdata already switched successfully. Just spill an extra warning. | ||
1566 | * The ieee80211_vif_use_reserved_switch() already stops all necessary | ||
1567 | * interfaces upon failure. | ||
1568 | */ | ||
1569 | if ((old_ctx && | ||
1570 | old_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) || | ||
1571 | new_ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) { | ||
1572 | err = ieee80211_vif_use_reserved_switch(local); | ||
1573 | if (err && err != -EAGAIN) { | ||
1574 | if (new_ctx->replace_state == | ||
1575 | IEEE80211_CHANCTX_REPLACES_OTHER) | ||
1576 | return err; | ||
1577 | |||
1578 | wiphy_info(local->hw.wiphy, | ||
1579 | "depending in-place reservation failed (err=%d)\n", | ||
1580 | err); | ||
1581 | } | ||
1582 | } | ||
1583 | |||
1584 | return 0; | ||
1037 | } | 1585 | } |
1038 | 1586 | ||
1039 | int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | 1587 | int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, |
@@ -1043,6 +1591,7 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | |||
1043 | struct ieee80211_local *local = sdata->local; | 1591 | struct ieee80211_local *local = sdata->local; |
1044 | struct ieee80211_chanctx_conf *conf; | 1592 | struct ieee80211_chanctx_conf *conf; |
1045 | struct ieee80211_chanctx *ctx; | 1593 | struct ieee80211_chanctx *ctx; |
1594 | const struct cfg80211_chan_def *compat; | ||
1046 | int ret; | 1595 | int ret; |
1047 | 1596 | ||
1048 | if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, | 1597 | if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, |
@@ -1069,11 +1618,33 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | |||
1069 | } | 1618 | } |
1070 | 1619 | ||
1071 | ctx = container_of(conf, struct ieee80211_chanctx, conf); | 1620 | ctx = container_of(conf, struct ieee80211_chanctx, conf); |
1072 | if (!cfg80211_chandef_compatible(&conf->def, chandef)) { | 1621 | |
1622 | compat = cfg80211_chandef_compatible(&conf->def, chandef); | ||
1623 | if (!compat) { | ||
1073 | ret = -EINVAL; | 1624 | ret = -EINVAL; |
1074 | goto out; | 1625 | goto out; |
1075 | } | 1626 | } |
1076 | 1627 | ||
1628 | switch (ctx->replace_state) { | ||
1629 | case IEEE80211_CHANCTX_REPLACE_NONE: | ||
1630 | if (!ieee80211_chanctx_reserved_chandef(local, ctx, compat)) { | ||
1631 | ret = -EBUSY; | ||
1632 | goto out; | ||
1633 | } | ||
1634 | break; | ||
1635 | case IEEE80211_CHANCTX_WILL_BE_REPLACED: | ||
1636 | /* TODO: Perhaps the bandwith change could be treated as a | ||
1637 | * reservation itself? */ | ||
1638 | ret = -EBUSY; | ||
1639 | goto out; | ||
1640 | case IEEE80211_CHANCTX_REPLACES_OTHER: | ||
1641 | /* channel context that is going to replace another channel | ||
1642 | * context doesn't really exist and shouldn't be assigned | ||
1643 | * anywhere yet */ | ||
1644 | WARN_ON(1); | ||
1645 | break; | ||
1646 | } | ||
1647 | |||
1077 | sdata->vif.bss_conf.chandef = *chandef; | 1648 | sdata->vif.bss_conf.chandef = *chandef; |
1078 | 1649 | ||
1079 | ieee80211_recalc_chanctx_chantype(local, ctx); | 1650 | ieee80211_recalc_chanctx_chantype(local, ctx); |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 2ecb4deddb5d..3db96648b45a 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -124,7 +124,7 @@ static ssize_t sta_connected_time_read(struct file *file, char __user *userbuf, | |||
124 | long connected_time_secs; | 124 | long connected_time_secs; |
125 | char buf[100]; | 125 | char buf[100]; |
126 | int res; | 126 | int res; |
127 | do_posix_clock_monotonic_gettime(&uptime); | 127 | ktime_get_ts(&uptime); |
128 | connected_time_secs = uptime.tv_sec - sta->last_connected; | 128 | connected_time_secs = uptime.tv_sec - sta->last_connected; |
129 | time_to_tm(connected_time_secs, 0, &result); | 129 | time_to_tm(connected_time_secs, 0, &result); |
130 | result.tm_year -= 70; | 130 | result.tm_year -= 70; |
@@ -587,7 +587,6 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) | |||
587 | DEBUGFS_ADD_COUNTER(tx_filtered, tx_filtered_count); | 587 | DEBUGFS_ADD_COUNTER(tx_filtered, tx_filtered_count); |
588 | DEBUGFS_ADD_COUNTER(tx_retry_failed, tx_retry_failed); | 588 | DEBUGFS_ADD_COUNTER(tx_retry_failed, tx_retry_failed); |
589 | DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count); | 589 | DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count); |
590 | DEBUGFS_ADD_COUNTER(wep_weak_iv_count, wep_weak_iv_count); | ||
591 | 590 | ||
592 | if (sizeof(sta->driver_buffered_tids) == sizeof(u32)) | 591 | if (sizeof(sta->driver_buffered_tids) == sizeof(u32)) |
593 | debugfs_create_x32("driver_buffered_tids", 0400, | 592 | debugfs_create_x32("driver_buffered_tids", 0400, |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index bd782dcffcc7..11423958116a 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -314,7 +314,7 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local, | |||
314 | 314 | ||
315 | static inline int drv_hw_scan(struct ieee80211_local *local, | 315 | static inline int drv_hw_scan(struct ieee80211_local *local, |
316 | struct ieee80211_sub_if_data *sdata, | 316 | struct ieee80211_sub_if_data *sdata, |
317 | struct cfg80211_scan_request *req) | 317 | struct ieee80211_scan_request *req) |
318 | { | 318 | { |
319 | int ret; | 319 | int ret; |
320 | 320 | ||
@@ -346,7 +346,7 @@ static inline int | |||
346 | drv_sched_scan_start(struct ieee80211_local *local, | 346 | drv_sched_scan_start(struct ieee80211_local *local, |
347 | struct ieee80211_sub_if_data *sdata, | 347 | struct ieee80211_sub_if_data *sdata, |
348 | struct cfg80211_sched_scan_request *req, | 348 | struct cfg80211_sched_scan_request *req, |
349 | struct ieee80211_sched_scan_ies *ies) | 349 | struct ieee80211_scan_ies *ies) |
350 | { | 350 | { |
351 | int ret; | 351 | int ret; |
352 | 352 | ||
@@ -970,6 +970,22 @@ static inline void drv_mgd_prepare_tx(struct ieee80211_local *local, | |||
970 | trace_drv_return_void(local); | 970 | trace_drv_return_void(local); |
971 | } | 971 | } |
972 | 972 | ||
973 | static inline void | ||
974 | drv_mgd_protect_tdls_discover(struct ieee80211_local *local, | ||
975 | struct ieee80211_sub_if_data *sdata) | ||
976 | { | ||
977 | might_sleep(); | ||
978 | |||
979 | if (!check_sdata_in_driver(sdata)) | ||
980 | return; | ||
981 | WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION); | ||
982 | |||
983 | trace_drv_mgd_protect_tdls_discover(local, sdata); | ||
984 | if (local->ops->mgd_protect_tdls_discover) | ||
985 | local->ops->mgd_protect_tdls_discover(&local->hw, &sdata->vif); | ||
986 | trace_drv_return_void(local); | ||
987 | } | ||
988 | |||
973 | static inline int drv_add_chanctx(struct ieee80211_local *local, | 989 | static inline int drv_add_chanctx(struct ieee80211_local *local, |
974 | struct ieee80211_chanctx *ctx) | 990 | struct ieee80211_chanctx *ctx) |
975 | { | 991 | { |
diff --git a/net/mac80211/ethtool.c b/net/mac80211/ethtool.c new file mode 100644 index 000000000000..ebfc8091557b --- /dev/null +++ b/net/mac80211/ethtool.c | |||
@@ -0,0 +1,244 @@ | |||
1 | /* | ||
2 | * mac80211 ethtool hooks for cfg80211 | ||
3 | * | ||
4 | * Copied from cfg.c - originally | ||
5 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> | ||
6 | * Copyright 2014 Intel Corporation (Author: Johannes Berg) | ||
7 | * | ||
8 | * This file is GPLv2 as found in COPYING. | ||
9 | */ | ||
10 | #include <linux/types.h> | ||
11 | #include <net/cfg80211.h> | ||
12 | #include "ieee80211_i.h" | ||
13 | #include "sta_info.h" | ||
14 | #include "driver-ops.h" | ||
15 | |||
16 | static int ieee80211_set_ringparam(struct net_device *dev, | ||
17 | struct ethtool_ringparam *rp) | ||
18 | { | ||
19 | struct ieee80211_local *local = wiphy_priv(dev->ieee80211_ptr->wiphy); | ||
20 | |||
21 | if (rp->rx_mini_pending != 0 || rp->rx_jumbo_pending != 0) | ||
22 | return -EINVAL; | ||
23 | |||
24 | return drv_set_ringparam(local, rp->tx_pending, rp->rx_pending); | ||
25 | } | ||
26 | |||
27 | static void ieee80211_get_ringparam(struct net_device *dev, | ||
28 | struct ethtool_ringparam *rp) | ||
29 | { | ||
30 | struct ieee80211_local *local = wiphy_priv(dev->ieee80211_ptr->wiphy); | ||
31 | |||
32 | memset(rp, 0, sizeof(*rp)); | ||
33 | |||
34 | drv_get_ringparam(local, &rp->tx_pending, &rp->tx_max_pending, | ||
35 | &rp->rx_pending, &rp->rx_max_pending); | ||
36 | } | ||
37 | |||
38 | static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = { | ||
39 | "rx_packets", "rx_bytes", | ||
40 | "rx_duplicates", "rx_fragments", "rx_dropped", | ||
41 | "tx_packets", "tx_bytes", "tx_fragments", | ||
42 | "tx_filtered", "tx_retry_failed", "tx_retries", | ||
43 | "beacon_loss", "sta_state", "txrate", "rxrate", "signal", | ||
44 | "channel", "noise", "ch_time", "ch_time_busy", | ||
45 | "ch_time_ext_busy", "ch_time_rx", "ch_time_tx" | ||
46 | }; | ||
47 | #define STA_STATS_LEN ARRAY_SIZE(ieee80211_gstrings_sta_stats) | ||
48 | |||
49 | static int ieee80211_get_sset_count(struct net_device *dev, int sset) | ||
50 | { | ||
51 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
52 | int rv = 0; | ||
53 | |||
54 | if (sset == ETH_SS_STATS) | ||
55 | rv += STA_STATS_LEN; | ||
56 | |||
57 | rv += drv_get_et_sset_count(sdata, sset); | ||
58 | |||
59 | if (rv == 0) | ||
60 | return -EOPNOTSUPP; | ||
61 | return rv; | ||
62 | } | ||
63 | |||
64 | static void ieee80211_get_stats(struct net_device *dev, | ||
65 | struct ethtool_stats *stats, | ||
66 | u64 *data) | ||
67 | { | ||
68 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
69 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
70 | struct ieee80211_channel *channel; | ||
71 | struct sta_info *sta; | ||
72 | struct ieee80211_local *local = sdata->local; | ||
73 | struct station_info sinfo; | ||
74 | struct survey_info survey; | ||
75 | int i, q; | ||
76 | #define STA_STATS_SURVEY_LEN 7 | ||
77 | |||
78 | memset(data, 0, sizeof(u64) * STA_STATS_LEN); | ||
79 | |||
80 | #define ADD_STA_STATS(sta) \ | ||
81 | do { \ | ||
82 | data[i++] += sta->rx_packets; \ | ||
83 | data[i++] += sta->rx_bytes; \ | ||
84 | data[i++] += sta->num_duplicates; \ | ||
85 | data[i++] += sta->rx_fragments; \ | ||
86 | data[i++] += sta->rx_dropped; \ | ||
87 | \ | ||
88 | data[i++] += sinfo.tx_packets; \ | ||
89 | data[i++] += sinfo.tx_bytes; \ | ||
90 | data[i++] += sta->tx_fragments; \ | ||
91 | data[i++] += sta->tx_filtered_count; \ | ||
92 | data[i++] += sta->tx_retry_failed; \ | ||
93 | data[i++] += sta->tx_retry_count; \ | ||
94 | data[i++] += sta->beacon_loss_count; \ | ||
95 | } while (0) | ||
96 | |||
97 | /* For Managed stations, find the single station based on BSSID | ||
98 | * and use that. For interface types, iterate through all available | ||
99 | * stations and add stats for any station that is assigned to this | ||
100 | * network device. | ||
101 | */ | ||
102 | |||
103 | mutex_lock(&local->sta_mtx); | ||
104 | |||
105 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
106 | sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid); | ||
107 | |||
108 | if (!(sta && !WARN_ON(sta->sdata->dev != dev))) | ||
109 | goto do_survey; | ||
110 | |||
111 | sinfo.filled = 0; | ||
112 | sta_set_sinfo(sta, &sinfo); | ||
113 | |||
114 | i = 0; | ||
115 | ADD_STA_STATS(sta); | ||
116 | |||
117 | data[i++] = sta->sta_state; | ||
118 | |||
119 | |||
120 | if (sinfo.filled & STATION_INFO_TX_BITRATE) | ||
121 | data[i] = 100000 * | ||
122 | cfg80211_calculate_bitrate(&sinfo.txrate); | ||
123 | i++; | ||
124 | if (sinfo.filled & STATION_INFO_RX_BITRATE) | ||
125 | data[i] = 100000 * | ||
126 | cfg80211_calculate_bitrate(&sinfo.rxrate); | ||
127 | i++; | ||
128 | |||
129 | if (sinfo.filled & STATION_INFO_SIGNAL_AVG) | ||
130 | data[i] = (u8)sinfo.signal_avg; | ||
131 | i++; | ||
132 | } else { | ||
133 | list_for_each_entry(sta, &local->sta_list, list) { | ||
134 | /* Make sure this station belongs to the proper dev */ | ||
135 | if (sta->sdata->dev != dev) | ||
136 | continue; | ||
137 | |||
138 | sinfo.filled = 0; | ||
139 | sta_set_sinfo(sta, &sinfo); | ||
140 | i = 0; | ||
141 | ADD_STA_STATS(sta); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | do_survey: | ||
146 | i = STA_STATS_LEN - STA_STATS_SURVEY_LEN; | ||
147 | /* Get survey stats for current channel */ | ||
148 | survey.filled = 0; | ||
149 | |||
150 | rcu_read_lock(); | ||
151 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
152 | if (chanctx_conf) | ||
153 | channel = chanctx_conf->def.chan; | ||
154 | else | ||
155 | channel = NULL; | ||
156 | rcu_read_unlock(); | ||
157 | |||
158 | if (channel) { | ||
159 | q = 0; | ||
160 | do { | ||
161 | survey.filled = 0; | ||
162 | if (drv_get_survey(local, q, &survey) != 0) { | ||
163 | survey.filled = 0; | ||
164 | break; | ||
165 | } | ||
166 | q++; | ||
167 | } while (channel != survey.channel); | ||
168 | } | ||
169 | |||
170 | if (survey.filled) | ||
171 | data[i++] = survey.channel->center_freq; | ||
172 | else | ||
173 | data[i++] = 0; | ||
174 | if (survey.filled & SURVEY_INFO_NOISE_DBM) | ||
175 | data[i++] = (u8)survey.noise; | ||
176 | else | ||
177 | data[i++] = -1LL; | ||
178 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME) | ||
179 | data[i++] = survey.channel_time; | ||
180 | else | ||
181 | data[i++] = -1LL; | ||
182 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_BUSY) | ||
183 | data[i++] = survey.channel_time_busy; | ||
184 | else | ||
185 | data[i++] = -1LL; | ||
186 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) | ||
187 | data[i++] = survey.channel_time_ext_busy; | ||
188 | else | ||
189 | data[i++] = -1LL; | ||
190 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_RX) | ||
191 | data[i++] = survey.channel_time_rx; | ||
192 | else | ||
193 | data[i++] = -1LL; | ||
194 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_TX) | ||
195 | data[i++] = survey.channel_time_tx; | ||
196 | else | ||
197 | data[i++] = -1LL; | ||
198 | |||
199 | mutex_unlock(&local->sta_mtx); | ||
200 | |||
201 | if (WARN_ON(i != STA_STATS_LEN)) | ||
202 | return; | ||
203 | |||
204 | drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN])); | ||
205 | } | ||
206 | |||
207 | static void ieee80211_get_strings(struct net_device *dev, u32 sset, u8 *data) | ||
208 | { | ||
209 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
210 | int sz_sta_stats = 0; | ||
211 | |||
212 | if (sset == ETH_SS_STATS) { | ||
213 | sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats); | ||
214 | memcpy(data, ieee80211_gstrings_sta_stats, sz_sta_stats); | ||
215 | } | ||
216 | drv_get_et_strings(sdata, sset, &(data[sz_sta_stats])); | ||
217 | } | ||
218 | |||
219 | static int ieee80211_get_regs_len(struct net_device *dev) | ||
220 | { | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static void ieee80211_get_regs(struct net_device *dev, | ||
225 | struct ethtool_regs *regs, | ||
226 | void *data) | ||
227 | { | ||
228 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
229 | |||
230 | regs->version = wdev->wiphy->hw_version; | ||
231 | regs->len = 0; | ||
232 | } | ||
233 | |||
234 | const struct ethtool_ops ieee80211_ethtool_ops = { | ||
235 | .get_drvinfo = cfg80211_get_drvinfo, | ||
236 | .get_regs_len = ieee80211_get_regs_len, | ||
237 | .get_regs = ieee80211_get_regs, | ||
238 | .get_link = ethtool_op_get_link, | ||
239 | .get_ringparam = ieee80211_get_ringparam, | ||
240 | .set_ringparam = ieee80211_set_ringparam, | ||
241 | .get_strings = ieee80211_get_strings, | ||
242 | .get_ethtool_stats = ieee80211_get_stats, | ||
243 | .get_sset_count = ieee80211_get_sset_count, | ||
244 | }; | ||
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 18ee0a256b1e..713485f9effc 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -143,7 +143,7 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata, | |||
143 | *pos++ = csa_settings->block_tx ? 1 : 0; | 143 | *pos++ = csa_settings->block_tx ? 1 : 0; |
144 | *pos++ = ieee80211_frequency_to_channel( | 144 | *pos++ = ieee80211_frequency_to_channel( |
145 | csa_settings->chandef.chan->center_freq); | 145 | csa_settings->chandef.chan->center_freq); |
146 | sdata->csa_counter_offset_beacon[0] = (pos - presp->head); | 146 | presp->csa_counter_offsets[0] = (pos - presp->head); |
147 | *pos++ = csa_settings->count; | 147 | *pos++ = csa_settings->count; |
148 | } | 148 | } |
149 | 149 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ac9836e0aab3..9e025e1184cc 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -229,16 +229,29 @@ struct ieee80211_rx_data { | |||
229 | u16 tkip_iv16; | 229 | u16 tkip_iv16; |
230 | }; | 230 | }; |
231 | 231 | ||
232 | struct ieee80211_csa_settings { | ||
233 | const u16 *counter_offsets_beacon; | ||
234 | const u16 *counter_offsets_presp; | ||
235 | |||
236 | int n_counter_offsets_beacon; | ||
237 | int n_counter_offsets_presp; | ||
238 | |||
239 | u8 count; | ||
240 | }; | ||
241 | |||
232 | struct beacon_data { | 242 | struct beacon_data { |
233 | u8 *head, *tail; | 243 | u8 *head, *tail; |
234 | int head_len, tail_len; | 244 | int head_len, tail_len; |
235 | struct ieee80211_meshconf_ie *meshconf; | 245 | struct ieee80211_meshconf_ie *meshconf; |
246 | u16 csa_counter_offsets[IEEE80211_MAX_CSA_COUNTERS_NUM]; | ||
247 | u8 csa_current_counter; | ||
236 | struct rcu_head rcu_head; | 248 | struct rcu_head rcu_head; |
237 | }; | 249 | }; |
238 | 250 | ||
239 | struct probe_resp { | 251 | struct probe_resp { |
240 | struct rcu_head rcu_head; | 252 | struct rcu_head rcu_head; |
241 | int len; | 253 | int len; |
254 | u16 csa_counter_offsets[IEEE80211_MAX_CSA_COUNTERS_NUM]; | ||
242 | u8 data[0]; | 255 | u8 data[0]; |
243 | }; | 256 | }; |
244 | 257 | ||
@@ -688,6 +701,24 @@ enum ieee80211_chanctx_mode { | |||
688 | IEEE80211_CHANCTX_EXCLUSIVE | 701 | IEEE80211_CHANCTX_EXCLUSIVE |
689 | }; | 702 | }; |
690 | 703 | ||
704 | /** | ||
705 | * enum ieee80211_chanctx_replace_state - channel context replacement state | ||
706 | * | ||
707 | * This is used for channel context in-place reservations that require channel | ||
708 | * context switch/swap. | ||
709 | * | ||
710 | * @IEEE80211_CHANCTX_REPLACE_NONE: no replacement is taking place | ||
711 | * @IEEE80211_CHANCTX_WILL_BE_REPLACED: this channel context will be replaced | ||
712 | * by a (not yet registered) channel context pointed by %replace_ctx. | ||
713 | * @IEEE80211_CHANCTX_REPLACES_OTHER: this (not yet registered) channel context | ||
714 | * replaces an existing channel context pointed to by %replace_ctx. | ||
715 | */ | ||
716 | enum ieee80211_chanctx_replace_state { | ||
717 | IEEE80211_CHANCTX_REPLACE_NONE, | ||
718 | IEEE80211_CHANCTX_WILL_BE_REPLACED, | ||
719 | IEEE80211_CHANCTX_REPLACES_OTHER, | ||
720 | }; | ||
721 | |||
691 | struct ieee80211_chanctx { | 722 | struct ieee80211_chanctx { |
692 | struct list_head list; | 723 | struct list_head list; |
693 | struct rcu_head rcu_head; | 724 | struct rcu_head rcu_head; |
@@ -695,6 +726,9 @@ struct ieee80211_chanctx { | |||
695 | struct list_head assigned_vifs; | 726 | struct list_head assigned_vifs; |
696 | struct list_head reserved_vifs; | 727 | struct list_head reserved_vifs; |
697 | 728 | ||
729 | enum ieee80211_chanctx_replace_state replace_state; | ||
730 | struct ieee80211_chanctx *replace_ctx; | ||
731 | |||
698 | enum ieee80211_chanctx_mode mode; | 732 | enum ieee80211_chanctx_mode mode; |
699 | bool driver_present; | 733 | bool driver_present; |
700 | 734 | ||
@@ -754,9 +788,6 @@ struct ieee80211_sub_if_data { | |||
754 | struct mac80211_qos_map __rcu *qos_map; | 788 | struct mac80211_qos_map __rcu *qos_map; |
755 | 789 | ||
756 | struct work_struct csa_finalize_work; | 790 | struct work_struct csa_finalize_work; |
757 | u16 csa_counter_offset_beacon[IEEE80211_MAX_CSA_COUNTERS_NUM]; | ||
758 | u16 csa_counter_offset_presp[IEEE80211_MAX_CSA_COUNTERS_NUM]; | ||
759 | bool csa_radar_required; | ||
760 | bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */ | 791 | bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */ |
761 | struct cfg80211_chan_def csa_chandef; | 792 | struct cfg80211_chan_def csa_chandef; |
762 | 793 | ||
@@ -767,7 +798,7 @@ struct ieee80211_sub_if_data { | |||
767 | struct ieee80211_chanctx *reserved_chanctx; | 798 | struct ieee80211_chanctx *reserved_chanctx; |
768 | struct cfg80211_chan_def reserved_chandef; | 799 | struct cfg80211_chan_def reserved_chandef; |
769 | bool reserved_radar_required; | 800 | bool reserved_radar_required; |
770 | u8 csa_current_counter; | 801 | bool reserved_ready; |
771 | 802 | ||
772 | /* used to reconfigure hardware SM PS */ | 803 | /* used to reconfigure hardware SM PS */ |
773 | struct work_struct recalc_smps; | 804 | struct work_struct recalc_smps; |
@@ -784,6 +815,9 @@ struct ieee80211_sub_if_data { | |||
784 | bool radar_required; | 815 | bool radar_required; |
785 | struct delayed_work dfs_cac_timer_work; | 816 | struct delayed_work dfs_cac_timer_work; |
786 | 817 | ||
818 | u8 tdls_peer[ETH_ALEN] __aligned(2); | ||
819 | struct delayed_work tdls_peer_del_work; | ||
820 | |||
787 | /* | 821 | /* |
788 | * AP this belongs to: self in AP mode and | 822 | * AP this belongs to: self in AP mode and |
789 | * corresponding AP in VLAN mode, NULL for | 823 | * corresponding AP in VLAN mode, NULL for |
@@ -912,6 +946,9 @@ enum queue_stop_reason { | |||
912 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD, | 946 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD, |
913 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, | 947 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, |
914 | IEEE80211_QUEUE_STOP_REASON_FLUSH, | 948 | IEEE80211_QUEUE_STOP_REASON_FLUSH, |
949 | IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN, | ||
950 | |||
951 | IEEE80211_QUEUE_STOP_REASONS, | ||
915 | }; | 952 | }; |
916 | 953 | ||
917 | #ifdef CONFIG_MAC80211_LEDS | 954 | #ifdef CONFIG_MAC80211_LEDS |
@@ -1008,6 +1045,7 @@ struct ieee80211_local { | |||
1008 | struct workqueue_struct *workqueue; | 1045 | struct workqueue_struct *workqueue; |
1009 | 1046 | ||
1010 | unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES]; | 1047 | unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES]; |
1048 | int q_stop_reasons[IEEE80211_MAX_QUEUES][IEEE80211_QUEUE_STOP_REASONS]; | ||
1011 | /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */ | 1049 | /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */ |
1012 | spinlock_t queue_stop_reason_lock; | 1050 | spinlock_t queue_stop_reason_lock; |
1013 | 1051 | ||
@@ -1135,7 +1173,8 @@ struct ieee80211_local { | |||
1135 | unsigned long scanning; | 1173 | unsigned long scanning; |
1136 | struct cfg80211_ssid scan_ssid; | 1174 | struct cfg80211_ssid scan_ssid; |
1137 | struct cfg80211_scan_request *int_scan_req; | 1175 | struct cfg80211_scan_request *int_scan_req; |
1138 | struct cfg80211_scan_request *scan_req, *hw_scan_req; | 1176 | struct cfg80211_scan_request *scan_req; |
1177 | struct ieee80211_scan_request *hw_scan_req; | ||
1139 | struct cfg80211_chan_def scan_chandef; | 1178 | struct cfg80211_chan_def scan_chandef; |
1140 | enum ieee80211_band hw_scan_band; | 1179 | enum ieee80211_band hw_scan_band; |
1141 | int scan_channel_idx; | 1180 | int scan_channel_idx; |
@@ -1476,7 +1515,6 @@ void ieee80211_sw_roc_work(struct work_struct *work); | |||
1476 | void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc); | 1515 | void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc); |
1477 | 1516 | ||
1478 | /* channel switch handling */ | 1517 | /* channel switch handling */ |
1479 | bool ieee80211_csa_needs_block_tx(struct ieee80211_local *local); | ||
1480 | void ieee80211_csa_finalize_work(struct work_struct *work); | 1518 | void ieee80211_csa_finalize_work(struct work_struct *work); |
1481 | int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | 1519 | int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, |
1482 | struct cfg80211_csa_settings *params); | 1520 | struct cfg80211_csa_settings *params); |
@@ -1705,14 +1743,24 @@ void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, | |||
1705 | 1743 | ||
1706 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | 1744 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, |
1707 | unsigned long queues, | 1745 | unsigned long queues, |
1708 | enum queue_stop_reason reason); | 1746 | enum queue_stop_reason reason, |
1747 | bool refcounted); | ||
1748 | void ieee80211_stop_vif_queues(struct ieee80211_local *local, | ||
1749 | struct ieee80211_sub_if_data *sdata, | ||
1750 | enum queue_stop_reason reason); | ||
1751 | void ieee80211_wake_vif_queues(struct ieee80211_local *local, | ||
1752 | struct ieee80211_sub_if_data *sdata, | ||
1753 | enum queue_stop_reason reason); | ||
1709 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | 1754 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, |
1710 | unsigned long queues, | 1755 | unsigned long queues, |
1711 | enum queue_stop_reason reason); | 1756 | enum queue_stop_reason reason, |
1757 | bool refcounted); | ||
1712 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, | 1758 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, |
1713 | enum queue_stop_reason reason); | 1759 | enum queue_stop_reason reason, |
1760 | bool refcounted); | ||
1714 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, | 1761 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, |
1715 | enum queue_stop_reason reason); | 1762 | enum queue_stop_reason reason, |
1763 | bool refcounted); | ||
1716 | void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue); | 1764 | void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue); |
1717 | void ieee80211_add_pending_skb(struct ieee80211_local *local, | 1765 | void ieee80211_add_pending_skb(struct ieee80211_local *local, |
1718 | struct sk_buff *skb); | 1766 | struct sk_buff *skb); |
@@ -1730,8 +1778,10 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1730 | const u8 *bssid, u16 stype, u16 reason, | 1778 | const u8 *bssid, u16 stype, u16 reason, |
1731 | bool send_frame, u8 *frame_buf); | 1779 | bool send_frame, u8 *frame_buf); |
1732 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | 1780 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, |
1733 | size_t buffer_len, const u8 *ie, size_t ie_len, | 1781 | size_t buffer_len, |
1734 | enum ieee80211_band band, u32 rate_mask, | 1782 | struct ieee80211_scan_ies *ie_desc, |
1783 | const u8 *ie, size_t ie_len, | ||
1784 | u8 bands_used, u32 *rate_masks, | ||
1735 | struct cfg80211_chan_def *chandef); | 1785 | struct cfg80211_chan_def *chandef); |
1736 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | 1786 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, |
1737 | u8 *dst, u32 ratemask, | 1787 | u8 *dst, u32 ratemask, |
@@ -1791,18 +1841,14 @@ ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, | |||
1791 | enum ieee80211_chanctx_mode mode, | 1841 | enum ieee80211_chanctx_mode mode, |
1792 | bool radar_required); | 1842 | bool radar_required); |
1793 | int __must_check | 1843 | int __must_check |
1794 | ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata, | 1844 | ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata); |
1795 | u32 *changed); | ||
1796 | int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata); | 1845 | int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata); |
1846 | int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local); | ||
1797 | 1847 | ||
1798 | int __must_check | 1848 | int __must_check |
1799 | ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | 1849 | ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, |
1800 | const struct cfg80211_chan_def *chandef, | 1850 | const struct cfg80211_chan_def *chandef, |
1801 | u32 *changed); | 1851 | u32 *changed); |
1802 | /* NOTE: only use ieee80211_vif_change_channel() for channel switch */ | ||
1803 | int __must_check | ||
1804 | ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, | ||
1805 | u32 *changed); | ||
1806 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); | 1852 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); |
1807 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); | 1853 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); |
1808 | void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, | 1854 | void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, |
@@ -1842,11 +1888,14 @@ int ieee80211_max_num_channels(struct ieee80211_local *local); | |||
1842 | int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | 1888 | int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, |
1843 | const u8 *peer, u8 action_code, u8 dialog_token, | 1889 | const u8 *peer, u8 action_code, u8 dialog_token, |
1844 | u16 status_code, u32 peer_capability, | 1890 | u16 status_code, u32 peer_capability, |
1845 | const u8 *extra_ies, size_t extra_ies_len); | 1891 | bool initiator, const u8 *extra_ies, |
1892 | size_t extra_ies_len); | ||
1846 | int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | 1893 | int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, |
1847 | const u8 *peer, enum nl80211_tdls_operation oper); | 1894 | const u8 *peer, enum nl80211_tdls_operation oper); |
1848 | 1895 | ||
1849 | 1896 | ||
1897 | extern const struct ethtool_ops ieee80211_ethtool_ops; | ||
1898 | |||
1850 | #ifdef CONFIG_MAC80211_NOINLINE | 1899 | #ifdef CONFIG_MAC80211_NOINLINE |
1851 | #define debug_noinline noinline | 1900 | #define debug_noinline noinline |
1852 | #else | 1901 | #else |
@@ -1854,3 +1903,4 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | |||
1854 | #endif | 1903 | #endif |
1855 | 1904 | ||
1856 | #endif /* IEEE80211_I_H */ | 1905 | #endif /* IEEE80211_I_H */ |
1906 | void ieee80211_tdls_peer_del_work(struct work_struct *wk); | ||
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 388b863e821c..bbf51b2f0651 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -841,10 +841,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
841 | sdata_lock(sdata); | 841 | sdata_lock(sdata); |
842 | mutex_lock(&local->mtx); | 842 | mutex_lock(&local->mtx); |
843 | sdata->vif.csa_active = false; | 843 | sdata->vif.csa_active = false; |
844 | if (!ieee80211_csa_needs_block_tx(local)) | 844 | if (sdata->csa_block_tx) { |
845 | ieee80211_wake_queues_by_reason(&local->hw, | 845 | ieee80211_wake_vif_queues(local, sdata, |
846 | IEEE80211_MAX_QUEUE_MAP, | 846 | IEEE80211_QUEUE_STOP_REASON_CSA); |
847 | IEEE80211_QUEUE_STOP_REASON_CSA); | 847 | sdata->csa_block_tx = false; |
848 | } | ||
848 | mutex_unlock(&local->mtx); | 849 | mutex_unlock(&local->mtx); |
849 | sdata_unlock(sdata); | 850 | sdata_unlock(sdata); |
850 | 851 | ||
@@ -1671,6 +1672,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1671 | ieee80211_dfs_cac_timer_work); | 1672 | ieee80211_dfs_cac_timer_work); |
1672 | INIT_DELAYED_WORK(&sdata->dec_tailroom_needed_wk, | 1673 | INIT_DELAYED_WORK(&sdata->dec_tailroom_needed_wk, |
1673 | ieee80211_delayed_tailroom_dec); | 1674 | ieee80211_delayed_tailroom_dec); |
1675 | INIT_DELAYED_WORK(&sdata->tdls_peer_del_work, | ||
1676 | ieee80211_tdls_peer_del_work); | ||
1674 | 1677 | ||
1675 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | 1678 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { |
1676 | struct ieee80211_supported_band *sband; | 1679 | struct ieee80211_supported_band *sband; |
@@ -1705,6 +1708,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1705 | 1708 | ||
1706 | ndev->features |= local->hw.netdev_features; | 1709 | ndev->features |= local->hw.netdev_features; |
1707 | 1710 | ||
1711 | netdev_set_default_ethtool_ops(ndev, &ieee80211_ethtool_ops); | ||
1712 | |||
1708 | ret = register_netdevice(ndev); | 1713 | ret = register_netdevice(ndev); |
1709 | if (ret) { | 1714 | if (ret) { |
1710 | free_netdev(ndev); | 1715 | free_netdev(ndev); |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d17c26d6e369..e0ab4320a078 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -272,7 +272,8 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw) | |||
272 | 272 | ||
273 | /* use this reason, ieee80211_reconfig will unblock it */ | 273 | /* use this reason, ieee80211_reconfig will unblock it */ |
274 | ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, | 274 | ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, |
275 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 275 | IEEE80211_QUEUE_STOP_REASON_SUSPEND, |
276 | false); | ||
276 | 277 | ||
277 | /* | 278 | /* |
278 | * Stop all Rx during the reconfig. We don't want state changes | 279 | * Stop all Rx during the reconfig. We don't want state changes |
@@ -1187,18 +1188,12 @@ static int __init ieee80211_init(void) | |||
1187 | if (ret) | 1188 | if (ret) |
1188 | goto err_minstrel; | 1189 | goto err_minstrel; |
1189 | 1190 | ||
1190 | ret = rc80211_pid_init(); | ||
1191 | if (ret) | ||
1192 | goto err_pid; | ||
1193 | |||
1194 | ret = ieee80211_iface_init(); | 1191 | ret = ieee80211_iface_init(); |
1195 | if (ret) | 1192 | if (ret) |
1196 | goto err_netdev; | 1193 | goto err_netdev; |
1197 | 1194 | ||
1198 | return 0; | 1195 | return 0; |
1199 | err_netdev: | 1196 | err_netdev: |
1200 | rc80211_pid_exit(); | ||
1201 | err_pid: | ||
1202 | rc80211_minstrel_ht_exit(); | 1197 | rc80211_minstrel_ht_exit(); |
1203 | err_minstrel: | 1198 | err_minstrel: |
1204 | rc80211_minstrel_exit(); | 1199 | rc80211_minstrel_exit(); |
@@ -1208,7 +1203,6 @@ static int __init ieee80211_init(void) | |||
1208 | 1203 | ||
1209 | static void __exit ieee80211_exit(void) | 1204 | static void __exit ieee80211_exit(void) |
1210 | { | 1205 | { |
1211 | rc80211_pid_exit(); | ||
1212 | rc80211_minstrel_ht_exit(); | 1206 | rc80211_minstrel_ht_exit(); |
1213 | rc80211_minstrel_exit(); | 1207 | rc80211_minstrel_exit(); |
1214 | 1208 | ||
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 6495a3f0428d..e9f99c1e3fad 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -679,7 +679,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | |||
679 | *pos++ = 0x0; | 679 | *pos++ = 0x0; |
680 | *pos++ = ieee80211_frequency_to_channel( | 680 | *pos++ = ieee80211_frequency_to_channel( |
681 | csa->settings.chandef.chan->center_freq); | 681 | csa->settings.chandef.chan->center_freq); |
682 | sdata->csa_counter_offset_beacon[0] = hdr_len + 6; | 682 | bcn->csa_counter_offsets[0] = hdr_len + 6; |
683 | *pos++ = csa->settings.count; | 683 | *pos++ = csa->settings.count; |
684 | *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; | 684 | *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; |
685 | *pos++ = 6; | 685 | *pos++ = 6; |
@@ -1122,7 +1122,7 @@ static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata, | |||
1122 | mgmt_fwd = (struct ieee80211_mgmt *) skb_put(skb, len); | 1122 | mgmt_fwd = (struct ieee80211_mgmt *) skb_put(skb, len); |
1123 | 1123 | ||
1124 | /* offset_ttl is based on whether the secondary channel | 1124 | /* offset_ttl is based on whether the secondary channel |
1125 | * offset is available or not. Substract 1 from the mesh TTL | 1125 | * offset is available or not. Subtract 1 from the mesh TTL |
1126 | * and disable the initiator flag before forwarding. | 1126 | * and disable the initiator flag before forwarding. |
1127 | */ | 1127 | */ |
1128 | offset_ttl = (len < 42) ? 7 : 10; | 1128 | offset_ttl = (len < 42) ? 7 : 10; |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index e8f60aa2e848..63b874101b27 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -551,11 +551,30 @@ static void mesh_plink_timer(unsigned long data) | |||
551 | return; | 551 | return; |
552 | 552 | ||
553 | spin_lock_bh(&sta->lock); | 553 | spin_lock_bh(&sta->lock); |
554 | if (sta->ignore_plink_timer) { | 554 | |
555 | sta->ignore_plink_timer = false; | 555 | /* If a timer fires just before a state transition on another CPU, |
556 | * we may have already extended the timeout and changed state by the | ||
557 | * time we've acquired the lock and arrived here. In that case, | ||
558 | * skip this timer and wait for the new one. | ||
559 | */ | ||
560 | if (time_before(jiffies, sta->plink_timer.expires)) { | ||
561 | mpl_dbg(sta->sdata, | ||
562 | "Ignoring timer for %pM in state %s (timer adjusted)", | ||
563 | sta->sta.addr, mplstates[sta->plink_state]); | ||
556 | spin_unlock_bh(&sta->lock); | 564 | spin_unlock_bh(&sta->lock); |
557 | return; | 565 | return; |
558 | } | 566 | } |
567 | |||
568 | /* del_timer() and handler may race when entering these states */ | ||
569 | if (sta->plink_state == NL80211_PLINK_LISTEN || | ||
570 | sta->plink_state == NL80211_PLINK_ESTAB) { | ||
571 | mpl_dbg(sta->sdata, | ||
572 | "Ignoring timer for %pM in state %s (timer deleted)", | ||
573 | sta->sta.addr, mplstates[sta->plink_state]); | ||
574 | spin_unlock_bh(&sta->lock); | ||
575 | return; | ||
576 | } | ||
577 | |||
559 | mpl_dbg(sta->sdata, | 578 | mpl_dbg(sta->sdata, |
560 | "Mesh plink timer for %pM fired on state %s\n", | 579 | "Mesh plink timer for %pM fired on state %s\n", |
561 | sta->sta.addr, mplstates[sta->plink_state]); | 580 | sta->sta.addr, mplstates[sta->plink_state]); |
@@ -773,9 +792,7 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, | |||
773 | break; | 792 | break; |
774 | case CNF_ACPT: | 793 | case CNF_ACPT: |
775 | sta->plink_state = NL80211_PLINK_CNF_RCVD; | 794 | sta->plink_state = NL80211_PLINK_CNF_RCVD; |
776 | if (!mod_plink_timer(sta, | 795 | mod_plink_timer(sta, mshcfg->dot11MeshConfirmTimeout); |
777 | mshcfg->dot11MeshConfirmTimeout)) | ||
778 | sta->ignore_plink_timer = true; | ||
779 | break; | 796 | break; |
780 | default: | 797 | default: |
781 | break; | 798 | break; |
@@ -834,8 +851,7 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, | |||
834 | case NL80211_PLINK_HOLDING: | 851 | case NL80211_PLINK_HOLDING: |
835 | switch (event) { | 852 | switch (event) { |
836 | case CLS_ACPT: | 853 | case CLS_ACPT: |
837 | if (del_timer(&sta->plink_timer)) | 854 | del_timer(&sta->plink_timer); |
838 | sta->ignore_plink_timer = 1; | ||
839 | mesh_plink_fsm_restart(sta); | 855 | mesh_plink_fsm_restart(sta); |
840 | break; | 856 | break; |
841 | case OPN_ACPT: | 857 | case OPN_ACPT: |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3345401be1b3..931330bbe00c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -940,51 +940,70 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
940 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); | 940 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); |
941 | struct ieee80211_local *local = sdata->local; | 941 | struct ieee80211_local *local = sdata->local; |
942 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 942 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
943 | u32 changed = 0; | ||
944 | int ret; | 943 | int ret; |
945 | 944 | ||
946 | if (!ieee80211_sdata_running(sdata)) | 945 | if (!ieee80211_sdata_running(sdata)) |
947 | return; | 946 | return; |
948 | 947 | ||
949 | sdata_lock(sdata); | 948 | sdata_lock(sdata); |
949 | mutex_lock(&local->mtx); | ||
950 | mutex_lock(&local->chanctx_mtx); | ||
951 | |||
950 | if (!ifmgd->associated) | 952 | if (!ifmgd->associated) |
951 | goto out; | 953 | goto out; |
952 | 954 | ||
953 | mutex_lock(&local->mtx); | 955 | if (!sdata->vif.csa_active) |
954 | ret = ieee80211_vif_change_channel(sdata, &changed); | 956 | goto out; |
955 | mutex_unlock(&local->mtx); | 957 | |
956 | if (ret) { | 958 | /* |
959 | * using reservation isn't immediate as it may be deferred until later | ||
960 | * with multi-vif. once reservation is complete it will re-schedule the | ||
961 | * work with no reserved_chanctx so verify chandef to check if it | ||
962 | * completed successfully | ||
963 | */ | ||
964 | |||
965 | if (sdata->reserved_chanctx) { | ||
966 | /* | ||
967 | * with multi-vif csa driver may call ieee80211_csa_finish() | ||
968 | * many times while waiting for other interfaces to use their | ||
969 | * reservations | ||
970 | */ | ||
971 | if (sdata->reserved_ready) | ||
972 | goto out; | ||
973 | |||
974 | ret = ieee80211_vif_use_reserved_context(sdata); | ||
975 | if (ret) { | ||
976 | sdata_info(sdata, | ||
977 | "failed to use reserved channel context, disconnecting (err=%d)\n", | ||
978 | ret); | ||
979 | ieee80211_queue_work(&sdata->local->hw, | ||
980 | &ifmgd->csa_connection_drop_work); | ||
981 | goto out; | ||
982 | } | ||
983 | |||
984 | goto out; | ||
985 | } | ||
986 | |||
987 | if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef, | ||
988 | &sdata->csa_chandef)) { | ||
957 | sdata_info(sdata, | 989 | sdata_info(sdata, |
958 | "vif channel switch failed, disconnecting\n"); | 990 | "failed to finalize channel switch, disconnecting\n"); |
959 | ieee80211_queue_work(&sdata->local->hw, | 991 | ieee80211_queue_work(&sdata->local->hw, |
960 | &ifmgd->csa_connection_drop_work); | 992 | &ifmgd->csa_connection_drop_work); |
961 | goto out; | 993 | goto out; |
962 | } | 994 | } |
963 | 995 | ||
964 | if (!local->use_chanctx) { | ||
965 | local->_oper_chandef = sdata->csa_chandef; | ||
966 | /* Call "hw_config" only if doing sw channel switch. | ||
967 | * Otherwise update the channel directly | ||
968 | */ | ||
969 | if (!local->ops->channel_switch) | ||
970 | ieee80211_hw_config(local, 0); | ||
971 | else | ||
972 | local->hw.conf.chandef = local->_oper_chandef; | ||
973 | } | ||
974 | |||
975 | /* XXX: shouldn't really modify cfg80211-owned data! */ | 996 | /* XXX: shouldn't really modify cfg80211-owned data! */ |
976 | ifmgd->associated->channel = sdata->csa_chandef.chan; | 997 | ifmgd->associated->channel = sdata->csa_chandef.chan; |
977 | 998 | ||
978 | ieee80211_bss_info_change_notify(sdata, changed); | ||
979 | |||
980 | mutex_lock(&local->mtx); | ||
981 | sdata->vif.csa_active = false; | 999 | sdata->vif.csa_active = false; |
1000 | |||
982 | /* XXX: wait for a beacon first? */ | 1001 | /* XXX: wait for a beacon first? */ |
983 | if (!ieee80211_csa_needs_block_tx(local)) | 1002 | if (sdata->csa_block_tx) { |
984 | ieee80211_wake_queues_by_reason(&local->hw, | 1003 | ieee80211_wake_vif_queues(local, sdata, |
985 | IEEE80211_MAX_QUEUE_MAP, | 1004 | IEEE80211_QUEUE_STOP_REASON_CSA); |
986 | IEEE80211_QUEUE_STOP_REASON_CSA); | 1005 | sdata->csa_block_tx = false; |
987 | mutex_unlock(&local->mtx); | 1006 | } |
988 | 1007 | ||
989 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | 1008 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; |
990 | 1009 | ||
@@ -992,6 +1011,8 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
992 | ieee80211_sta_reset_conn_monitor(sdata); | 1011 | ieee80211_sta_reset_conn_monitor(sdata); |
993 | 1012 | ||
994 | out: | 1013 | out: |
1014 | mutex_unlock(&local->chanctx_mtx); | ||
1015 | mutex_unlock(&local->mtx); | ||
995 | sdata_unlock(sdata); | 1016 | sdata_unlock(sdata); |
996 | } | 1017 | } |
997 | 1018 | ||
@@ -1028,6 +1049,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1028 | struct ieee80211_local *local = sdata->local; | 1049 | struct ieee80211_local *local = sdata->local; |
1029 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1050 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1030 | struct cfg80211_bss *cbss = ifmgd->associated; | 1051 | struct cfg80211_bss *cbss = ifmgd->associated; |
1052 | struct ieee80211_chanctx_conf *conf; | ||
1031 | struct ieee80211_chanctx *chanctx; | 1053 | struct ieee80211_chanctx *chanctx; |
1032 | enum ieee80211_band current_band; | 1054 | enum ieee80211_band current_band; |
1033 | struct ieee80211_csa_ie csa_ie; | 1055 | struct ieee80211_csa_ie csa_ie; |
@@ -1071,7 +1093,22 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1071 | 1093 | ||
1072 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | 1094 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; |
1073 | 1095 | ||
1096 | mutex_lock(&local->mtx); | ||
1074 | mutex_lock(&local->chanctx_mtx); | 1097 | mutex_lock(&local->chanctx_mtx); |
1098 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
1099 | lockdep_is_held(&local->chanctx_mtx)); | ||
1100 | if (!conf) { | ||
1101 | sdata_info(sdata, | ||
1102 | "no channel context assigned to vif?, disconnecting\n"); | ||
1103 | ieee80211_queue_work(&local->hw, | ||
1104 | &ifmgd->csa_connection_drop_work); | ||
1105 | mutex_unlock(&local->chanctx_mtx); | ||
1106 | mutex_unlock(&local->mtx); | ||
1107 | return; | ||
1108 | } | ||
1109 | |||
1110 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); | ||
1111 | |||
1075 | if (local->use_chanctx) { | 1112 | if (local->use_chanctx) { |
1076 | u32 num_chanctx = 0; | 1113 | u32 num_chanctx = 0; |
1077 | list_for_each_entry(chanctx, &local->chanctx_list, list) | 1114 | list_for_each_entry(chanctx, &local->chanctx_list, list) |
@@ -1084,38 +1121,32 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1084 | ieee80211_queue_work(&local->hw, | 1121 | ieee80211_queue_work(&local->hw, |
1085 | &ifmgd->csa_connection_drop_work); | 1122 | &ifmgd->csa_connection_drop_work); |
1086 | mutex_unlock(&local->chanctx_mtx); | 1123 | mutex_unlock(&local->chanctx_mtx); |
1124 | mutex_unlock(&local->mtx); | ||
1087 | return; | 1125 | return; |
1088 | } | 1126 | } |
1089 | } | 1127 | } |
1090 | 1128 | ||
1091 | if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) { | 1129 | res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef, |
1092 | ieee80211_queue_work(&local->hw, | 1130 | chanctx->mode, false); |
1093 | &ifmgd->csa_connection_drop_work); | 1131 | if (res) { |
1094 | mutex_unlock(&local->chanctx_mtx); | ||
1095 | return; | ||
1096 | } | ||
1097 | chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf), | ||
1098 | struct ieee80211_chanctx, conf); | ||
1099 | if (ieee80211_chanctx_refcount(local, chanctx) > 1) { | ||
1100 | sdata_info(sdata, | 1132 | sdata_info(sdata, |
1101 | "channel switch with multiple interfaces on the same channel, disconnecting\n"); | 1133 | "failed to reserve channel context for channel switch, disconnecting (err=%d)\n", |
1134 | res); | ||
1102 | ieee80211_queue_work(&local->hw, | 1135 | ieee80211_queue_work(&local->hw, |
1103 | &ifmgd->csa_connection_drop_work); | 1136 | &ifmgd->csa_connection_drop_work); |
1104 | mutex_unlock(&local->chanctx_mtx); | 1137 | mutex_unlock(&local->chanctx_mtx); |
1138 | mutex_unlock(&local->mtx); | ||
1105 | return; | 1139 | return; |
1106 | } | 1140 | } |
1107 | mutex_unlock(&local->chanctx_mtx); | 1141 | mutex_unlock(&local->chanctx_mtx); |
1108 | 1142 | ||
1109 | sdata->csa_chandef = csa_ie.chandef; | ||
1110 | |||
1111 | mutex_lock(&local->mtx); | ||
1112 | sdata->vif.csa_active = true; | 1143 | sdata->vif.csa_active = true; |
1144 | sdata->csa_chandef = csa_ie.chandef; | ||
1113 | sdata->csa_block_tx = csa_ie.mode; | 1145 | sdata->csa_block_tx = csa_ie.mode; |
1114 | 1146 | ||
1115 | if (sdata->csa_block_tx) | 1147 | if (sdata->csa_block_tx) |
1116 | ieee80211_stop_queues_by_reason(&local->hw, | 1148 | ieee80211_stop_vif_queues(local, sdata, |
1117 | IEEE80211_MAX_QUEUE_MAP, | 1149 | IEEE80211_QUEUE_STOP_REASON_CSA); |
1118 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
1119 | mutex_unlock(&local->mtx); | 1150 | mutex_unlock(&local->mtx); |
1120 | 1151 | ||
1121 | if (local->ops->channel_switch) { | 1152 | if (local->ops->channel_switch) { |
@@ -1385,7 +1416,8 @@ void ieee80211_dynamic_ps_disable_work(struct work_struct *work) | |||
1385 | 1416 | ||
1386 | ieee80211_wake_queues_by_reason(&local->hw, | 1417 | ieee80211_wake_queues_by_reason(&local->hw, |
1387 | IEEE80211_MAX_QUEUE_MAP, | 1418 | IEEE80211_MAX_QUEUE_MAP, |
1388 | IEEE80211_QUEUE_STOP_REASON_PS); | 1419 | IEEE80211_QUEUE_STOP_REASON_PS, |
1420 | false); | ||
1389 | } | 1421 | } |
1390 | 1422 | ||
1391 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | 1423 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work) |
@@ -1830,10 +1862,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1830 | ieee80211_vif_release_channel(sdata); | 1862 | ieee80211_vif_release_channel(sdata); |
1831 | 1863 | ||
1832 | sdata->vif.csa_active = false; | 1864 | sdata->vif.csa_active = false; |
1833 | if (!ieee80211_csa_needs_block_tx(local)) | 1865 | if (sdata->csa_block_tx) { |
1834 | ieee80211_wake_queues_by_reason(&local->hw, | 1866 | ieee80211_wake_vif_queues(local, sdata, |
1835 | IEEE80211_MAX_QUEUE_MAP, | 1867 | IEEE80211_QUEUE_STOP_REASON_CSA); |
1836 | IEEE80211_QUEUE_STOP_REASON_CSA); | 1868 | sdata->csa_block_tx = false; |
1869 | } | ||
1837 | mutex_unlock(&local->mtx); | 1870 | mutex_unlock(&local->mtx); |
1838 | 1871 | ||
1839 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; | 1872 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; |
@@ -2079,10 +2112,11 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | |||
2079 | 2112 | ||
2080 | mutex_lock(&local->mtx); | 2113 | mutex_lock(&local->mtx); |
2081 | sdata->vif.csa_active = false; | 2114 | sdata->vif.csa_active = false; |
2082 | if (!ieee80211_csa_needs_block_tx(local)) | 2115 | if (sdata->csa_block_tx) { |
2083 | ieee80211_wake_queues_by_reason(&local->hw, | 2116 | ieee80211_wake_vif_queues(local, sdata, |
2084 | IEEE80211_MAX_QUEUE_MAP, | 2117 | IEEE80211_QUEUE_STOP_REASON_CSA); |
2085 | IEEE80211_QUEUE_STOP_REASON_CSA); | 2118 | sdata->csa_block_tx = false; |
2119 | } | ||
2086 | mutex_unlock(&local->mtx); | 2120 | mutex_unlock(&local->mtx); |
2087 | 2121 | ||
2088 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | 2122 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, |
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 7a17decd27f9..ff20b2ebdb30 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
@@ -119,7 +119,8 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local) | |||
119 | * before sending nullfunc to enable powersave at the AP. | 119 | * before sending nullfunc to enable powersave at the AP. |
120 | */ | 120 | */ |
121 | ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, | 121 | ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, |
122 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL); | 122 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, |
123 | false); | ||
123 | ieee80211_flush_queues(local, NULL); | 124 | ieee80211_flush_queues(local, NULL); |
124 | 125 | ||
125 | mutex_lock(&local->iflist_mtx); | 126 | mutex_lock(&local->iflist_mtx); |
@@ -182,7 +183,8 @@ void ieee80211_offchannel_return(struct ieee80211_local *local) | |||
182 | mutex_unlock(&local->iflist_mtx); | 183 | mutex_unlock(&local->iflist_mtx); |
183 | 184 | ||
184 | ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, | 185 | ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, |
185 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL); | 186 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, |
187 | false); | ||
186 | } | 188 | } |
187 | 189 | ||
188 | void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc) | 190 | void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc) |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index d478b880a0af..4c5192e0d66c 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -35,7 +35,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
35 | 35 | ||
36 | ieee80211_stop_queues_by_reason(hw, | 36 | ieee80211_stop_queues_by_reason(hw, |
37 | IEEE80211_MAX_QUEUE_MAP, | 37 | IEEE80211_MAX_QUEUE_MAP, |
38 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 38 | IEEE80211_QUEUE_STOP_REASON_SUSPEND, |
39 | false); | ||
39 | 40 | ||
40 | /* flush out all packets */ | 41 | /* flush out all packets */ |
41 | synchronize_net(); | 42 | synchronize_net(); |
@@ -74,7 +75,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
74 | } | 75 | } |
75 | ieee80211_wake_queues_by_reason(hw, | 76 | ieee80211_wake_queues_by_reason(hw, |
76 | IEEE80211_MAX_QUEUE_MAP, | 77 | IEEE80211_MAX_QUEUE_MAP, |
77 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 78 | IEEE80211_QUEUE_STOP_REASON_SUSPEND, |
79 | false); | ||
78 | return err; | 80 | return err; |
79 | } else if (err > 0) { | 81 | } else if (err > 0) { |
80 | WARN_ON(err != 1); | 82 | WARN_ON(err != 1); |
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 9aa2a1190a86..18babe302832 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
@@ -143,19 +143,6 @@ void rate_control_deinitialize(struct ieee80211_local *local); | |||
143 | 143 | ||
144 | 144 | ||
145 | /* Rate control algorithms */ | 145 | /* Rate control algorithms */ |
146 | #ifdef CONFIG_MAC80211_RC_PID | ||
147 | int rc80211_pid_init(void); | ||
148 | void rc80211_pid_exit(void); | ||
149 | #else | ||
150 | static inline int rc80211_pid_init(void) | ||
151 | { | ||
152 | return 0; | ||
153 | } | ||
154 | static inline void rc80211_pid_exit(void) | ||
155 | { | ||
156 | } | ||
157 | #endif | ||
158 | |||
159 | #ifdef CONFIG_MAC80211_RC_MINSTREL | 146 | #ifdef CONFIG_MAC80211_RC_MINSTREL |
160 | int rc80211_minstrel_init(void); | 147 | int rc80211_minstrel_init(void); |
161 | void rc80211_minstrel_exit(void); | 148 | void rc80211_minstrel_exit(void); |
diff --git a/net/mac80211/rc80211_pid.h b/net/mac80211/rc80211_pid.h deleted file mode 100644 index 19111c7bf454..000000000000 --- a/net/mac80211/rc80211_pid.h +++ /dev/null | |||
@@ -1,278 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de> | ||
3 | * Copyright 2007, Stefano Brivio <stefano.brivio@polimi.it> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #ifndef RC80211_PID_H | ||
11 | #define RC80211_PID_H | ||
12 | |||
13 | /* Sampling period for measuring percentage of failed frames in ms. */ | ||
14 | #define RC_PID_INTERVAL 125 | ||
15 | |||
16 | /* Exponential averaging smoothness (used for I part of PID controller) */ | ||
17 | #define RC_PID_SMOOTHING_SHIFT 3 | ||
18 | #define RC_PID_SMOOTHING (1 << RC_PID_SMOOTHING_SHIFT) | ||
19 | |||
20 | /* Sharpening factor (used for D part of PID controller) */ | ||
21 | #define RC_PID_SHARPENING_FACTOR 0 | ||
22 | #define RC_PID_SHARPENING_DURATION 0 | ||
23 | |||
24 | /* Fixed point arithmetic shifting amount. */ | ||
25 | #define RC_PID_ARITH_SHIFT 8 | ||
26 | |||
27 | /* Proportional PID component coefficient. */ | ||
28 | #define RC_PID_COEFF_P 15 | ||
29 | /* Integral PID component coefficient. */ | ||
30 | #define RC_PID_COEFF_I 9 | ||
31 | /* Derivative PID component coefficient. */ | ||
32 | #define RC_PID_COEFF_D 15 | ||
33 | |||
34 | /* Target failed frames rate for the PID controller. NB: This effectively gives | ||
35 | * maximum failed frames percentage we're willing to accept. If the wireless | ||
36 | * link quality is good, the controller will fail to adjust failed frames | ||
37 | * percentage to the target. This is intentional. | ||
38 | */ | ||
39 | #define RC_PID_TARGET_PF 14 | ||
40 | |||
41 | /* Rate behaviour normalization quantity over time. */ | ||
42 | #define RC_PID_NORM_OFFSET 3 | ||
43 | |||
44 | /* Push high rates right after loading. */ | ||
45 | #define RC_PID_FAST_START 0 | ||
46 | |||
47 | /* Arithmetic right shift for positive and negative values for ISO C. */ | ||
48 | #define RC_PID_DO_ARITH_RIGHT_SHIFT(x, y) \ | ||
49 | ((x) < 0 ? -((-(x)) >> (y)) : (x) >> (y)) | ||
50 | |||
51 | enum rc_pid_event_type { | ||
52 | RC_PID_EVENT_TYPE_TX_STATUS, | ||
53 | RC_PID_EVENT_TYPE_RATE_CHANGE, | ||
54 | RC_PID_EVENT_TYPE_TX_RATE, | ||
55 | RC_PID_EVENT_TYPE_PF_SAMPLE, | ||
56 | }; | ||
57 | |||
58 | union rc_pid_event_data { | ||
59 | /* RC_PID_EVENT_TX_STATUS */ | ||
60 | struct { | ||
61 | u32 flags; | ||
62 | struct ieee80211_tx_info tx_status; | ||
63 | }; | ||
64 | /* RC_PID_EVENT_TYPE_RATE_CHANGE */ | ||
65 | /* RC_PID_EVENT_TYPE_TX_RATE */ | ||
66 | struct { | ||
67 | int index; | ||
68 | int rate; | ||
69 | }; | ||
70 | /* RC_PID_EVENT_TYPE_PF_SAMPLE */ | ||
71 | struct { | ||
72 | s32 pf_sample; | ||
73 | s32 prop_err; | ||
74 | s32 int_err; | ||
75 | s32 der_err; | ||
76 | }; | ||
77 | }; | ||
78 | |||
79 | struct rc_pid_event { | ||
80 | /* The time when the event occurred */ | ||
81 | unsigned long timestamp; | ||
82 | |||
83 | /* Event ID number */ | ||
84 | unsigned int id; | ||
85 | |||
86 | /* Type of event */ | ||
87 | enum rc_pid_event_type type; | ||
88 | |||
89 | /* type specific data */ | ||
90 | union rc_pid_event_data data; | ||
91 | }; | ||
92 | |||
93 | /* Size of the event ring buffer. */ | ||
94 | #define RC_PID_EVENT_RING_SIZE 32 | ||
95 | |||
96 | struct rc_pid_event_buffer { | ||
97 | /* Counter that generates event IDs */ | ||
98 | unsigned int ev_count; | ||
99 | |||
100 | /* Ring buffer of events */ | ||
101 | struct rc_pid_event ring[RC_PID_EVENT_RING_SIZE]; | ||
102 | |||
103 | /* Index to the entry in events_buf to be reused */ | ||
104 | unsigned int next_entry; | ||
105 | |||
106 | /* Lock that guards against concurrent access to this buffer struct */ | ||
107 | spinlock_t lock; | ||
108 | |||
109 | /* Wait queue for poll/select and blocking I/O */ | ||
110 | wait_queue_head_t waitqueue; | ||
111 | }; | ||
112 | |||
113 | struct rc_pid_events_file_info { | ||
114 | /* The event buffer we read */ | ||
115 | struct rc_pid_event_buffer *events; | ||
116 | |||
117 | /* The entry we have should read next */ | ||
118 | unsigned int next_entry; | ||
119 | }; | ||
120 | |||
121 | /** | ||
122 | * struct rc_pid_debugfs_entries - tunable parameters | ||
123 | * | ||
124 | * Algorithm parameters, tunable via debugfs. | ||
125 | * @target: target percentage for failed frames | ||
126 | * @sampling_period: error sampling interval in milliseconds | ||
127 | * @coeff_p: absolute value of the proportional coefficient | ||
128 | * @coeff_i: absolute value of the integral coefficient | ||
129 | * @coeff_d: absolute value of the derivative coefficient | ||
130 | * @smoothing_shift: absolute value of the integral smoothing factor (i.e. | ||
131 | * amount of smoothing introduced by the exponential moving average) | ||
132 | * @sharpen_factor: absolute value of the derivative sharpening factor (i.e. | ||
133 | * amount of emphasis given to the derivative term after low activity | ||
134 | * events) | ||
135 | * @sharpen_duration: duration of the sharpening effect after the detected low | ||
136 | * activity event, relative to sampling_period | ||
137 | * @norm_offset: amount of normalization periodically performed on the learnt | ||
138 | * rate behaviour values (lower means we should trust more what we learnt | ||
139 | * about behaviour of rates, higher means we should trust more the natural | ||
140 | * ordering of rates) | ||
141 | */ | ||
142 | struct rc_pid_debugfs_entries { | ||
143 | struct dentry *target; | ||
144 | struct dentry *sampling_period; | ||
145 | struct dentry *coeff_p; | ||
146 | struct dentry *coeff_i; | ||
147 | struct dentry *coeff_d; | ||
148 | struct dentry *smoothing_shift; | ||
149 | struct dentry *sharpen_factor; | ||
150 | struct dentry *sharpen_duration; | ||
151 | struct dentry *norm_offset; | ||
152 | }; | ||
153 | |||
154 | void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf, | ||
155 | struct ieee80211_tx_info *stat); | ||
156 | |||
157 | void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf, | ||
158 | int index, int rate); | ||
159 | |||
160 | void rate_control_pid_event_tx_rate(struct rc_pid_event_buffer *buf, | ||
161 | int index, int rate); | ||
162 | |||
163 | void rate_control_pid_event_pf_sample(struct rc_pid_event_buffer *buf, | ||
164 | s32 pf_sample, s32 prop_err, | ||
165 | s32 int_err, s32 der_err); | ||
166 | |||
167 | void rate_control_pid_add_sta_debugfs(void *priv, void *priv_sta, | ||
168 | struct dentry *dir); | ||
169 | |||
170 | void rate_control_pid_remove_sta_debugfs(void *priv, void *priv_sta); | ||
171 | |||
172 | struct rc_pid_sta_info { | ||
173 | unsigned long last_change; | ||
174 | unsigned long last_sample; | ||
175 | |||
176 | u32 tx_num_failed; | ||
177 | u32 tx_num_xmit; | ||
178 | |||
179 | int txrate_idx; | ||
180 | |||
181 | /* Average failed frames percentage error (i.e. actual vs. target | ||
182 | * percentage), scaled by RC_PID_SMOOTHING. This value is computed | ||
183 | * using using an exponential weighted average technique: | ||
184 | * | ||
185 | * (RC_PID_SMOOTHING - 1) * err_avg_old + err | ||
186 | * err_avg = ------------------------------------------ | ||
187 | * RC_PID_SMOOTHING | ||
188 | * | ||
189 | * where err_avg is the new approximation, err_avg_old the previous one | ||
190 | * and err is the error w.r.t. to the current failed frames percentage | ||
191 | * sample. Note that the bigger RC_PID_SMOOTHING the more weight is | ||
192 | * given to the previous estimate, resulting in smoother behavior (i.e. | ||
193 | * corresponding to a longer integration window). | ||
194 | * | ||
195 | * For computation, we actually don't use the above formula, but this | ||
196 | * one: | ||
197 | * | ||
198 | * err_avg_scaled = err_avg_old_scaled - err_avg_old + err | ||
199 | * | ||
200 | * where: | ||
201 | * err_avg_scaled = err * RC_PID_SMOOTHING | ||
202 | * err_avg_old_scaled = err_avg_old * RC_PID_SMOOTHING | ||
203 | * | ||
204 | * This avoids floating point numbers and the per_failed_old value can | ||
205 | * easily be obtained by shifting per_failed_old_scaled right by | ||
206 | * RC_PID_SMOOTHING_SHIFT. | ||
207 | */ | ||
208 | s32 err_avg_sc; | ||
209 | |||
210 | /* Last framed failes percentage sample. */ | ||
211 | u32 last_pf; | ||
212 | |||
213 | /* Sharpening needed. */ | ||
214 | u8 sharp_cnt; | ||
215 | |||
216 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
217 | /* Event buffer */ | ||
218 | struct rc_pid_event_buffer events; | ||
219 | |||
220 | /* Events debugfs file entry */ | ||
221 | struct dentry *events_entry; | ||
222 | #endif | ||
223 | }; | ||
224 | |||
225 | /* Algorithm parameters. We keep them on a per-algorithm approach, so they can | ||
226 | * be tuned individually for each interface. | ||
227 | */ | ||
228 | struct rc_pid_rateinfo { | ||
229 | |||
230 | /* Map sorted rates to rates in ieee80211_hw_mode. */ | ||
231 | int index; | ||
232 | |||
233 | /* Map rates in ieee80211_hw_mode to sorted rates. */ | ||
234 | int rev_index; | ||
235 | |||
236 | /* Did we do any measurement on this rate? */ | ||
237 | bool valid; | ||
238 | |||
239 | /* Comparison with the lowest rate. */ | ||
240 | int diff; | ||
241 | }; | ||
242 | |||
243 | struct rc_pid_info { | ||
244 | |||
245 | /* The failed frames percentage target. */ | ||
246 | unsigned int target; | ||
247 | |||
248 | /* Rate at which failed frames percentage is sampled in 0.001s. */ | ||
249 | unsigned int sampling_period; | ||
250 | |||
251 | /* P, I and D coefficients. */ | ||
252 | int coeff_p; | ||
253 | int coeff_i; | ||
254 | int coeff_d; | ||
255 | |||
256 | /* Exponential averaging shift. */ | ||
257 | unsigned int smoothing_shift; | ||
258 | |||
259 | /* Sharpening factor and duration. */ | ||
260 | unsigned int sharpen_factor; | ||
261 | unsigned int sharpen_duration; | ||
262 | |||
263 | /* Normalization offset. */ | ||
264 | unsigned int norm_offset; | ||
265 | |||
266 | /* Rates information. */ | ||
267 | struct rc_pid_rateinfo *rinfo; | ||
268 | |||
269 | /* Index of the last used rate. */ | ||
270 | int oldrate; | ||
271 | |||
272 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
273 | /* Debugfs entries created for the parameters above. */ | ||
274 | struct rc_pid_debugfs_entries dentries; | ||
275 | #endif | ||
276 | }; | ||
277 | |||
278 | #endif /* RC80211_PID_H */ | ||
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c deleted file mode 100644 index d0da2a70fe68..000000000000 --- a/net/mac80211/rc80211_pid_algo.c +++ /dev/null | |||
@@ -1,478 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2002-2005, Instant802 Networks, Inc. | ||
3 | * Copyright 2005, Devicescape Software, Inc. | ||
4 | * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de> | ||
5 | * Copyright 2007-2008, Stefano Brivio <stefano.brivio@polimi.it> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/netdevice.h> | ||
13 | #include <linux/types.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/debugfs.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <net/mac80211.h> | ||
18 | #include "rate.h" | ||
19 | #include "mesh.h" | ||
20 | #include "rc80211_pid.h" | ||
21 | |||
22 | |||
23 | /* This is an implementation of a TX rate control algorithm that uses a PID | ||
24 | * controller. Given a target failed frames rate, the controller decides about | ||
25 | * TX rate changes to meet the target failed frames rate. | ||
26 | * | ||
27 | * The controller basically computes the following: | ||
28 | * | ||
29 | * adj = CP * err + CI * err_avg + CD * (err - last_err) * (1 + sharpening) | ||
30 | * | ||
31 | * where | ||
32 | * adj adjustment value that is used to switch TX rate (see below) | ||
33 | * err current error: target vs. current failed frames percentage | ||
34 | * last_err last error | ||
35 | * err_avg average (i.e. poor man's integral) of recent errors | ||
36 | * sharpening non-zero when fast response is needed (i.e. right after | ||
37 | * association or no frames sent for a long time), heading | ||
38 | * to zero over time | ||
39 | * CP Proportional coefficient | ||
40 | * CI Integral coefficient | ||
41 | * CD Derivative coefficient | ||
42 | * | ||
43 | * CP, CI, CD are subject to careful tuning. | ||
44 | * | ||
45 | * The integral component uses a exponential moving average approach instead of | ||
46 | * an actual sliding window. The advantage is that we don't need to keep an | ||
47 | * array of the last N error values and computation is easier. | ||
48 | * | ||
49 | * Once we have the adj value, we map it to a rate by means of a learning | ||
50 | * algorithm. This algorithm keeps the state of the percentual failed frames | ||
51 | * difference between rates. The behaviour of the lowest available rate is kept | ||
52 | * as a reference value, and every time we switch between two rates, we compute | ||
53 | * the difference between the failed frames each rate exhibited. By doing so, | ||
54 | * we compare behaviours which different rates exhibited in adjacent timeslices, | ||
55 | * thus the comparison is minimally affected by external conditions. This | ||
56 | * difference gets propagated to the whole set of measurements, so that the | ||
57 | * reference is always the same. Periodically, we normalize this set so that | ||
58 | * recent events weigh the most. By comparing the adj value with this set, we | ||
59 | * avoid pejorative switches to lower rates and allow for switches to higher | ||
60 | * rates if they behaved well. | ||
61 | * | ||
62 | * Note that for the computations we use a fixed-point representation to avoid | ||
63 | * floating point arithmetic. Hence, all values are shifted left by | ||
64 | * RC_PID_ARITH_SHIFT. | ||
65 | */ | ||
66 | |||
67 | |||
68 | /* Adjust the rate while ensuring that we won't switch to a lower rate if it | ||
69 | * exhibited a worse failed frames behaviour and we'll choose the highest rate | ||
70 | * whose failed frames behaviour is not worse than the one of the original rate | ||
71 | * target. While at it, check that the new rate is valid. */ | ||
72 | static void rate_control_pid_adjust_rate(struct ieee80211_supported_band *sband, | ||
73 | struct ieee80211_sta *sta, | ||
74 | struct rc_pid_sta_info *spinfo, int adj, | ||
75 | struct rc_pid_rateinfo *rinfo) | ||
76 | { | ||
77 | int cur_sorted, new_sorted, probe, tmp, n_bitrates, band; | ||
78 | int cur = spinfo->txrate_idx; | ||
79 | |||
80 | band = sband->band; | ||
81 | n_bitrates = sband->n_bitrates; | ||
82 | |||
83 | /* Map passed arguments to sorted values. */ | ||
84 | cur_sorted = rinfo[cur].rev_index; | ||
85 | new_sorted = cur_sorted + adj; | ||
86 | |||
87 | /* Check limits. */ | ||
88 | if (new_sorted < 0) | ||
89 | new_sorted = rinfo[0].rev_index; | ||
90 | else if (new_sorted >= n_bitrates) | ||
91 | new_sorted = rinfo[n_bitrates - 1].rev_index; | ||
92 | |||
93 | tmp = new_sorted; | ||
94 | |||
95 | if (adj < 0) { | ||
96 | /* Ensure that the rate decrease isn't disadvantageous. */ | ||
97 | for (probe = cur_sorted; probe >= new_sorted; probe--) | ||
98 | if (rinfo[probe].diff <= rinfo[cur_sorted].diff && | ||
99 | rate_supported(sta, band, rinfo[probe].index)) | ||
100 | tmp = probe; | ||
101 | } else { | ||
102 | /* Look for rate increase with zero (or below) cost. */ | ||
103 | for (probe = new_sorted + 1; probe < n_bitrates; probe++) | ||
104 | if (rinfo[probe].diff <= rinfo[new_sorted].diff && | ||
105 | rate_supported(sta, band, rinfo[probe].index)) | ||
106 | tmp = probe; | ||
107 | } | ||
108 | |||
109 | /* Fit the rate found to the nearest supported rate. */ | ||
110 | do { | ||
111 | if (rate_supported(sta, band, rinfo[tmp].index)) { | ||
112 | spinfo->txrate_idx = rinfo[tmp].index; | ||
113 | break; | ||
114 | } | ||
115 | if (adj < 0) | ||
116 | tmp--; | ||
117 | else | ||
118 | tmp++; | ||
119 | } while (tmp < n_bitrates && tmp >= 0); | ||
120 | |||
121 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
122 | rate_control_pid_event_rate_change(&spinfo->events, | ||
123 | spinfo->txrate_idx, | ||
124 | sband->bitrates[spinfo->txrate_idx].bitrate); | ||
125 | #endif | ||
126 | } | ||
127 | |||
128 | /* Normalize the failed frames per-rate differences. */ | ||
129 | static void rate_control_pid_normalize(struct rc_pid_info *pinfo, int l) | ||
130 | { | ||
131 | int i, norm_offset = pinfo->norm_offset; | ||
132 | struct rc_pid_rateinfo *r = pinfo->rinfo; | ||
133 | |||
134 | if (r[0].diff > norm_offset) | ||
135 | r[0].diff -= norm_offset; | ||
136 | else if (r[0].diff < -norm_offset) | ||
137 | r[0].diff += norm_offset; | ||
138 | for (i = 0; i < l - 1; i++) | ||
139 | if (r[i + 1].diff > r[i].diff + norm_offset) | ||
140 | r[i + 1].diff -= norm_offset; | ||
141 | else if (r[i + 1].diff <= r[i].diff) | ||
142 | r[i + 1].diff += norm_offset; | ||
143 | } | ||
144 | |||
145 | static void rate_control_pid_sample(struct rc_pid_info *pinfo, | ||
146 | struct ieee80211_supported_band *sband, | ||
147 | struct ieee80211_sta *sta, | ||
148 | struct rc_pid_sta_info *spinfo) | ||
149 | { | ||
150 | struct rc_pid_rateinfo *rinfo = pinfo->rinfo; | ||
151 | u32 pf; | ||
152 | s32 err_avg; | ||
153 | u32 err_prop; | ||
154 | u32 err_int; | ||
155 | u32 err_der; | ||
156 | int adj, i, j, tmp; | ||
157 | unsigned long period; | ||
158 | |||
159 | /* In case nothing happened during the previous control interval, turn | ||
160 | * the sharpening factor on. */ | ||
161 | period = msecs_to_jiffies(pinfo->sampling_period); | ||
162 | if (jiffies - spinfo->last_sample > 2 * period) | ||
163 | spinfo->sharp_cnt = pinfo->sharpen_duration; | ||
164 | |||
165 | spinfo->last_sample = jiffies; | ||
166 | |||
167 | /* This should never happen, but in case, we assume the old sample is | ||
168 | * still a good measurement and copy it. */ | ||
169 | if (unlikely(spinfo->tx_num_xmit == 0)) | ||
170 | pf = spinfo->last_pf; | ||
171 | else | ||
172 | pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit; | ||
173 | |||
174 | spinfo->tx_num_xmit = 0; | ||
175 | spinfo->tx_num_failed = 0; | ||
176 | |||
177 | /* If we just switched rate, update the rate behaviour info. */ | ||
178 | if (pinfo->oldrate != spinfo->txrate_idx) { | ||
179 | |||
180 | i = rinfo[pinfo->oldrate].rev_index; | ||
181 | j = rinfo[spinfo->txrate_idx].rev_index; | ||
182 | |||
183 | tmp = (pf - spinfo->last_pf); | ||
184 | tmp = RC_PID_DO_ARITH_RIGHT_SHIFT(tmp, RC_PID_ARITH_SHIFT); | ||
185 | |||
186 | rinfo[j].diff = rinfo[i].diff + tmp; | ||
187 | pinfo->oldrate = spinfo->txrate_idx; | ||
188 | } | ||
189 | rate_control_pid_normalize(pinfo, sband->n_bitrates); | ||
190 | |||
191 | /* Compute the proportional, integral and derivative errors. */ | ||
192 | err_prop = (pinfo->target - pf) << RC_PID_ARITH_SHIFT; | ||
193 | |||
194 | err_avg = spinfo->err_avg_sc >> pinfo->smoothing_shift; | ||
195 | spinfo->err_avg_sc = spinfo->err_avg_sc - err_avg + err_prop; | ||
196 | err_int = spinfo->err_avg_sc >> pinfo->smoothing_shift; | ||
197 | |||
198 | err_der = (pf - spinfo->last_pf) * | ||
199 | (1 + pinfo->sharpen_factor * spinfo->sharp_cnt); | ||
200 | spinfo->last_pf = pf; | ||
201 | if (spinfo->sharp_cnt) | ||
202 | spinfo->sharp_cnt--; | ||
203 | |||
204 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
205 | rate_control_pid_event_pf_sample(&spinfo->events, pf, err_prop, err_int, | ||
206 | err_der); | ||
207 | #endif | ||
208 | |||
209 | /* Compute the controller output. */ | ||
210 | adj = (err_prop * pinfo->coeff_p + err_int * pinfo->coeff_i | ||
211 | + err_der * pinfo->coeff_d); | ||
212 | adj = RC_PID_DO_ARITH_RIGHT_SHIFT(adj, 2 * RC_PID_ARITH_SHIFT); | ||
213 | |||
214 | /* Change rate. */ | ||
215 | if (adj) | ||
216 | rate_control_pid_adjust_rate(sband, sta, spinfo, adj, rinfo); | ||
217 | } | ||
218 | |||
219 | static void rate_control_pid_tx_status(void *priv, struct ieee80211_supported_band *sband, | ||
220 | struct ieee80211_sta *sta, void *priv_sta, | ||
221 | struct sk_buff *skb) | ||
222 | { | ||
223 | struct rc_pid_info *pinfo = priv; | ||
224 | struct rc_pid_sta_info *spinfo = priv_sta; | ||
225 | unsigned long period; | ||
226 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
227 | |||
228 | if (!spinfo) | ||
229 | return; | ||
230 | |||
231 | /* Ignore all frames that were sent with a different rate than the rate | ||
232 | * we currently advise mac80211 to use. */ | ||
233 | if (info->status.rates[0].idx != spinfo->txrate_idx) | ||
234 | return; | ||
235 | |||
236 | spinfo->tx_num_xmit++; | ||
237 | |||
238 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
239 | rate_control_pid_event_tx_status(&spinfo->events, info); | ||
240 | #endif | ||
241 | |||
242 | /* We count frames that totally failed to be transmitted as two bad | ||
243 | * frames, those that made it out but had some retries as one good and | ||
244 | * one bad frame. */ | ||
245 | if (!(info->flags & IEEE80211_TX_STAT_ACK)) { | ||
246 | spinfo->tx_num_failed += 2; | ||
247 | spinfo->tx_num_xmit++; | ||
248 | } else if (info->status.rates[0].count > 1) { | ||
249 | spinfo->tx_num_failed++; | ||
250 | spinfo->tx_num_xmit++; | ||
251 | } | ||
252 | |||
253 | /* Update PID controller state. */ | ||
254 | period = msecs_to_jiffies(pinfo->sampling_period); | ||
255 | if (time_after(jiffies, spinfo->last_sample + period)) | ||
256 | rate_control_pid_sample(pinfo, sband, sta, spinfo); | ||
257 | } | ||
258 | |||
259 | static void | ||
260 | rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta, | ||
261 | void *priv_sta, | ||
262 | struct ieee80211_tx_rate_control *txrc) | ||
263 | { | ||
264 | struct sk_buff *skb = txrc->skb; | ||
265 | struct ieee80211_supported_band *sband = txrc->sband; | ||
266 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
267 | struct rc_pid_sta_info *spinfo = priv_sta; | ||
268 | int rateidx; | ||
269 | |||
270 | if (txrc->rts) | ||
271 | info->control.rates[0].count = | ||
272 | txrc->hw->conf.long_frame_max_tx_count; | ||
273 | else | ||
274 | info->control.rates[0].count = | ||
275 | txrc->hw->conf.short_frame_max_tx_count; | ||
276 | |||
277 | /* Send management frames and NO_ACK data using lowest rate. */ | ||
278 | if (rate_control_send_low(sta, priv_sta, txrc)) | ||
279 | return; | ||
280 | |||
281 | rateidx = spinfo->txrate_idx; | ||
282 | |||
283 | if (rateidx >= sband->n_bitrates) | ||
284 | rateidx = sband->n_bitrates - 1; | ||
285 | |||
286 | info->control.rates[0].idx = rateidx; | ||
287 | |||
288 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
289 | rate_control_pid_event_tx_rate(&spinfo->events, | ||
290 | rateidx, sband->bitrates[rateidx].bitrate); | ||
291 | #endif | ||
292 | } | ||
293 | |||
294 | static void | ||
295 | rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband, | ||
296 | struct cfg80211_chan_def *chandef, | ||
297 | struct ieee80211_sta *sta, void *priv_sta) | ||
298 | { | ||
299 | struct rc_pid_sta_info *spinfo = priv_sta; | ||
300 | struct rc_pid_info *pinfo = priv; | ||
301 | struct rc_pid_rateinfo *rinfo = pinfo->rinfo; | ||
302 | int i, j, tmp; | ||
303 | bool s; | ||
304 | |||
305 | /* TODO: This routine should consider using RSSI from previous packets | ||
306 | * as we need to have IEEE 802.1X auth succeed immediately after assoc.. | ||
307 | * Until that method is implemented, we will use the lowest supported | ||
308 | * rate as a workaround. */ | ||
309 | |||
310 | /* Sort the rates. This is optimized for the most common case (i.e. | ||
311 | * almost-sorted CCK+OFDM rates). Kind of bubble-sort with reversed | ||
312 | * mapping too. */ | ||
313 | for (i = 0; i < sband->n_bitrates; i++) { | ||
314 | rinfo[i].index = i; | ||
315 | rinfo[i].rev_index = i; | ||
316 | if (RC_PID_FAST_START) | ||
317 | rinfo[i].diff = 0; | ||
318 | else | ||
319 | rinfo[i].diff = i * pinfo->norm_offset; | ||
320 | } | ||
321 | for (i = 1; i < sband->n_bitrates; i++) { | ||
322 | s = false; | ||
323 | for (j = 0; j < sband->n_bitrates - i; j++) | ||
324 | if (unlikely(sband->bitrates[rinfo[j].index].bitrate > | ||
325 | sband->bitrates[rinfo[j + 1].index].bitrate)) { | ||
326 | tmp = rinfo[j].index; | ||
327 | rinfo[j].index = rinfo[j + 1].index; | ||
328 | rinfo[j + 1].index = tmp; | ||
329 | rinfo[rinfo[j].index].rev_index = j; | ||
330 | rinfo[rinfo[j + 1].index].rev_index = j + 1; | ||
331 | s = true; | ||
332 | } | ||
333 | if (!s) | ||
334 | break; | ||
335 | } | ||
336 | |||
337 | spinfo->txrate_idx = rate_lowest_index(sband, sta); | ||
338 | } | ||
339 | |||
340 | static void *rate_control_pid_alloc(struct ieee80211_hw *hw, | ||
341 | struct dentry *debugfsdir) | ||
342 | { | ||
343 | struct rc_pid_info *pinfo; | ||
344 | struct rc_pid_rateinfo *rinfo; | ||
345 | struct ieee80211_supported_band *sband; | ||
346 | int i, max_rates = 0; | ||
347 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
348 | struct rc_pid_debugfs_entries *de; | ||
349 | #endif | ||
350 | |||
351 | pinfo = kmalloc(sizeof(*pinfo), GFP_ATOMIC); | ||
352 | if (!pinfo) | ||
353 | return NULL; | ||
354 | |||
355 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | ||
356 | sband = hw->wiphy->bands[i]; | ||
357 | if (sband && sband->n_bitrates > max_rates) | ||
358 | max_rates = sband->n_bitrates; | ||
359 | } | ||
360 | |||
361 | rinfo = kmalloc(sizeof(*rinfo) * max_rates, GFP_ATOMIC); | ||
362 | if (!rinfo) { | ||
363 | kfree(pinfo); | ||
364 | return NULL; | ||
365 | } | ||
366 | |||
367 | pinfo->target = RC_PID_TARGET_PF; | ||
368 | pinfo->sampling_period = RC_PID_INTERVAL; | ||
369 | pinfo->coeff_p = RC_PID_COEFF_P; | ||
370 | pinfo->coeff_i = RC_PID_COEFF_I; | ||
371 | pinfo->coeff_d = RC_PID_COEFF_D; | ||
372 | pinfo->smoothing_shift = RC_PID_SMOOTHING_SHIFT; | ||
373 | pinfo->sharpen_factor = RC_PID_SHARPENING_FACTOR; | ||
374 | pinfo->sharpen_duration = RC_PID_SHARPENING_DURATION; | ||
375 | pinfo->norm_offset = RC_PID_NORM_OFFSET; | ||
376 | pinfo->rinfo = rinfo; | ||
377 | pinfo->oldrate = 0; | ||
378 | |||
379 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
380 | de = &pinfo->dentries; | ||
381 | de->target = debugfs_create_u32("target_pf", S_IRUSR | S_IWUSR, | ||
382 | debugfsdir, &pinfo->target); | ||
383 | de->sampling_period = debugfs_create_u32("sampling_period", | ||
384 | S_IRUSR | S_IWUSR, debugfsdir, | ||
385 | &pinfo->sampling_period); | ||
386 | de->coeff_p = debugfs_create_u32("coeff_p", S_IRUSR | S_IWUSR, | ||
387 | debugfsdir, (u32 *)&pinfo->coeff_p); | ||
388 | de->coeff_i = debugfs_create_u32("coeff_i", S_IRUSR | S_IWUSR, | ||
389 | debugfsdir, (u32 *)&pinfo->coeff_i); | ||
390 | de->coeff_d = debugfs_create_u32("coeff_d", S_IRUSR | S_IWUSR, | ||
391 | debugfsdir, (u32 *)&pinfo->coeff_d); | ||
392 | de->smoothing_shift = debugfs_create_u32("smoothing_shift", | ||
393 | S_IRUSR | S_IWUSR, debugfsdir, | ||
394 | &pinfo->smoothing_shift); | ||
395 | de->sharpen_factor = debugfs_create_u32("sharpen_factor", | ||
396 | S_IRUSR | S_IWUSR, debugfsdir, | ||
397 | &pinfo->sharpen_factor); | ||
398 | de->sharpen_duration = debugfs_create_u32("sharpen_duration", | ||
399 | S_IRUSR | S_IWUSR, debugfsdir, | ||
400 | &pinfo->sharpen_duration); | ||
401 | de->norm_offset = debugfs_create_u32("norm_offset", | ||
402 | S_IRUSR | S_IWUSR, debugfsdir, | ||
403 | &pinfo->norm_offset); | ||
404 | #endif | ||
405 | |||
406 | return pinfo; | ||
407 | } | ||
408 | |||
409 | static void rate_control_pid_free(void *priv) | ||
410 | { | ||
411 | struct rc_pid_info *pinfo = priv; | ||
412 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
413 | struct rc_pid_debugfs_entries *de = &pinfo->dentries; | ||
414 | |||
415 | debugfs_remove(de->norm_offset); | ||
416 | debugfs_remove(de->sharpen_duration); | ||
417 | debugfs_remove(de->sharpen_factor); | ||
418 | debugfs_remove(de->smoothing_shift); | ||
419 | debugfs_remove(de->coeff_d); | ||
420 | debugfs_remove(de->coeff_i); | ||
421 | debugfs_remove(de->coeff_p); | ||
422 | debugfs_remove(de->sampling_period); | ||
423 | debugfs_remove(de->target); | ||
424 | #endif | ||
425 | |||
426 | kfree(pinfo->rinfo); | ||
427 | kfree(pinfo); | ||
428 | } | ||
429 | |||
430 | static void *rate_control_pid_alloc_sta(void *priv, struct ieee80211_sta *sta, | ||
431 | gfp_t gfp) | ||
432 | { | ||
433 | struct rc_pid_sta_info *spinfo; | ||
434 | |||
435 | spinfo = kzalloc(sizeof(*spinfo), gfp); | ||
436 | if (spinfo == NULL) | ||
437 | return NULL; | ||
438 | |||
439 | spinfo->last_sample = jiffies; | ||
440 | |||
441 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
442 | spin_lock_init(&spinfo->events.lock); | ||
443 | init_waitqueue_head(&spinfo->events.waitqueue); | ||
444 | #endif | ||
445 | |||
446 | return spinfo; | ||
447 | } | ||
448 | |||
449 | static void rate_control_pid_free_sta(void *priv, struct ieee80211_sta *sta, | ||
450 | void *priv_sta) | ||
451 | { | ||
452 | kfree(priv_sta); | ||
453 | } | ||
454 | |||
455 | static const struct rate_control_ops mac80211_rcpid = { | ||
456 | .name = "pid", | ||
457 | .tx_status = rate_control_pid_tx_status, | ||
458 | .get_rate = rate_control_pid_get_rate, | ||
459 | .rate_init = rate_control_pid_rate_init, | ||
460 | .alloc = rate_control_pid_alloc, | ||
461 | .free = rate_control_pid_free, | ||
462 | .alloc_sta = rate_control_pid_alloc_sta, | ||
463 | .free_sta = rate_control_pid_free_sta, | ||
464 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
465 | .add_sta_debugfs = rate_control_pid_add_sta_debugfs, | ||
466 | .remove_sta_debugfs = rate_control_pid_remove_sta_debugfs, | ||
467 | #endif | ||
468 | }; | ||
469 | |||
470 | int __init rc80211_pid_init(void) | ||
471 | { | ||
472 | return ieee80211_rate_control_register(&mac80211_rcpid); | ||
473 | } | ||
474 | |||
475 | void rc80211_pid_exit(void) | ||
476 | { | ||
477 | ieee80211_rate_control_unregister(&mac80211_rcpid); | ||
478 | } | ||
diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c deleted file mode 100644 index 6ff134650a84..000000000000 --- a/net/mac80211/rc80211_pid_debugfs.c +++ /dev/null | |||
@@ -1,228 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/sched.h> | ||
10 | #include <linux/spinlock.h> | ||
11 | #include <linux/poll.h> | ||
12 | #include <linux/netdevice.h> | ||
13 | #include <linux/types.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/export.h> | ||
17 | |||
18 | #include <net/mac80211.h> | ||
19 | #include "rate.h" | ||
20 | |||
21 | #include "rc80211_pid.h" | ||
22 | |||
23 | static void rate_control_pid_event(struct rc_pid_event_buffer *buf, | ||
24 | enum rc_pid_event_type type, | ||
25 | union rc_pid_event_data *data) | ||
26 | { | ||
27 | struct rc_pid_event *ev; | ||
28 | unsigned long status; | ||
29 | |||
30 | spin_lock_irqsave(&buf->lock, status); | ||
31 | ev = &(buf->ring[buf->next_entry]); | ||
32 | buf->next_entry = (buf->next_entry + 1) % RC_PID_EVENT_RING_SIZE; | ||
33 | |||
34 | ev->timestamp = jiffies; | ||
35 | ev->id = buf->ev_count++; | ||
36 | ev->type = type; | ||
37 | ev->data = *data; | ||
38 | |||
39 | spin_unlock_irqrestore(&buf->lock, status); | ||
40 | |||
41 | wake_up_all(&buf->waitqueue); | ||
42 | } | ||
43 | |||
44 | void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf, | ||
45 | struct ieee80211_tx_info *stat) | ||
46 | { | ||
47 | union rc_pid_event_data evd; | ||
48 | |||
49 | evd.flags = stat->flags; | ||
50 | memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_info)); | ||
51 | rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd); | ||
52 | } | ||
53 | |||
54 | void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf, | ||
55 | int index, int rate) | ||
56 | { | ||
57 | union rc_pid_event_data evd; | ||
58 | |||
59 | evd.index = index; | ||
60 | evd.rate = rate; | ||
61 | rate_control_pid_event(buf, RC_PID_EVENT_TYPE_RATE_CHANGE, &evd); | ||
62 | } | ||
63 | |||
64 | void rate_control_pid_event_tx_rate(struct rc_pid_event_buffer *buf, | ||
65 | int index, int rate) | ||
66 | { | ||
67 | union rc_pid_event_data evd; | ||
68 | |||
69 | evd.index = index; | ||
70 | evd.rate = rate; | ||
71 | rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_RATE, &evd); | ||
72 | } | ||
73 | |||
74 | void rate_control_pid_event_pf_sample(struct rc_pid_event_buffer *buf, | ||
75 | s32 pf_sample, s32 prop_err, | ||
76 | s32 int_err, s32 der_err) | ||
77 | { | ||
78 | union rc_pid_event_data evd; | ||
79 | |||
80 | evd.pf_sample = pf_sample; | ||
81 | evd.prop_err = prop_err; | ||
82 | evd.int_err = int_err; | ||
83 | evd.der_err = der_err; | ||
84 | rate_control_pid_event(buf, RC_PID_EVENT_TYPE_PF_SAMPLE, &evd); | ||
85 | } | ||
86 | |||
87 | static int rate_control_pid_events_open(struct inode *inode, struct file *file) | ||
88 | { | ||
89 | struct rc_pid_sta_info *sinfo = inode->i_private; | ||
90 | struct rc_pid_event_buffer *events = &sinfo->events; | ||
91 | struct rc_pid_events_file_info *file_info; | ||
92 | unsigned long status; | ||
93 | |||
94 | /* Allocate a state struct */ | ||
95 | file_info = kmalloc(sizeof(*file_info), GFP_KERNEL); | ||
96 | if (file_info == NULL) | ||
97 | return -ENOMEM; | ||
98 | |||
99 | spin_lock_irqsave(&events->lock, status); | ||
100 | |||
101 | file_info->next_entry = events->next_entry; | ||
102 | file_info->events = events; | ||
103 | |||
104 | spin_unlock_irqrestore(&events->lock, status); | ||
105 | |||
106 | file->private_data = file_info; | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static int rate_control_pid_events_release(struct inode *inode, | ||
112 | struct file *file) | ||
113 | { | ||
114 | struct rc_pid_events_file_info *file_info = file->private_data; | ||
115 | |||
116 | kfree(file_info); | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | static unsigned int rate_control_pid_events_poll(struct file *file, | ||
122 | poll_table *wait) | ||
123 | { | ||
124 | struct rc_pid_events_file_info *file_info = file->private_data; | ||
125 | |||
126 | poll_wait(file, &file_info->events->waitqueue, wait); | ||
127 | |||
128 | return POLLIN | POLLRDNORM; | ||
129 | } | ||
130 | |||
131 | #define RC_PID_PRINT_BUF_SIZE 64 | ||
132 | |||
133 | static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf, | ||
134 | size_t length, loff_t *offset) | ||
135 | { | ||
136 | struct rc_pid_events_file_info *file_info = file->private_data; | ||
137 | struct rc_pid_event_buffer *events = file_info->events; | ||
138 | struct rc_pid_event *ev; | ||
139 | char pb[RC_PID_PRINT_BUF_SIZE]; | ||
140 | int ret; | ||
141 | int p; | ||
142 | unsigned long status; | ||
143 | |||
144 | /* Check if there is something to read. */ | ||
145 | if (events->next_entry == file_info->next_entry) { | ||
146 | if (file->f_flags & O_NONBLOCK) | ||
147 | return -EAGAIN; | ||
148 | |||
149 | /* Wait */ | ||
150 | ret = wait_event_interruptible(events->waitqueue, | ||
151 | events->next_entry != file_info->next_entry); | ||
152 | |||
153 | if (ret) | ||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | /* Write out one event per call. I don't care whether it's a little | ||
158 | * inefficient, this is debugging code anyway. */ | ||
159 | spin_lock_irqsave(&events->lock, status); | ||
160 | |||
161 | /* Get an event */ | ||
162 | ev = &(events->ring[file_info->next_entry]); | ||
163 | file_info->next_entry = (file_info->next_entry + 1) % | ||
164 | RC_PID_EVENT_RING_SIZE; | ||
165 | |||
166 | /* Print information about the event. Note that userspace needs to | ||
167 | * provide large enough buffers. */ | ||
168 | length = length < RC_PID_PRINT_BUF_SIZE ? | ||
169 | length : RC_PID_PRINT_BUF_SIZE; | ||
170 | p = scnprintf(pb, length, "%u %lu ", ev->id, ev->timestamp); | ||
171 | switch (ev->type) { | ||
172 | case RC_PID_EVENT_TYPE_TX_STATUS: | ||
173 | p += scnprintf(pb + p, length - p, "tx_status %u %u", | ||
174 | !(ev->data.flags & IEEE80211_TX_STAT_ACK), | ||
175 | ev->data.tx_status.status.rates[0].idx); | ||
176 | break; | ||
177 | case RC_PID_EVENT_TYPE_RATE_CHANGE: | ||
178 | p += scnprintf(pb + p, length - p, "rate_change %d %d", | ||
179 | ev->data.index, ev->data.rate); | ||
180 | break; | ||
181 | case RC_PID_EVENT_TYPE_TX_RATE: | ||
182 | p += scnprintf(pb + p, length - p, "tx_rate %d %d", | ||
183 | ev->data.index, ev->data.rate); | ||
184 | break; | ||
185 | case RC_PID_EVENT_TYPE_PF_SAMPLE: | ||
186 | p += scnprintf(pb + p, length - p, | ||
187 | "pf_sample %d %d %d %d", | ||
188 | ev->data.pf_sample, ev->data.prop_err, | ||
189 | ev->data.int_err, ev->data.der_err); | ||
190 | break; | ||
191 | } | ||
192 | p += scnprintf(pb + p, length - p, "\n"); | ||
193 | |||
194 | spin_unlock_irqrestore(&events->lock, status); | ||
195 | |||
196 | if (copy_to_user(buf, pb, p)) | ||
197 | return -EFAULT; | ||
198 | |||
199 | return p; | ||
200 | } | ||
201 | |||
202 | #undef RC_PID_PRINT_BUF_SIZE | ||
203 | |||
204 | static const struct file_operations rc_pid_fop_events = { | ||
205 | .owner = THIS_MODULE, | ||
206 | .read = rate_control_pid_events_read, | ||
207 | .poll = rate_control_pid_events_poll, | ||
208 | .open = rate_control_pid_events_open, | ||
209 | .release = rate_control_pid_events_release, | ||
210 | .llseek = noop_llseek, | ||
211 | }; | ||
212 | |||
213 | void rate_control_pid_add_sta_debugfs(void *priv, void *priv_sta, | ||
214 | struct dentry *dir) | ||
215 | { | ||
216 | struct rc_pid_sta_info *spinfo = priv_sta; | ||
217 | |||
218 | spinfo->events_entry = debugfs_create_file("rc_pid_events", S_IRUGO, | ||
219 | dir, spinfo, | ||
220 | &rc_pid_fop_events); | ||
221 | } | ||
222 | |||
223 | void rate_control_pid_remove_sta_debugfs(void *priv, void *priv_sta) | ||
224 | { | ||
225 | struct rc_pid_sta_info *spinfo = priv_sta; | ||
226 | |||
227 | debugfs_remove(spinfo->events_entry); | ||
228 | } | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 394e201cde6d..5f572bed1761 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1107,6 +1107,8 @@ static void sta_ps_end(struct sta_info *sta) | |||
1107 | return; | 1107 | return; |
1108 | } | 1108 | } |
1109 | 1109 | ||
1110 | set_sta_flag(sta, WLAN_STA_PS_DELIVER); | ||
1111 | clear_sta_flag(sta, WLAN_STA_PS_STA); | ||
1110 | ieee80211_sta_ps_deliver_wakeup(sta); | 1112 | ieee80211_sta_ps_deliver_wakeup(sta); |
1111 | } | 1113 | } |
1112 | 1114 | ||
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index f40661eb75b5..a0a938145dcc 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -235,38 +235,51 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | |||
235 | { | 235 | { |
236 | struct cfg80211_scan_request *req = local->scan_req; | 236 | struct cfg80211_scan_request *req = local->scan_req; |
237 | struct cfg80211_chan_def chandef; | 237 | struct cfg80211_chan_def chandef; |
238 | enum ieee80211_band band; | 238 | u8 bands_used = 0; |
239 | int i, ielen, n_chans; | 239 | int i, ielen, n_chans; |
240 | 240 | ||
241 | if (test_bit(SCAN_HW_CANCELLED, &local->scanning)) | 241 | if (test_bit(SCAN_HW_CANCELLED, &local->scanning)) |
242 | return false; | 242 | return false; |
243 | 243 | ||
244 | do { | 244 | if (local->hw.flags & IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS) { |
245 | if (local->hw_scan_band == IEEE80211_NUM_BANDS) | ||
246 | return false; | ||
247 | |||
248 | band = local->hw_scan_band; | ||
249 | n_chans = 0; | ||
250 | for (i = 0; i < req->n_channels; i++) { | 245 | for (i = 0; i < req->n_channels; i++) { |
251 | if (req->channels[i]->band == band) { | 246 | local->hw_scan_req->req.channels[i] = req->channels[i]; |
252 | local->hw_scan_req->channels[n_chans] = | 247 | bands_used |= BIT(req->channels[i]->band); |
248 | } | ||
249 | |||
250 | n_chans = req->n_channels; | ||
251 | } else { | ||
252 | do { | ||
253 | if (local->hw_scan_band == IEEE80211_NUM_BANDS) | ||
254 | return false; | ||
255 | |||
256 | n_chans = 0; | ||
257 | |||
258 | for (i = 0; i < req->n_channels; i++) { | ||
259 | if (req->channels[i]->band != | ||
260 | local->hw_scan_band) | ||
261 | continue; | ||
262 | local->hw_scan_req->req.channels[n_chans] = | ||
253 | req->channels[i]; | 263 | req->channels[i]; |
254 | n_chans++; | 264 | n_chans++; |
265 | bands_used |= BIT(req->channels[i]->band); | ||
255 | } | 266 | } |
256 | } | ||
257 | 267 | ||
258 | local->hw_scan_band++; | 268 | local->hw_scan_band++; |
259 | } while (!n_chans); | 269 | } while (!n_chans); |
270 | } | ||
260 | 271 | ||
261 | local->hw_scan_req->n_channels = n_chans; | 272 | local->hw_scan_req->req.n_channels = n_chans; |
262 | ieee80211_prepare_scan_chandef(&chandef, req->scan_width); | 273 | ieee80211_prepare_scan_chandef(&chandef, req->scan_width); |
263 | 274 | ||
264 | ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, | 275 | ielen = ieee80211_build_preq_ies(local, |
276 | (u8 *)local->hw_scan_req->req.ie, | ||
265 | local->hw_scan_ies_bufsize, | 277 | local->hw_scan_ies_bufsize, |
266 | req->ie, req->ie_len, band, | 278 | &local->hw_scan_req->ies, |
267 | req->rates[band], &chandef); | 279 | req->ie, req->ie_len, |
268 | local->hw_scan_req->ie_len = ielen; | 280 | bands_used, req->rates, &chandef); |
269 | local->hw_scan_req->no_cck = req->no_cck; | 281 | local->hw_scan_req->req.ie_len = ielen; |
282 | local->hw_scan_req->req.no_cck = req->no_cck; | ||
270 | 283 | ||
271 | return true; | 284 | return true; |
272 | } | 285 | } |
@@ -291,7 +304,9 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
291 | if (WARN_ON(!local->scan_req)) | 304 | if (WARN_ON(!local->scan_req)) |
292 | return; | 305 | return; |
293 | 306 | ||
294 | if (hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { | 307 | if (hw_scan && !aborted && |
308 | !(local->hw.flags & IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS) && | ||
309 | ieee80211_prep_hw_scan(local)) { | ||
295 | int rc; | 310 | int rc; |
296 | 311 | ||
297 | rc = drv_hw_scan(local, | 312 | rc = drv_hw_scan(local, |
@@ -473,6 +488,21 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
473 | u8 *ies; | 488 | u8 *ies; |
474 | 489 | ||
475 | local->hw_scan_ies_bufsize = local->scan_ies_len + req->ie_len; | 490 | local->hw_scan_ies_bufsize = local->scan_ies_len + req->ie_len; |
491 | |||
492 | if (local->hw.flags & IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS) { | ||
493 | int i, n_bands = 0; | ||
494 | u8 bands_counted = 0; | ||
495 | |||
496 | for (i = 0; i < req->n_channels; i++) { | ||
497 | if (bands_counted & BIT(req->channels[i]->band)) | ||
498 | continue; | ||
499 | bands_counted |= BIT(req->channels[i]->band); | ||
500 | n_bands++; | ||
501 | } | ||
502 | |||
503 | local->hw_scan_ies_bufsize *= n_bands; | ||
504 | } | ||
505 | |||
476 | local->hw_scan_req = kmalloc( | 506 | local->hw_scan_req = kmalloc( |
477 | sizeof(*local->hw_scan_req) + | 507 | sizeof(*local->hw_scan_req) + |
478 | req->n_channels * sizeof(req->channels[0]) + | 508 | req->n_channels * sizeof(req->channels[0]) + |
@@ -480,13 +510,13 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
480 | if (!local->hw_scan_req) | 510 | if (!local->hw_scan_req) |
481 | return -ENOMEM; | 511 | return -ENOMEM; |
482 | 512 | ||
483 | local->hw_scan_req->ssids = req->ssids; | 513 | local->hw_scan_req->req.ssids = req->ssids; |
484 | local->hw_scan_req->n_ssids = req->n_ssids; | 514 | local->hw_scan_req->req.n_ssids = req->n_ssids; |
485 | ies = (u8 *)local->hw_scan_req + | 515 | ies = (u8 *)local->hw_scan_req + |
486 | sizeof(*local->hw_scan_req) + | 516 | sizeof(*local->hw_scan_req) + |
487 | req->n_channels * sizeof(req->channels[0]); | 517 | req->n_channels * sizeof(req->channels[0]); |
488 | local->hw_scan_req->ie = ies; | 518 | local->hw_scan_req->req.ie = ies; |
489 | local->hw_scan_req->flags = req->flags; | 519 | local->hw_scan_req->req.flags = req->flags; |
490 | 520 | ||
491 | local->hw_scan_band = 0; | 521 | local->hw_scan_band = 0; |
492 | 522 | ||
@@ -973,9 +1003,13 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | |||
973 | struct cfg80211_sched_scan_request *req) | 1003 | struct cfg80211_sched_scan_request *req) |
974 | { | 1004 | { |
975 | struct ieee80211_local *local = sdata->local; | 1005 | struct ieee80211_local *local = sdata->local; |
976 | struct ieee80211_sched_scan_ies sched_scan_ies = {}; | 1006 | struct ieee80211_scan_ies sched_scan_ies = {}; |
977 | struct cfg80211_chan_def chandef; | 1007 | struct cfg80211_chan_def chandef; |
978 | int ret, i, iebufsz; | 1008 | int ret, i, iebufsz, num_bands = 0; |
1009 | u32 rate_masks[IEEE80211_NUM_BANDS] = {}; | ||
1010 | u8 bands_used = 0; | ||
1011 | u8 *ie; | ||
1012 | size_t len; | ||
979 | 1013 | ||
980 | iebufsz = local->scan_ies_len + req->ie_len; | 1014 | iebufsz = local->scan_ies_len + req->ie_len; |
981 | 1015 | ||
@@ -985,33 +1019,35 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | |||
985 | return -ENOTSUPP; | 1019 | return -ENOTSUPP; |
986 | 1020 | ||
987 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | 1021 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { |
988 | if (!local->hw.wiphy->bands[i]) | 1022 | if (local->hw.wiphy->bands[i]) { |
989 | continue; | 1023 | bands_used |= BIT(i); |
990 | 1024 | rate_masks[i] = (u32) -1; | |
991 | sched_scan_ies.ie[i] = kzalloc(iebufsz, GFP_KERNEL); | 1025 | num_bands++; |
992 | if (!sched_scan_ies.ie[i]) { | ||
993 | ret = -ENOMEM; | ||
994 | goto out_free; | ||
995 | } | 1026 | } |
1027 | } | ||
996 | 1028 | ||
997 | ieee80211_prepare_scan_chandef(&chandef, req->scan_width); | 1029 | ie = kzalloc(num_bands * iebufsz, GFP_KERNEL); |
998 | 1030 | if (!ie) { | |
999 | sched_scan_ies.len[i] = | 1031 | ret = -ENOMEM; |
1000 | ieee80211_build_preq_ies(local, sched_scan_ies.ie[i], | 1032 | goto out; |
1001 | iebufsz, req->ie, req->ie_len, | ||
1002 | i, (u32) -1, &chandef); | ||
1003 | } | 1033 | } |
1004 | 1034 | ||
1035 | ieee80211_prepare_scan_chandef(&chandef, req->scan_width); | ||
1036 | |||
1037 | len = ieee80211_build_preq_ies(local, ie, num_bands * iebufsz, | ||
1038 | &sched_scan_ies, req->ie, | ||
1039 | req->ie_len, bands_used, | ||
1040 | rate_masks, &chandef); | ||
1041 | |||
1005 | ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); | 1042 | ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); |
1006 | if (ret == 0) { | 1043 | if (ret == 0) { |
1007 | rcu_assign_pointer(local->sched_scan_sdata, sdata); | 1044 | rcu_assign_pointer(local->sched_scan_sdata, sdata); |
1008 | local->sched_scan_req = req; | 1045 | local->sched_scan_req = req; |
1009 | } | 1046 | } |
1010 | 1047 | ||
1011 | out_free: | 1048 | kfree(ie); |
1012 | while (i > 0) | ||
1013 | kfree(sched_scan_ies.ie[--i]); | ||
1014 | 1049 | ||
1050 | out: | ||
1015 | if (ret) { | 1051 | if (ret) { |
1016 | /* Clean in case of failure after HW restart or upon resume. */ | 1052 | /* Clean in case of failure after HW restart or upon resume. */ |
1017 | RCU_INIT_POINTER(local->sched_scan_sdata, NULL); | 1053 | RCU_INIT_POINTER(local->sched_scan_sdata, NULL); |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a9b46d8ea22f..f41177f58b30 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -100,7 +100,8 @@ static void __cleanup_single_sta(struct sta_info *sta) | |||
100 | struct ps_data *ps; | 100 | struct ps_data *ps; |
101 | 101 | ||
102 | if (test_sta_flag(sta, WLAN_STA_PS_STA) || | 102 | if (test_sta_flag(sta, WLAN_STA_PS_STA) || |
103 | test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { | 103 | test_sta_flag(sta, WLAN_STA_PS_DRIVER) || |
104 | test_sta_flag(sta, WLAN_STA_PS_DELIVER)) { | ||
104 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || | 105 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || |
105 | sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 106 | sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
106 | ps = &sdata->bss->ps; | 107 | ps = &sdata->bss->ps; |
@@ -111,6 +112,7 @@ static void __cleanup_single_sta(struct sta_info *sta) | |||
111 | 112 | ||
112 | clear_sta_flag(sta, WLAN_STA_PS_STA); | 113 | clear_sta_flag(sta, WLAN_STA_PS_STA); |
113 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | 114 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); |
115 | clear_sta_flag(sta, WLAN_STA_PS_DELIVER); | ||
114 | 116 | ||
115 | atomic_dec(&ps->num_sta_ps); | 117 | atomic_dec(&ps->num_sta_ps); |
116 | sta_info_recalc_tim(sta); | 118 | sta_info_recalc_tim(sta); |
@@ -125,7 +127,7 @@ static void __cleanup_single_sta(struct sta_info *sta) | |||
125 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 127 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
126 | mesh_sta_cleanup(sta); | 128 | mesh_sta_cleanup(sta); |
127 | 129 | ||
128 | cancel_work_sync(&sta->drv_unblock_wk); | 130 | cancel_work_sync(&sta->drv_deliver_wk); |
129 | 131 | ||
130 | /* | 132 | /* |
131 | * Destroy aggregation state here. It would be nice to wait for the | 133 | * Destroy aggregation state here. It would be nice to wait for the |
@@ -253,33 +255,23 @@ static void sta_info_hash_add(struct ieee80211_local *local, | |||
253 | rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta); | 255 | rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta); |
254 | } | 256 | } |
255 | 257 | ||
256 | static void sta_unblock(struct work_struct *wk) | 258 | static void sta_deliver_ps_frames(struct work_struct *wk) |
257 | { | 259 | { |
258 | struct sta_info *sta; | 260 | struct sta_info *sta; |
259 | 261 | ||
260 | sta = container_of(wk, struct sta_info, drv_unblock_wk); | 262 | sta = container_of(wk, struct sta_info, drv_deliver_wk); |
261 | 263 | ||
262 | if (sta->dead) | 264 | if (sta->dead) |
263 | return; | 265 | return; |
264 | 266 | ||
265 | if (!test_sta_flag(sta, WLAN_STA_PS_STA)) { | 267 | local_bh_disable(); |
266 | local_bh_disable(); | 268 | if (!test_sta_flag(sta, WLAN_STA_PS_STA)) |
267 | ieee80211_sta_ps_deliver_wakeup(sta); | 269 | ieee80211_sta_ps_deliver_wakeup(sta); |
268 | local_bh_enable(); | 270 | else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) |
269 | } else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) { | ||
270 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
271 | |||
272 | local_bh_disable(); | ||
273 | ieee80211_sta_ps_deliver_poll_response(sta); | 271 | ieee80211_sta_ps_deliver_poll_response(sta); |
274 | local_bh_enable(); | 272 | else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD)) |
275 | } else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD)) { | ||
276 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
277 | |||
278 | local_bh_disable(); | ||
279 | ieee80211_sta_ps_deliver_uapsd(sta); | 273 | ieee80211_sta_ps_deliver_uapsd(sta); |
280 | local_bh_enable(); | 274 | local_bh_enable(); |
281 | } else | ||
282 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
283 | } | 275 | } |
284 | 276 | ||
285 | static int sta_prepare_rate_control(struct ieee80211_local *local, | 277 | static int sta_prepare_rate_control(struct ieee80211_local *local, |
@@ -341,7 +333,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
341 | 333 | ||
342 | spin_lock_init(&sta->lock); | 334 | spin_lock_init(&sta->lock); |
343 | spin_lock_init(&sta->ps_lock); | 335 | spin_lock_init(&sta->ps_lock); |
344 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); | 336 | INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames); |
345 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); | 337 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); |
346 | mutex_init(&sta->ampdu_mlme.mtx); | 338 | mutex_init(&sta->ampdu_mlme.mtx); |
347 | #ifdef CONFIG_MAC80211_MESH | 339 | #ifdef CONFIG_MAC80211_MESH |
@@ -358,7 +350,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
358 | 350 | ||
359 | sta->sta_state = IEEE80211_STA_NONE; | 351 | sta->sta_state = IEEE80211_STA_NONE; |
360 | 352 | ||
361 | do_posix_clock_monotonic_gettime(&uptime); | 353 | ktime_get_ts(&uptime); |
362 | sta->last_connected = uptime.tv_sec; | 354 | sta->last_connected = uptime.tv_sec; |
363 | ewma_init(&sta->avg_signal, 1024, 8); | 355 | ewma_init(&sta->avg_signal, 1024, 8); |
364 | for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++) | 356 | for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++) |
@@ -1141,8 +1133,15 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
1141 | } | 1133 | } |
1142 | 1134 | ||
1143 | ieee80211_add_pending_skbs(local, &pending); | 1135 | ieee80211_add_pending_skbs(local, &pending); |
1144 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | 1136 | |
1145 | clear_sta_flag(sta, WLAN_STA_PS_STA); | 1137 | /* now we're no longer in the deliver code */ |
1138 | clear_sta_flag(sta, WLAN_STA_PS_DELIVER); | ||
1139 | |||
1140 | /* The station might have polled and then woken up before we responded, | ||
1141 | * so clear these flags now to avoid them sticking around. | ||
1142 | */ | ||
1143 | clear_sta_flag(sta, WLAN_STA_PSPOLL); | ||
1144 | clear_sta_flag(sta, WLAN_STA_UAPSD); | ||
1146 | spin_unlock(&sta->ps_lock); | 1145 | spin_unlock(&sta->ps_lock); |
1147 | 1146 | ||
1148 | atomic_dec(&ps->num_sta_ps); | 1147 | atomic_dec(&ps->num_sta_ps); |
@@ -1543,10 +1542,26 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, | |||
1543 | 1542 | ||
1544 | trace_api_sta_block_awake(sta->local, pubsta, block); | 1543 | trace_api_sta_block_awake(sta->local, pubsta, block); |
1545 | 1544 | ||
1546 | if (block) | 1545 | if (block) { |
1547 | set_sta_flag(sta, WLAN_STA_PS_DRIVER); | 1546 | set_sta_flag(sta, WLAN_STA_PS_DRIVER); |
1548 | else if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) | 1547 | return; |
1549 | ieee80211_queue_work(hw, &sta->drv_unblock_wk); | 1548 | } |
1549 | |||
1550 | if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER)) | ||
1551 | return; | ||
1552 | |||
1553 | if (!test_sta_flag(sta, WLAN_STA_PS_STA)) { | ||
1554 | set_sta_flag(sta, WLAN_STA_PS_DELIVER); | ||
1555 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
1556 | ieee80211_queue_work(hw, &sta->drv_deliver_wk); | ||
1557 | } else if (test_sta_flag(sta, WLAN_STA_PSPOLL) || | ||
1558 | test_sta_flag(sta, WLAN_STA_UAPSD)) { | ||
1559 | /* must be asleep in this case */ | ||
1560 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
1561 | ieee80211_queue_work(hw, &sta->drv_deliver_wk); | ||
1562 | } else { | ||
1563 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
1564 | } | ||
1550 | } | 1565 | } |
1551 | EXPORT_SYMBOL(ieee80211_sta_block_awake); | 1566 | EXPORT_SYMBOL(ieee80211_sta_block_awake); |
1552 | 1567 | ||
@@ -1704,3 +1719,137 @@ u8 sta_info_tx_streams(struct sta_info *sta) | |||
1704 | return ((ht_cap->mcs.tx_params & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) | 1719 | return ((ht_cap->mcs.tx_params & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) |
1705 | >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1; | 1720 | >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1; |
1706 | } | 1721 | } |
1722 | |||
1723 | void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | ||
1724 | { | ||
1725 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
1726 | struct ieee80211_local *local = sdata->local; | ||
1727 | struct rate_control_ref *ref = local->rate_ctrl; | ||
1728 | struct timespec uptime; | ||
1729 | u64 packets = 0; | ||
1730 | u32 thr = 0; | ||
1731 | int i, ac; | ||
1732 | |||
1733 | sinfo->generation = sdata->local->sta_generation; | ||
1734 | |||
1735 | sinfo->filled = STATION_INFO_INACTIVE_TIME | | ||
1736 | STATION_INFO_RX_BYTES64 | | ||
1737 | STATION_INFO_TX_BYTES64 | | ||
1738 | STATION_INFO_RX_PACKETS | | ||
1739 | STATION_INFO_TX_PACKETS | | ||
1740 | STATION_INFO_TX_RETRIES | | ||
1741 | STATION_INFO_TX_FAILED | | ||
1742 | STATION_INFO_TX_BITRATE | | ||
1743 | STATION_INFO_RX_BITRATE | | ||
1744 | STATION_INFO_RX_DROP_MISC | | ||
1745 | STATION_INFO_BSS_PARAM | | ||
1746 | STATION_INFO_CONNECTED_TIME | | ||
1747 | STATION_INFO_STA_FLAGS | | ||
1748 | STATION_INFO_BEACON_LOSS_COUNT; | ||
1749 | |||
1750 | ktime_get_ts(&uptime); | ||
1751 | sinfo->connected_time = uptime.tv_sec - sta->last_connected; | ||
1752 | |||
1753 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | ||
1754 | sinfo->tx_bytes = 0; | ||
1755 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
1756 | sinfo->tx_bytes += sta->tx_bytes[ac]; | ||
1757 | packets += sta->tx_packets[ac]; | ||
1758 | } | ||
1759 | sinfo->tx_packets = packets; | ||
1760 | sinfo->rx_bytes = sta->rx_bytes; | ||
1761 | sinfo->rx_packets = sta->rx_packets; | ||
1762 | sinfo->tx_retries = sta->tx_retry_count; | ||
1763 | sinfo->tx_failed = sta->tx_retry_failed; | ||
1764 | sinfo->rx_dropped_misc = sta->rx_dropped; | ||
1765 | sinfo->beacon_loss_count = sta->beacon_loss_count; | ||
1766 | |||
1767 | if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || | ||
1768 | (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { | ||
1769 | sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; | ||
1770 | if (!local->ops->get_rssi || | ||
1771 | drv_get_rssi(local, sdata, &sta->sta, &sinfo->signal)) | ||
1772 | sinfo->signal = (s8)sta->last_signal; | ||
1773 | sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); | ||
1774 | } | ||
1775 | if (sta->chains) { | ||
1776 | sinfo->filled |= STATION_INFO_CHAIN_SIGNAL | | ||
1777 | STATION_INFO_CHAIN_SIGNAL_AVG; | ||
1778 | |||
1779 | sinfo->chains = sta->chains; | ||
1780 | for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) { | ||
1781 | sinfo->chain_signal[i] = sta->chain_signal_last[i]; | ||
1782 | sinfo->chain_signal_avg[i] = | ||
1783 | (s8) -ewma_read(&sta->chain_signal_avg[i]); | ||
1784 | } | ||
1785 | } | ||
1786 | |||
1787 | sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); | ||
1788 | sta_set_rate_info_rx(sta, &sinfo->rxrate); | ||
1789 | |||
1790 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
1791 | #ifdef CONFIG_MAC80211_MESH | ||
1792 | sinfo->filled |= STATION_INFO_LLID | | ||
1793 | STATION_INFO_PLID | | ||
1794 | STATION_INFO_PLINK_STATE | | ||
1795 | STATION_INFO_LOCAL_PM | | ||
1796 | STATION_INFO_PEER_PM | | ||
1797 | STATION_INFO_NONPEER_PM; | ||
1798 | |||
1799 | sinfo->llid = sta->llid; | ||
1800 | sinfo->plid = sta->plid; | ||
1801 | sinfo->plink_state = sta->plink_state; | ||
1802 | if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { | ||
1803 | sinfo->filled |= STATION_INFO_T_OFFSET; | ||
1804 | sinfo->t_offset = sta->t_offset; | ||
1805 | } | ||
1806 | sinfo->local_pm = sta->local_pm; | ||
1807 | sinfo->peer_pm = sta->peer_pm; | ||
1808 | sinfo->nonpeer_pm = sta->nonpeer_pm; | ||
1809 | #endif | ||
1810 | } | ||
1811 | |||
1812 | sinfo->bss_param.flags = 0; | ||
1813 | if (sdata->vif.bss_conf.use_cts_prot) | ||
1814 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT; | ||
1815 | if (sdata->vif.bss_conf.use_short_preamble) | ||
1816 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE; | ||
1817 | if (sdata->vif.bss_conf.use_short_slot) | ||
1818 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME; | ||
1819 | sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period; | ||
1820 | sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int; | ||
1821 | |||
1822 | sinfo->sta_flags.set = 0; | ||
1823 | sinfo->sta_flags.mask = BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
1824 | BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | | ||
1825 | BIT(NL80211_STA_FLAG_WME) | | ||
1826 | BIT(NL80211_STA_FLAG_MFP) | | ||
1827 | BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
1828 | BIT(NL80211_STA_FLAG_ASSOCIATED) | | ||
1829 | BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
1830 | if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) | ||
1831 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED); | ||
1832 | if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE)) | ||
1833 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); | ||
1834 | if (test_sta_flag(sta, WLAN_STA_WME)) | ||
1835 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_WME); | ||
1836 | if (test_sta_flag(sta, WLAN_STA_MFP)) | ||
1837 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP); | ||
1838 | if (test_sta_flag(sta, WLAN_STA_AUTH)) | ||
1839 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED); | ||
1840 | if (test_sta_flag(sta, WLAN_STA_ASSOC)) | ||
1841 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED); | ||
1842 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | ||
1843 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
1844 | |||
1845 | /* check if the driver has a SW RC implementation */ | ||
1846 | if (ref && ref->ops->get_expected_throughput) | ||
1847 | thr = ref->ops->get_expected_throughput(sta->rate_ctrl_priv); | ||
1848 | else | ||
1849 | thr = drv_get_expected_throughput(local, &sta->sta); | ||
1850 | |||
1851 | if (thr != 0) { | ||
1852 | sinfo->filled |= STATION_INFO_EXPECTED_THROUGHPUT; | ||
1853 | sinfo->expected_throughput = thr; | ||
1854 | } | ||
1855 | } | ||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 4acc5fc402fa..2a04361b2162 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -58,6 +58,8 @@ | |||
58 | * @WLAN_STA_TOFFSET_KNOWN: toffset calculated for this station is valid. | 58 | * @WLAN_STA_TOFFSET_KNOWN: toffset calculated for this station is valid. |
59 | * @WLAN_STA_MPSP_OWNER: local STA is owner of a mesh Peer Service Period. | 59 | * @WLAN_STA_MPSP_OWNER: local STA is owner of a mesh Peer Service Period. |
60 | * @WLAN_STA_MPSP_RECIPIENT: local STA is recipient of a MPSP. | 60 | * @WLAN_STA_MPSP_RECIPIENT: local STA is recipient of a MPSP. |
61 | * @WLAN_STA_PS_DELIVER: station woke up, but we're still blocking TX | ||
62 | * until pending frames are delivered | ||
61 | */ | 63 | */ |
62 | enum ieee80211_sta_info_flags { | 64 | enum ieee80211_sta_info_flags { |
63 | WLAN_STA_AUTH, | 65 | WLAN_STA_AUTH, |
@@ -82,6 +84,7 @@ enum ieee80211_sta_info_flags { | |||
82 | WLAN_STA_TOFFSET_KNOWN, | 84 | WLAN_STA_TOFFSET_KNOWN, |
83 | WLAN_STA_MPSP_OWNER, | 85 | WLAN_STA_MPSP_OWNER, |
84 | WLAN_STA_MPSP_RECIPIENT, | 86 | WLAN_STA_MPSP_RECIPIENT, |
87 | WLAN_STA_PS_DELIVER, | ||
85 | }; | 88 | }; |
86 | 89 | ||
87 | #define ADDBA_RESP_INTERVAL HZ | 90 | #define ADDBA_RESP_INTERVAL HZ |
@@ -265,7 +268,7 @@ struct ieee80211_tx_latency_stat { | |||
265 | * @last_rx_rate_vht_nss: rx status nss of last data packet | 268 | * @last_rx_rate_vht_nss: rx status nss of last data packet |
266 | * @lock: used for locking all fields that require locking, see comments | 269 | * @lock: used for locking all fields that require locking, see comments |
267 | * in the header file. | 270 | * in the header file. |
268 | * @drv_unblock_wk: used for driver PS unblocking | 271 | * @drv_deliver_wk: used for delivering frames after driver PS unblocking |
269 | * @listen_interval: listen interval of this station, when we're acting as AP | 272 | * @listen_interval: listen interval of this station, when we're acting as AP |
270 | * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly | 273 | * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly |
271 | * @ps_lock: used for powersave (when mac80211 is the AP) related locking | 274 | * @ps_lock: used for powersave (when mac80211 is the AP) related locking |
@@ -278,7 +281,6 @@ struct ieee80211_tx_latency_stat { | |||
278 | * @driver_buffered_tids: bitmap of TIDs the driver has data buffered on | 281 | * @driver_buffered_tids: bitmap of TIDs the driver has data buffered on |
279 | * @rx_packets: Number of MSDUs received from this STA | 282 | * @rx_packets: Number of MSDUs received from this STA |
280 | * @rx_bytes: Number of bytes received from this STA | 283 | * @rx_bytes: Number of bytes received from this STA |
281 | * @wep_weak_iv_count: number of weak WEP IVs received from this station | ||
282 | * @last_rx: time (in jiffies) when last frame was received from this STA | 284 | * @last_rx: time (in jiffies) when last frame was received from this STA |
283 | * @last_connected: time (in seconds) when a station got connected | 285 | * @last_connected: time (in seconds) when a station got connected |
284 | * @num_duplicates: number of duplicate frames received from this STA | 286 | * @num_duplicates: number of duplicate frames received from this STA |
@@ -303,7 +305,6 @@ struct ieee80211_tx_latency_stat { | |||
303 | * @plid: Peer link ID | 305 | * @plid: Peer link ID |
304 | * @reason: Cancel reason on PLINK_HOLDING state | 306 | * @reason: Cancel reason on PLINK_HOLDING state |
305 | * @plink_retries: Retries in establishment | 307 | * @plink_retries: Retries in establishment |
306 | * @ignore_plink_timer: ignore the peer-link timer (used internally) | ||
307 | * @plink_state: peer link state | 308 | * @plink_state: peer link state |
308 | * @plink_timeout: timeout of peer link | 309 | * @plink_timeout: timeout of peer link |
309 | * @plink_timer: peer link watch timer | 310 | * @plink_timer: peer link watch timer |
@@ -345,7 +346,7 @@ struct sta_info { | |||
345 | void *rate_ctrl_priv; | 346 | void *rate_ctrl_priv; |
346 | spinlock_t lock; | 347 | spinlock_t lock; |
347 | 348 | ||
348 | struct work_struct drv_unblock_wk; | 349 | struct work_struct drv_deliver_wk; |
349 | 350 | ||
350 | u16 listen_interval; | 351 | u16 listen_interval; |
351 | 352 | ||
@@ -367,7 +368,6 @@ struct sta_info { | |||
367 | /* Updated from RX path only, no locking requirements */ | 368 | /* Updated from RX path only, no locking requirements */ |
368 | unsigned long rx_packets; | 369 | unsigned long rx_packets; |
369 | u64 rx_bytes; | 370 | u64 rx_bytes; |
370 | unsigned long wep_weak_iv_count; | ||
371 | unsigned long last_rx; | 371 | unsigned long last_rx; |
372 | long last_connected; | 372 | long last_connected; |
373 | unsigned long num_duplicates; | 373 | unsigned long num_duplicates; |
@@ -418,7 +418,6 @@ struct sta_info { | |||
418 | u16 plid; | 418 | u16 plid; |
419 | u16 reason; | 419 | u16 reason; |
420 | u8 plink_retries; | 420 | u8 plink_retries; |
421 | bool ignore_plink_timer; | ||
422 | enum nl80211_plink_state plink_state; | 421 | enum nl80211_plink_state plink_state; |
423 | u32 plink_timeout; | 422 | u32 plink_timeout; |
424 | struct timer_list plink_timer; | 423 | struct timer_list plink_timer; |
@@ -628,6 +627,8 @@ void sta_set_rate_info_tx(struct sta_info *sta, | |||
628 | struct rate_info *rinfo); | 627 | struct rate_info *rinfo); |
629 | void sta_set_rate_info_rx(struct sta_info *sta, | 628 | void sta_set_rate_info_rx(struct sta_info *sta, |
630 | struct rate_info *rinfo); | 629 | struct rate_info *rinfo); |
630 | void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo); | ||
631 | |||
631 | void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, | 632 | void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, |
632 | unsigned long exp_time); | 633 | unsigned long exp_time); |
633 | u8 sta_info_tx_streams(struct sta_info *sta); | 634 | u8 sta_info_tx_streams(struct sta_info *sta); |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index ba29ebc86141..aa06dcad336e 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -473,8 +473,6 @@ static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local, | |||
473 | struct sta_info *sta, | 473 | struct sta_info *sta, |
474 | struct ieee80211_hdr *hdr) | 474 | struct ieee80211_hdr *hdr) |
475 | { | 475 | { |
476 | ktime_t skb_dprt; | ||
477 | struct timespec dprt_time; | ||
478 | u32 msrmnt; | 476 | u32 msrmnt; |
479 | u16 tid; | 477 | u16 tid; |
480 | u8 *qc; | 478 | u8 *qc; |
@@ -506,9 +504,8 @@ static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local, | |||
506 | 504 | ||
507 | tx_lat = &sta->tx_lat[tid]; | 505 | tx_lat = &sta->tx_lat[tid]; |
508 | 506 | ||
509 | ktime_get_ts(&dprt_time); /* time stamp completion time */ | 507 | /* Calculate the latency */ |
510 | skb_dprt = ktime_set(dprt_time.tv_sec, dprt_time.tv_nsec); | 508 | msrmnt = ktime_to_ms(ktime_sub(ktime_get(), skb_arv)); |
511 | msrmnt = ktime_to_ms(ktime_sub(skb_dprt, skb_arv)); | ||
512 | 509 | ||
513 | if (tx_lat->max < msrmnt) /* update stats */ | 510 | if (tx_lat->max < msrmnt) /* update stats */ |
514 | tx_lat->max = msrmnt; | 511 | tx_lat->max = msrmnt; |
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 652813b2d3df..f7185338a0fa 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c | |||
@@ -8,7 +8,30 @@ | |||
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/ieee80211.h> | 10 | #include <linux/ieee80211.h> |
11 | #include <net/cfg80211.h> | ||
11 | #include "ieee80211_i.h" | 12 | #include "ieee80211_i.h" |
13 | #include "driver-ops.h" | ||
14 | |||
15 | /* give usermode some time for retries in setting up the TDLS session */ | ||
16 | #define TDLS_PEER_SETUP_TIMEOUT (15 * HZ) | ||
17 | |||
18 | void ieee80211_tdls_peer_del_work(struct work_struct *wk) | ||
19 | { | ||
20 | struct ieee80211_sub_if_data *sdata; | ||
21 | struct ieee80211_local *local; | ||
22 | |||
23 | sdata = container_of(wk, struct ieee80211_sub_if_data, | ||
24 | tdls_peer_del_work.work); | ||
25 | local = sdata->local; | ||
26 | |||
27 | mutex_lock(&local->mtx); | ||
28 | if (!is_zero_ether_addr(sdata->tdls_peer)) { | ||
29 | tdls_dbg(sdata, "TDLS del peer %pM\n", sdata->tdls_peer); | ||
30 | sta_info_destroy_addr(sdata, sdata->tdls_peer); | ||
31 | eth_zero_addr(sdata->tdls_peer); | ||
32 | } | ||
33 | mutex_unlock(&local->mtx); | ||
34 | } | ||
12 | 35 | ||
13 | static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb) | 36 | static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb) |
14 | { | 37 | { |
@@ -168,28 +191,20 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, | |||
168 | return 0; | 191 | return 0; |
169 | } | 192 | } |
170 | 193 | ||
171 | int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | 194 | static int |
172 | const u8 *peer, u8 action_code, u8 dialog_token, | 195 | ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, |
173 | u16 status_code, u32 peer_capability, | 196 | const u8 *peer, u8 action_code, |
174 | const u8 *extra_ies, size_t extra_ies_len) | 197 | u8 dialog_token, u16 status_code, |
198 | u32 peer_capability, bool initiator, | ||
199 | const u8 *extra_ies, size_t extra_ies_len) | ||
175 | { | 200 | { |
176 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 201 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
177 | struct ieee80211_local *local = sdata->local; | 202 | struct ieee80211_local *local = sdata->local; |
178 | struct sk_buff *skb = NULL; | 203 | struct sk_buff *skb = NULL; |
179 | bool send_direct; | 204 | bool send_direct; |
205 | const u8 *init_addr, *rsp_addr; | ||
180 | int ret; | 206 | int ret; |
181 | 207 | ||
182 | if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) | ||
183 | return -ENOTSUPP; | ||
184 | |||
185 | /* make sure we are in managed mode, and associated */ | ||
186 | if (sdata->vif.type != NL80211_IFTYPE_STATION || | ||
187 | !sdata->u.mgd.associated) | ||
188 | return -EINVAL; | ||
189 | |||
190 | tdls_dbg(sdata, "TDLS mgmt action %d peer %pM\n", | ||
191 | action_code, peer); | ||
192 | |||
193 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 208 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
194 | max(sizeof(struct ieee80211_mgmt), | 209 | max(sizeof(struct ieee80211_mgmt), |
195 | sizeof(struct ieee80211_tdls_data)) + | 210 | sizeof(struct ieee80211_tdls_data)) + |
@@ -230,27 +245,42 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | |||
230 | if (extra_ies_len) | 245 | if (extra_ies_len) |
231 | memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len); | 246 | memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len); |
232 | 247 | ||
233 | /* the TDLS link IE is always added last */ | 248 | /* sanity check for initiator */ |
234 | switch (action_code) { | 249 | switch (action_code) { |
235 | case WLAN_TDLS_SETUP_REQUEST: | 250 | case WLAN_TDLS_SETUP_REQUEST: |
236 | case WLAN_TDLS_SETUP_CONFIRM: | 251 | case WLAN_TDLS_SETUP_CONFIRM: |
237 | case WLAN_TDLS_TEARDOWN: | ||
238 | case WLAN_TDLS_DISCOVERY_REQUEST: | 252 | case WLAN_TDLS_DISCOVERY_REQUEST: |
239 | /* we are the initiator */ | 253 | if (!initiator) { |
240 | ieee80211_tdls_add_link_ie(skb, sdata->vif.addr, peer, | 254 | ret = -EINVAL; |
241 | sdata->u.mgd.bssid); | 255 | goto fail; |
256 | } | ||
242 | break; | 257 | break; |
243 | case WLAN_TDLS_SETUP_RESPONSE: | 258 | case WLAN_TDLS_SETUP_RESPONSE: |
244 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | 259 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: |
245 | /* we are the responder */ | 260 | if (initiator) { |
246 | ieee80211_tdls_add_link_ie(skb, peer, sdata->vif.addr, | 261 | ret = -EINVAL; |
247 | sdata->u.mgd.bssid); | 262 | goto fail; |
263 | } | ||
264 | break; | ||
265 | case WLAN_TDLS_TEARDOWN: | ||
266 | /* any value is ok */ | ||
248 | break; | 267 | break; |
249 | default: | 268 | default: |
250 | ret = -ENOTSUPP; | 269 | ret = -ENOTSUPP; |
251 | goto fail; | 270 | goto fail; |
252 | } | 271 | } |
253 | 272 | ||
273 | if (initiator) { | ||
274 | init_addr = sdata->vif.addr; | ||
275 | rsp_addr = peer; | ||
276 | } else { | ||
277 | init_addr = peer; | ||
278 | rsp_addr = sdata->vif.addr; | ||
279 | } | ||
280 | |||
281 | ieee80211_tdls_add_link_ie(skb, init_addr, rsp_addr, | ||
282 | sdata->u.mgd.bssid); | ||
283 | |||
254 | if (send_direct) { | 284 | if (send_direct) { |
255 | ieee80211_tx_skb(sdata, skb); | 285 | ieee80211_tx_skb(sdata, skb); |
256 | return 0; | 286 | return 0; |
@@ -284,11 +314,171 @@ fail: | |||
284 | return ret; | 314 | return ret; |
285 | } | 315 | } |
286 | 316 | ||
317 | static int | ||
318 | ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, | ||
319 | const u8 *peer, u8 action_code, u8 dialog_token, | ||
320 | u16 status_code, u32 peer_capability, bool initiator, | ||
321 | const u8 *extra_ies, size_t extra_ies_len) | ||
322 | { | ||
323 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
324 | struct ieee80211_local *local = sdata->local; | ||
325 | int ret; | ||
326 | |||
327 | mutex_lock(&local->mtx); | ||
328 | |||
329 | /* we don't support concurrent TDLS peer setups */ | ||
330 | if (!is_zero_ether_addr(sdata->tdls_peer) && | ||
331 | !ether_addr_equal(sdata->tdls_peer, peer)) { | ||
332 | ret = -EBUSY; | ||
333 | goto exit; | ||
334 | } | ||
335 | |||
336 | /* | ||
337 | * make sure we have a STA representing the peer so we drop or buffer | ||
338 | * non-TDLS-setup frames to the peer. We can't send other packets | ||
339 | * during setup through the AP path | ||
340 | */ | ||
341 | rcu_read_lock(); | ||
342 | if (!sta_info_get(sdata, peer)) { | ||
343 | rcu_read_unlock(); | ||
344 | ret = -ENOLINK; | ||
345 | goto exit; | ||
346 | } | ||
347 | rcu_read_unlock(); | ||
348 | |||
349 | ieee80211_flush_queues(local, sdata); | ||
350 | |||
351 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, | ||
352 | dialog_token, status_code, | ||
353 | peer_capability, initiator, | ||
354 | extra_ies, extra_ies_len); | ||
355 | if (ret < 0) | ||
356 | goto exit; | ||
357 | |||
358 | memcpy(sdata->tdls_peer, peer, ETH_ALEN); | ||
359 | ieee80211_queue_delayed_work(&sdata->local->hw, | ||
360 | &sdata->tdls_peer_del_work, | ||
361 | TDLS_PEER_SETUP_TIMEOUT); | ||
362 | |||
363 | exit: | ||
364 | mutex_unlock(&local->mtx); | ||
365 | return ret; | ||
366 | } | ||
367 | |||
368 | static int | ||
369 | ieee80211_tdls_mgmt_teardown(struct wiphy *wiphy, struct net_device *dev, | ||
370 | const u8 *peer, u8 action_code, u8 dialog_token, | ||
371 | u16 status_code, u32 peer_capability, | ||
372 | bool initiator, const u8 *extra_ies, | ||
373 | size_t extra_ies_len) | ||
374 | { | ||
375 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
376 | struct ieee80211_local *local = sdata->local; | ||
377 | struct sta_info *sta; | ||
378 | int ret; | ||
379 | |||
380 | /* | ||
381 | * No packets can be transmitted to the peer via the AP during setup - | ||
382 | * the STA is set as a TDLS peer, but is not authorized. | ||
383 | * During teardown, we prevent direct transmissions by stopping the | ||
384 | * queues and flushing all direct packets. | ||
385 | */ | ||
386 | ieee80211_stop_vif_queues(local, sdata, | ||
387 | IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN); | ||
388 | ieee80211_flush_queues(local, sdata); | ||
389 | |||
390 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, | ||
391 | dialog_token, status_code, | ||
392 | peer_capability, initiator, | ||
393 | extra_ies, extra_ies_len); | ||
394 | if (ret < 0) | ||
395 | sdata_err(sdata, "Failed sending TDLS teardown packet %d\n", | ||
396 | ret); | ||
397 | |||
398 | /* | ||
399 | * Remove the STA AUTH flag to force further traffic through the AP. If | ||
400 | * the STA was unreachable, it was already removed. | ||
401 | */ | ||
402 | rcu_read_lock(); | ||
403 | sta = sta_info_get(sdata, peer); | ||
404 | if (sta) | ||
405 | clear_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); | ||
406 | rcu_read_unlock(); | ||
407 | |||
408 | ieee80211_wake_vif_queues(local, sdata, | ||
409 | IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN); | ||
410 | |||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | ||
415 | const u8 *peer, u8 action_code, u8 dialog_token, | ||
416 | u16 status_code, u32 peer_capability, | ||
417 | bool initiator, const u8 *extra_ies, | ||
418 | size_t extra_ies_len) | ||
419 | { | ||
420 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
421 | int ret; | ||
422 | |||
423 | if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) | ||
424 | return -ENOTSUPP; | ||
425 | |||
426 | /* make sure we are in managed mode, and associated */ | ||
427 | if (sdata->vif.type != NL80211_IFTYPE_STATION || | ||
428 | !sdata->u.mgd.associated) | ||
429 | return -EINVAL; | ||
430 | |||
431 | switch (action_code) { | ||
432 | case WLAN_TDLS_SETUP_REQUEST: | ||
433 | case WLAN_TDLS_SETUP_RESPONSE: | ||
434 | ret = ieee80211_tdls_mgmt_setup(wiphy, dev, peer, action_code, | ||
435 | dialog_token, status_code, | ||
436 | peer_capability, initiator, | ||
437 | extra_ies, extra_ies_len); | ||
438 | break; | ||
439 | case WLAN_TDLS_TEARDOWN: | ||
440 | ret = ieee80211_tdls_mgmt_teardown(wiphy, dev, peer, | ||
441 | action_code, dialog_token, | ||
442 | status_code, | ||
443 | peer_capability, initiator, | ||
444 | extra_ies, extra_ies_len); | ||
445 | break; | ||
446 | case WLAN_TDLS_DISCOVERY_REQUEST: | ||
447 | /* | ||
448 | * Protect the discovery so we can hear the TDLS discovery | ||
449 | * response frame. It is transmitted directly and not buffered | ||
450 | * by the AP. | ||
451 | */ | ||
452 | drv_mgd_protect_tdls_discover(sdata->local, sdata); | ||
453 | /* fall-through */ | ||
454 | case WLAN_TDLS_SETUP_CONFIRM: | ||
455 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | ||
456 | /* no special handling */ | ||
457 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, | ||
458 | action_code, | ||
459 | dialog_token, | ||
460 | status_code, | ||
461 | peer_capability, | ||
462 | initiator, extra_ies, | ||
463 | extra_ies_len); | ||
464 | break; | ||
465 | default: | ||
466 | ret = -EOPNOTSUPP; | ||
467 | break; | ||
468 | } | ||
469 | |||
470 | tdls_dbg(sdata, "TDLS mgmt action %d peer %pM status %d\n", | ||
471 | action_code, peer, ret); | ||
472 | return ret; | ||
473 | } | ||
474 | |||
287 | int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | 475 | int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, |
288 | const u8 *peer, enum nl80211_tdls_operation oper) | 476 | const u8 *peer, enum nl80211_tdls_operation oper) |
289 | { | 477 | { |
290 | struct sta_info *sta; | 478 | struct sta_info *sta; |
291 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 479 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
480 | struct ieee80211_local *local = sdata->local; | ||
481 | int ret; | ||
292 | 482 | ||
293 | if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) | 483 | if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) |
294 | return -ENOTSUPP; | 484 | return -ENOTSUPP; |
@@ -296,6 +486,18 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | |||
296 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 486 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
297 | return -EINVAL; | 487 | return -EINVAL; |
298 | 488 | ||
489 | switch (oper) { | ||
490 | case NL80211_TDLS_ENABLE_LINK: | ||
491 | case NL80211_TDLS_DISABLE_LINK: | ||
492 | break; | ||
493 | case NL80211_TDLS_TEARDOWN: | ||
494 | case NL80211_TDLS_SETUP: | ||
495 | case NL80211_TDLS_DISCOVERY_REQ: | ||
496 | /* We don't support in-driver setup/teardown/discovery */ | ||
497 | return -ENOTSUPP; | ||
498 | } | ||
499 | |||
500 | mutex_lock(&local->mtx); | ||
299 | tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer); | 501 | tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer); |
300 | 502 | ||
301 | switch (oper) { | 503 | switch (oper) { |
@@ -304,22 +506,49 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | |||
304 | sta = sta_info_get(sdata, peer); | 506 | sta = sta_info_get(sdata, peer); |
305 | if (!sta) { | 507 | if (!sta) { |
306 | rcu_read_unlock(); | 508 | rcu_read_unlock(); |
307 | return -ENOLINK; | 509 | ret = -ENOLINK; |
510 | break; | ||
308 | } | 511 | } |
309 | 512 | ||
310 | set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); | 513 | set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); |
311 | rcu_read_unlock(); | 514 | rcu_read_unlock(); |
515 | |||
516 | WARN_ON_ONCE(is_zero_ether_addr(sdata->tdls_peer) || | ||
517 | !ether_addr_equal(sdata->tdls_peer, peer)); | ||
518 | ret = 0; | ||
312 | break; | 519 | break; |
313 | case NL80211_TDLS_DISABLE_LINK: | 520 | case NL80211_TDLS_DISABLE_LINK: |
314 | return sta_info_destroy_addr(sdata, peer); | 521 | /* flush a potentially queued teardown packet */ |
315 | case NL80211_TDLS_TEARDOWN: | 522 | ieee80211_flush_queues(local, sdata); |
316 | case NL80211_TDLS_SETUP: | 523 | |
317 | case NL80211_TDLS_DISCOVERY_REQ: | 524 | ret = sta_info_destroy_addr(sdata, peer); |
318 | /* We don't support in-driver setup/teardown/discovery */ | 525 | break; |
319 | return -ENOTSUPP; | ||
320 | default: | 526 | default: |
321 | return -ENOTSUPP; | 527 | ret = -ENOTSUPP; |
528 | break; | ||
322 | } | 529 | } |
323 | 530 | ||
324 | return 0; | 531 | if (ret == 0 && ether_addr_equal(sdata->tdls_peer, peer)) { |
532 | cancel_delayed_work(&sdata->tdls_peer_del_work); | ||
533 | eth_zero_addr(sdata->tdls_peer); | ||
534 | } | ||
535 | |||
536 | mutex_unlock(&local->mtx); | ||
537 | return ret; | ||
538 | } | ||
539 | |||
540 | void ieee80211_tdls_oper_request(struct ieee80211_vif *vif, const u8 *peer, | ||
541 | enum nl80211_tdls_operation oper, | ||
542 | u16 reason_code, gfp_t gfp) | ||
543 | { | ||
544 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
545 | |||
546 | if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc) { | ||
547 | sdata_err(sdata, "Discarding TDLS oper %d - not STA or disconnected\n", | ||
548 | oper); | ||
549 | return; | ||
550 | } | ||
551 | |||
552 | cfg80211_tdls_oper_request(sdata->dev, peer, oper, reason_code, gfp); | ||
325 | } | 553 | } |
554 | EXPORT_SYMBOL(ieee80211_tdls_oper_request); | ||
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index cfe1a0688b5c..02ac535d1274 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -1330,6 +1330,13 @@ DEFINE_EVENT(local_sdata_evt, drv_mgd_prepare_tx, | |||
1330 | TP_ARGS(local, sdata) | 1330 | TP_ARGS(local, sdata) |
1331 | ); | 1331 | ); |
1332 | 1332 | ||
1333 | DEFINE_EVENT(local_sdata_evt, drv_mgd_protect_tdls_discover, | ||
1334 | TP_PROTO(struct ieee80211_local *local, | ||
1335 | struct ieee80211_sub_if_data *sdata), | ||
1336 | |||
1337 | TP_ARGS(local, sdata) | ||
1338 | ); | ||
1339 | |||
1333 | DECLARE_EVENT_CLASS(local_chanctx, | 1340 | DECLARE_EVENT_CLASS(local_chanctx, |
1334 | TP_PROTO(struct ieee80211_local *local, | 1341 | TP_PROTO(struct ieee80211_local *local, |
1335 | struct ieee80211_chanctx *ctx), | 1342 | struct ieee80211_chanctx *ctx), |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 5214686d9fd1..865bdaf06ff1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -250,7 +250,8 @@ ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx) | |||
250 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | 250 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { |
251 | ieee80211_stop_queues_by_reason(&local->hw, | 251 | ieee80211_stop_queues_by_reason(&local->hw, |
252 | IEEE80211_MAX_QUEUE_MAP, | 252 | IEEE80211_MAX_QUEUE_MAP, |
253 | IEEE80211_QUEUE_STOP_REASON_PS); | 253 | IEEE80211_QUEUE_STOP_REASON_PS, |
254 | false); | ||
254 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; | 255 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; |
255 | ieee80211_queue_work(&local->hw, | 256 | ieee80211_queue_work(&local->hw, |
256 | &local->dynamic_ps_disable_work); | 257 | &local->dynamic_ps_disable_work); |
@@ -469,7 +470,8 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) | |||
469 | return TX_CONTINUE; | 470 | return TX_CONTINUE; |
470 | 471 | ||
471 | if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) || | 472 | if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) || |
472 | test_sta_flag(sta, WLAN_STA_PS_DRIVER)) && | 473 | test_sta_flag(sta, WLAN_STA_PS_DRIVER) || |
474 | test_sta_flag(sta, WLAN_STA_PS_DELIVER)) && | ||
473 | !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) { | 475 | !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) { |
474 | int ac = skb_get_queue_mapping(tx->skb); | 476 | int ac = skb_get_queue_mapping(tx->skb); |
475 | 477 | ||
@@ -486,7 +488,8 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) | |||
486 | * ahead and Tx the packet. | 488 | * ahead and Tx the packet. |
487 | */ | 489 | */ |
488 | if (!test_sta_flag(sta, WLAN_STA_PS_STA) && | 490 | if (!test_sta_flag(sta, WLAN_STA_PS_STA) && |
489 | !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { | 491 | !test_sta_flag(sta, WLAN_STA_PS_DRIVER) && |
492 | !test_sta_flag(sta, WLAN_STA_PS_DELIVER)) { | ||
490 | spin_unlock(&sta->ps_lock); | 493 | spin_unlock(&sta->ps_lock); |
491 | return TX_CONTINUE; | 494 | return TX_CONTINUE; |
492 | } | 495 | } |
@@ -1618,12 +1621,12 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
1618 | { | 1621 | { |
1619 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1622 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1620 | struct ieee80211_chanctx_conf *chanctx_conf; | 1623 | struct ieee80211_chanctx_conf *chanctx_conf; |
1621 | struct ieee80211_channel *chan; | ||
1622 | struct ieee80211_radiotap_header *prthdr = | 1624 | struct ieee80211_radiotap_header *prthdr = |
1623 | (struct ieee80211_radiotap_header *)skb->data; | 1625 | (struct ieee80211_radiotap_header *)skb->data; |
1624 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1626 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1625 | struct ieee80211_hdr *hdr; | 1627 | struct ieee80211_hdr *hdr; |
1626 | struct ieee80211_sub_if_data *tmp_sdata, *sdata; | 1628 | struct ieee80211_sub_if_data *tmp_sdata, *sdata; |
1629 | struct cfg80211_chan_def *chandef; | ||
1627 | u16 len_rthdr; | 1630 | u16 len_rthdr; |
1628 | int hdrlen; | 1631 | int hdrlen; |
1629 | 1632 | ||
@@ -1721,9 +1724,9 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
1721 | } | 1724 | } |
1722 | 1725 | ||
1723 | if (chanctx_conf) | 1726 | if (chanctx_conf) |
1724 | chan = chanctx_conf->def.chan; | 1727 | chandef = &chanctx_conf->def; |
1725 | else if (!local->use_chanctx) | 1728 | else if (!local->use_chanctx) |
1726 | chan = local->_oper_chandef.chan; | 1729 | chandef = &local->_oper_chandef; |
1727 | else | 1730 | else |
1728 | goto fail_rcu; | 1731 | goto fail_rcu; |
1729 | 1732 | ||
@@ -1743,10 +1746,11 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
1743 | * radar detection by itself. We can do that later by adding a | 1746 | * radar detection by itself. We can do that later by adding a |
1744 | * monitor flag interfaces used for AP support. | 1747 | * monitor flag interfaces used for AP support. |
1745 | */ | 1748 | */ |
1746 | if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR))) | 1749 | if (!cfg80211_reg_can_beacon(local->hw.wiphy, chandef, |
1750 | sdata->vif.type)) | ||
1747 | goto fail_rcu; | 1751 | goto fail_rcu; |
1748 | 1752 | ||
1749 | ieee80211_xmit(sdata, skb, chan->band); | 1753 | ieee80211_xmit(sdata, skb, chandef->chan->band); |
1750 | rcu_read_unlock(); | 1754 | rcu_read_unlock(); |
1751 | 1755 | ||
1752 | return NETDEV_TX_OK; | 1756 | return NETDEV_TX_OK; |
@@ -1767,15 +1771,12 @@ fail: | |||
1767 | static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local, | 1771 | static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local, |
1768 | struct sk_buff *skb) | 1772 | struct sk_buff *skb) |
1769 | { | 1773 | { |
1770 | struct timespec skb_arv; | ||
1771 | struct ieee80211_tx_latency_bin_ranges *tx_latency; | 1774 | struct ieee80211_tx_latency_bin_ranges *tx_latency; |
1772 | 1775 | ||
1773 | tx_latency = rcu_dereference(local->tx_latency); | 1776 | tx_latency = rcu_dereference(local->tx_latency); |
1774 | if (!tx_latency) | 1777 | if (!tx_latency) |
1775 | return; | 1778 | return; |
1776 | 1779 | skb->tstamp = ktime_get(); | |
1777 | ktime_get_ts(&skb_arv); | ||
1778 | skb->tstamp = ktime_set(skb_arv.tv_sec, skb_arv.tv_nsec); | ||
1779 | } | 1780 | } |
1780 | 1781 | ||
1781 | /** | 1782 | /** |
@@ -1810,7 +1811,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1810 | int nh_pos, h_pos; | 1811 | int nh_pos, h_pos; |
1811 | struct sta_info *sta = NULL; | 1812 | struct sta_info *sta = NULL; |
1812 | bool wme_sta = false, authorized = false, tdls_auth = false; | 1813 | bool wme_sta = false, authorized = false, tdls_auth = false; |
1813 | bool tdls_direct = false; | 1814 | bool tdls_peer = false, tdls_setup_frame = false; |
1814 | bool multicast; | 1815 | bool multicast; |
1815 | u32 info_flags = 0; | 1816 | u32 info_flags = 0; |
1816 | u16 info_id = 0; | 1817 | u16 info_id = 0; |
@@ -1952,34 +1953,35 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1952 | #endif | 1953 | #endif |
1953 | case NL80211_IFTYPE_STATION: | 1954 | case NL80211_IFTYPE_STATION: |
1954 | if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { | 1955 | if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { |
1955 | bool tdls_peer = false; | ||
1956 | |||
1957 | sta = sta_info_get(sdata, skb->data); | 1956 | sta = sta_info_get(sdata, skb->data); |
1958 | if (sta) { | 1957 | if (sta) { |
1959 | authorized = test_sta_flag(sta, | 1958 | authorized = test_sta_flag(sta, |
1960 | WLAN_STA_AUTHORIZED); | 1959 | WLAN_STA_AUTHORIZED); |
1961 | wme_sta = test_sta_flag(sta, WLAN_STA_WME); | 1960 | wme_sta = test_sta_flag(sta, WLAN_STA_WME); |
1962 | tdls_peer = test_sta_flag(sta, | 1961 | tdls_peer = test_sta_flag(sta, |
1963 | WLAN_STA_TDLS_PEER); | 1962 | WLAN_STA_TDLS_PEER); |
1964 | tdls_auth = test_sta_flag(sta, | 1963 | tdls_auth = test_sta_flag(sta, |
1965 | WLAN_STA_TDLS_PEER_AUTH); | 1964 | WLAN_STA_TDLS_PEER_AUTH); |
1966 | } | 1965 | } |
1967 | 1966 | ||
1968 | /* | 1967 | if (tdls_peer) |
1969 | * If the TDLS link is enabled, send everything | 1968 | tdls_setup_frame = |
1970 | * directly. Otherwise, allow TDLS setup frames | 1969 | ethertype == ETH_P_TDLS && |
1971 | * to be transmitted indirectly. | 1970 | skb->len > 14 && |
1972 | */ | 1971 | skb->data[14] == WLAN_TDLS_SNAP_RFTYPE; |
1973 | tdls_direct = tdls_peer && (tdls_auth || | ||
1974 | !(ethertype == ETH_P_TDLS && skb->len > 14 && | ||
1975 | skb->data[14] == WLAN_TDLS_SNAP_RFTYPE)); | ||
1976 | } | 1972 | } |
1977 | 1973 | ||
1978 | if (tdls_direct) { | 1974 | /* |
1979 | /* link during setup - throw out frames to peer */ | 1975 | * TDLS link during setup - throw out frames to peer. We allow |
1980 | if (!tdls_auth) | 1976 | * TDLS-setup frames to unauthorized peers for the special case |
1981 | goto fail_rcu; | 1977 | * of a link teardown after a TDLS sta is removed due to being |
1978 | * unreachable. | ||
1979 | */ | ||
1980 | if (tdls_peer && !tdls_auth && !tdls_setup_frame) | ||
1981 | goto fail_rcu; | ||
1982 | 1982 | ||
1983 | /* send direct packets to authorized TDLS peers */ | ||
1984 | if (tdls_peer && tdls_auth) { | ||
1983 | /* DA SA BSSID */ | 1985 | /* DA SA BSSID */ |
1984 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 1986 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
1985 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | 1987 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); |
@@ -2423,7 +2425,7 @@ static void ieee80211_set_csa(struct ieee80211_sub_if_data *sdata, | |||
2423 | u8 *beacon_data; | 2425 | u8 *beacon_data; |
2424 | size_t beacon_data_len; | 2426 | size_t beacon_data_len; |
2425 | int i; | 2427 | int i; |
2426 | u8 count = sdata->csa_current_counter; | 2428 | u8 count = beacon->csa_current_counter; |
2427 | 2429 | ||
2428 | switch (sdata->vif.type) { | 2430 | switch (sdata->vif.type) { |
2429 | case NL80211_IFTYPE_AP: | 2431 | case NL80211_IFTYPE_AP: |
@@ -2442,46 +2444,53 @@ static void ieee80211_set_csa(struct ieee80211_sub_if_data *sdata, | |||
2442 | return; | 2444 | return; |
2443 | } | 2445 | } |
2444 | 2446 | ||
2447 | rcu_read_lock(); | ||
2445 | for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; ++i) { | 2448 | for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; ++i) { |
2446 | u16 counter_offset_beacon = | 2449 | resp = rcu_dereference(sdata->u.ap.probe_resp); |
2447 | sdata->csa_counter_offset_beacon[i]; | ||
2448 | u16 counter_offset_presp = sdata->csa_counter_offset_presp[i]; | ||
2449 | 2450 | ||
2450 | if (counter_offset_beacon) { | 2451 | if (beacon->csa_counter_offsets[i]) { |
2451 | if (WARN_ON(counter_offset_beacon >= beacon_data_len)) | 2452 | if (WARN_ON_ONCE(beacon->csa_counter_offsets[i] >= |
2452 | return; | 2453 | beacon_data_len)) { |
2453 | |||
2454 | beacon_data[counter_offset_beacon] = count; | ||
2455 | } | ||
2456 | |||
2457 | if (sdata->vif.type == NL80211_IFTYPE_AP && | ||
2458 | counter_offset_presp) { | ||
2459 | rcu_read_lock(); | ||
2460 | resp = rcu_dereference(sdata->u.ap.probe_resp); | ||
2461 | |||
2462 | /* If nl80211 accepted the offset, this should | ||
2463 | * not happen. | ||
2464 | */ | ||
2465 | if (WARN_ON(!resp)) { | ||
2466 | rcu_read_unlock(); | 2454 | rcu_read_unlock(); |
2467 | return; | 2455 | return; |
2468 | } | 2456 | } |
2469 | resp->data[counter_offset_presp] = count; | 2457 | |
2470 | rcu_read_unlock(); | 2458 | beacon_data[beacon->csa_counter_offsets[i]] = count; |
2471 | } | 2459 | } |
2460 | |||
2461 | if (sdata->vif.type == NL80211_IFTYPE_AP && resp) | ||
2462 | resp->data[resp->csa_counter_offsets[i]] = count; | ||
2472 | } | 2463 | } |
2464 | rcu_read_unlock(); | ||
2473 | } | 2465 | } |
2474 | 2466 | ||
2475 | u8 ieee80211_csa_update_counter(struct ieee80211_vif *vif) | 2467 | u8 ieee80211_csa_update_counter(struct ieee80211_vif *vif) |
2476 | { | 2468 | { |
2477 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 2469 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); |
2470 | struct beacon_data *beacon = NULL; | ||
2471 | u8 count = 0; | ||
2472 | |||
2473 | rcu_read_lock(); | ||
2478 | 2474 | ||
2479 | sdata->csa_current_counter--; | 2475 | if (sdata->vif.type == NL80211_IFTYPE_AP) |
2476 | beacon = rcu_dereference(sdata->u.ap.beacon); | ||
2477 | else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
2478 | beacon = rcu_dereference(sdata->u.ibss.presp); | ||
2479 | else if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
2480 | beacon = rcu_dereference(sdata->u.mesh.beacon); | ||
2481 | |||
2482 | if (!beacon) | ||
2483 | goto unlock; | ||
2484 | |||
2485 | beacon->csa_current_counter--; | ||
2480 | 2486 | ||
2481 | /* the counter should never reach 0 */ | 2487 | /* the counter should never reach 0 */ |
2482 | WARN_ON(!sdata->csa_current_counter); | 2488 | WARN_ON_ONCE(!beacon->csa_current_counter); |
2489 | count = beacon->csa_current_counter; | ||
2483 | 2490 | ||
2484 | return sdata->csa_current_counter; | 2491 | unlock: |
2492 | rcu_read_unlock(); | ||
2493 | return count; | ||
2485 | } | 2494 | } |
2486 | EXPORT_SYMBOL(ieee80211_csa_update_counter); | 2495 | EXPORT_SYMBOL(ieee80211_csa_update_counter); |
2487 | 2496 | ||
@@ -2491,7 +2500,6 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) | |||
2491 | struct beacon_data *beacon = NULL; | 2500 | struct beacon_data *beacon = NULL; |
2492 | u8 *beacon_data; | 2501 | u8 *beacon_data; |
2493 | size_t beacon_data_len; | 2502 | size_t beacon_data_len; |
2494 | int counter_beacon = sdata->csa_counter_offset_beacon[0]; | ||
2495 | int ret = false; | 2503 | int ret = false; |
2496 | 2504 | ||
2497 | if (!ieee80211_sdata_running(sdata)) | 2505 | if (!ieee80211_sdata_running(sdata)) |
@@ -2529,10 +2537,13 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) | |||
2529 | goto out; | 2537 | goto out; |
2530 | } | 2538 | } |
2531 | 2539 | ||
2532 | if (WARN_ON(counter_beacon > beacon_data_len)) | 2540 | if (!beacon->csa_counter_offsets[0]) |
2533 | goto out; | 2541 | goto out; |
2534 | 2542 | ||
2535 | if (beacon_data[counter_beacon] == 1) | 2543 | if (WARN_ON_ONCE(beacon->csa_counter_offsets[0] > beacon_data_len)) |
2544 | goto out; | ||
2545 | |||
2546 | if (beacon_data[beacon->csa_counter_offsets[0]] == 1) | ||
2536 | ret = true; | 2547 | ret = true; |
2537 | out: | 2548 | out: |
2538 | rcu_read_unlock(); | 2549 | rcu_read_unlock(); |
@@ -2548,6 +2559,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
2548 | bool is_template) | 2559 | bool is_template) |
2549 | { | 2560 | { |
2550 | struct ieee80211_local *local = hw_to_local(hw); | 2561 | struct ieee80211_local *local = hw_to_local(hw); |
2562 | struct beacon_data *beacon = NULL; | ||
2551 | struct sk_buff *skb = NULL; | 2563 | struct sk_buff *skb = NULL; |
2552 | struct ieee80211_tx_info *info; | 2564 | struct ieee80211_tx_info *info; |
2553 | struct ieee80211_sub_if_data *sdata = NULL; | 2565 | struct ieee80211_sub_if_data *sdata = NULL; |
@@ -2569,10 +2581,10 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
2569 | 2581 | ||
2570 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 2582 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
2571 | struct ieee80211_if_ap *ap = &sdata->u.ap; | 2583 | struct ieee80211_if_ap *ap = &sdata->u.ap; |
2572 | struct beacon_data *beacon = rcu_dereference(ap->beacon); | ||
2573 | 2584 | ||
2585 | beacon = rcu_dereference(ap->beacon); | ||
2574 | if (beacon) { | 2586 | if (beacon) { |
2575 | if (sdata->vif.csa_active) { | 2587 | if (beacon->csa_counter_offsets[0]) { |
2576 | if (!is_template) | 2588 | if (!is_template) |
2577 | ieee80211_csa_update_counter(vif); | 2589 | ieee80211_csa_update_counter(vif); |
2578 | 2590 | ||
@@ -2613,37 +2625,37 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
2613 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 2625 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
2614 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 2626 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
2615 | struct ieee80211_hdr *hdr; | 2627 | struct ieee80211_hdr *hdr; |
2616 | struct beacon_data *presp = rcu_dereference(ifibss->presp); | ||
2617 | 2628 | ||
2618 | if (!presp) | 2629 | beacon = rcu_dereference(ifibss->presp); |
2630 | if (!beacon) | ||
2619 | goto out; | 2631 | goto out; |
2620 | 2632 | ||
2621 | if (sdata->vif.csa_active) { | 2633 | if (beacon->csa_counter_offsets[0]) { |
2622 | if (!is_template) | 2634 | if (!is_template) |
2623 | ieee80211_csa_update_counter(vif); | 2635 | ieee80211_csa_update_counter(vif); |
2624 | 2636 | ||
2625 | ieee80211_set_csa(sdata, presp); | 2637 | ieee80211_set_csa(sdata, beacon); |
2626 | } | 2638 | } |
2627 | 2639 | ||
2628 | skb = dev_alloc_skb(local->tx_headroom + presp->head_len + | 2640 | skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + |
2629 | local->hw.extra_beacon_tailroom); | 2641 | local->hw.extra_beacon_tailroom); |
2630 | if (!skb) | 2642 | if (!skb) |
2631 | goto out; | 2643 | goto out; |
2632 | skb_reserve(skb, local->tx_headroom); | 2644 | skb_reserve(skb, local->tx_headroom); |
2633 | memcpy(skb_put(skb, presp->head_len), presp->head, | 2645 | memcpy(skb_put(skb, beacon->head_len), beacon->head, |
2634 | presp->head_len); | 2646 | beacon->head_len); |
2635 | 2647 | ||
2636 | hdr = (struct ieee80211_hdr *) skb->data; | 2648 | hdr = (struct ieee80211_hdr *) skb->data; |
2637 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 2649 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
2638 | IEEE80211_STYPE_BEACON); | 2650 | IEEE80211_STYPE_BEACON); |
2639 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 2651 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { |
2640 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 2652 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
2641 | struct beacon_data *bcn = rcu_dereference(ifmsh->beacon); | ||
2642 | 2653 | ||
2643 | if (!bcn) | 2654 | beacon = rcu_dereference(ifmsh->beacon); |
2655 | if (!beacon) | ||
2644 | goto out; | 2656 | goto out; |
2645 | 2657 | ||
2646 | if (sdata->vif.csa_active) { | 2658 | if (beacon->csa_counter_offsets[0]) { |
2647 | if (!is_template) | 2659 | if (!is_template) |
2648 | /* TODO: For mesh csa_counter is in TU, so | 2660 | /* TODO: For mesh csa_counter is in TU, so |
2649 | * decrementing it by one isn't correct, but | 2661 | * decrementing it by one isn't correct, but |
@@ -2652,40 +2664,42 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
2652 | */ | 2664 | */ |
2653 | ieee80211_csa_update_counter(vif); | 2665 | ieee80211_csa_update_counter(vif); |
2654 | 2666 | ||
2655 | ieee80211_set_csa(sdata, bcn); | 2667 | ieee80211_set_csa(sdata, beacon); |
2656 | } | 2668 | } |
2657 | 2669 | ||
2658 | if (ifmsh->sync_ops) | 2670 | if (ifmsh->sync_ops) |
2659 | ifmsh->sync_ops->adjust_tbtt(sdata, bcn); | 2671 | ifmsh->sync_ops->adjust_tbtt(sdata, beacon); |
2660 | 2672 | ||
2661 | skb = dev_alloc_skb(local->tx_headroom + | 2673 | skb = dev_alloc_skb(local->tx_headroom + |
2662 | bcn->head_len + | 2674 | beacon->head_len + |
2663 | 256 + /* TIM IE */ | 2675 | 256 + /* TIM IE */ |
2664 | bcn->tail_len + | 2676 | beacon->tail_len + |
2665 | local->hw.extra_beacon_tailroom); | 2677 | local->hw.extra_beacon_tailroom); |
2666 | if (!skb) | 2678 | if (!skb) |
2667 | goto out; | 2679 | goto out; |
2668 | skb_reserve(skb, local->tx_headroom); | 2680 | skb_reserve(skb, local->tx_headroom); |
2669 | memcpy(skb_put(skb, bcn->head_len), bcn->head, bcn->head_len); | 2681 | memcpy(skb_put(skb, beacon->head_len), beacon->head, |
2682 | beacon->head_len); | ||
2670 | ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb, is_template); | 2683 | ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb, is_template); |
2671 | 2684 | ||
2672 | if (offs) { | 2685 | if (offs) { |
2673 | offs->tim_offset = bcn->head_len; | 2686 | offs->tim_offset = beacon->head_len; |
2674 | offs->tim_length = skb->len - bcn->head_len; | 2687 | offs->tim_length = skb->len - beacon->head_len; |
2675 | } | 2688 | } |
2676 | 2689 | ||
2677 | memcpy(skb_put(skb, bcn->tail_len), bcn->tail, bcn->tail_len); | 2690 | memcpy(skb_put(skb, beacon->tail_len), beacon->tail, |
2691 | beacon->tail_len); | ||
2678 | } else { | 2692 | } else { |
2679 | WARN_ON(1); | 2693 | WARN_ON(1); |
2680 | goto out; | 2694 | goto out; |
2681 | } | 2695 | } |
2682 | 2696 | ||
2683 | /* CSA offsets */ | 2697 | /* CSA offsets */ |
2684 | if (offs) { | 2698 | if (offs && beacon) { |
2685 | int i; | 2699 | int i; |
2686 | 2700 | ||
2687 | for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; i++) { | 2701 | for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; i++) { |
2688 | u16 csa_off = sdata->csa_counter_offset_beacon[i]; | 2702 | u16 csa_off = beacon->csa_counter_offsets[i]; |
2689 | 2703 | ||
2690 | if (!csa_off) | 2704 | if (!csa_off) |
2691 | continue; | 2705 | continue; |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 6886601afe1c..ea79668c2e5f 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -317,7 +317,8 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) | |||
317 | } | 317 | } |
318 | 318 | ||
319 | static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | 319 | static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, |
320 | enum queue_stop_reason reason) | 320 | enum queue_stop_reason reason, |
321 | bool refcounted) | ||
321 | { | 322 | { |
322 | struct ieee80211_local *local = hw_to_local(hw); | 323 | struct ieee80211_local *local = hw_to_local(hw); |
323 | 324 | ||
@@ -329,7 +330,13 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
329 | if (!test_bit(reason, &local->queue_stop_reasons[queue])) | 330 | if (!test_bit(reason, &local->queue_stop_reasons[queue])) |
330 | return; | 331 | return; |
331 | 332 | ||
332 | __clear_bit(reason, &local->queue_stop_reasons[queue]); | 333 | if (!refcounted) |
334 | local->q_stop_reasons[queue][reason] = 0; | ||
335 | else | ||
336 | local->q_stop_reasons[queue][reason]--; | ||
337 | |||
338 | if (local->q_stop_reasons[queue][reason] == 0) | ||
339 | __clear_bit(reason, &local->queue_stop_reasons[queue]); | ||
333 | 340 | ||
334 | if (local->queue_stop_reasons[queue] != 0) | 341 | if (local->queue_stop_reasons[queue] != 0) |
335 | /* someone still has this queue stopped */ | 342 | /* someone still has this queue stopped */ |
@@ -344,25 +351,28 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
344 | } | 351 | } |
345 | 352 | ||
346 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, | 353 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, |
347 | enum queue_stop_reason reason) | 354 | enum queue_stop_reason reason, |
355 | bool refcounted) | ||
348 | { | 356 | { |
349 | struct ieee80211_local *local = hw_to_local(hw); | 357 | struct ieee80211_local *local = hw_to_local(hw); |
350 | unsigned long flags; | 358 | unsigned long flags; |
351 | 359 | ||
352 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 360 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
353 | __ieee80211_wake_queue(hw, queue, reason); | 361 | __ieee80211_wake_queue(hw, queue, reason, refcounted); |
354 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 362 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
355 | } | 363 | } |
356 | 364 | ||
357 | void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) | 365 | void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) |
358 | { | 366 | { |
359 | ieee80211_wake_queue_by_reason(hw, queue, | 367 | ieee80211_wake_queue_by_reason(hw, queue, |
360 | IEEE80211_QUEUE_STOP_REASON_DRIVER); | 368 | IEEE80211_QUEUE_STOP_REASON_DRIVER, |
369 | false); | ||
361 | } | 370 | } |
362 | EXPORT_SYMBOL(ieee80211_wake_queue); | 371 | EXPORT_SYMBOL(ieee80211_wake_queue); |
363 | 372 | ||
364 | static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | 373 | static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, |
365 | enum queue_stop_reason reason) | 374 | enum queue_stop_reason reason, |
375 | bool refcounted) | ||
366 | { | 376 | { |
367 | struct ieee80211_local *local = hw_to_local(hw); | 377 | struct ieee80211_local *local = hw_to_local(hw); |
368 | struct ieee80211_sub_if_data *sdata; | 378 | struct ieee80211_sub_if_data *sdata; |
@@ -373,10 +383,13 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
373 | if (WARN_ON(queue >= hw->queues)) | 383 | if (WARN_ON(queue >= hw->queues)) |
374 | return; | 384 | return; |
375 | 385 | ||
376 | if (test_bit(reason, &local->queue_stop_reasons[queue])) | 386 | if (!refcounted) |
377 | return; | 387 | local->q_stop_reasons[queue][reason] = 1; |
388 | else | ||
389 | local->q_stop_reasons[queue][reason]++; | ||
378 | 390 | ||
379 | __set_bit(reason, &local->queue_stop_reasons[queue]); | 391 | if (__test_and_set_bit(reason, &local->queue_stop_reasons[queue])) |
392 | return; | ||
380 | 393 | ||
381 | if (local->hw.queues < IEEE80211_NUM_ACS) | 394 | if (local->hw.queues < IEEE80211_NUM_ACS) |
382 | n_acs = 1; | 395 | n_acs = 1; |
@@ -398,20 +411,22 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
398 | } | 411 | } |
399 | 412 | ||
400 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, | 413 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, |
401 | enum queue_stop_reason reason) | 414 | enum queue_stop_reason reason, |
415 | bool refcounted) | ||
402 | { | 416 | { |
403 | struct ieee80211_local *local = hw_to_local(hw); | 417 | struct ieee80211_local *local = hw_to_local(hw); |
404 | unsigned long flags; | 418 | unsigned long flags; |
405 | 419 | ||
406 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 420 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
407 | __ieee80211_stop_queue(hw, queue, reason); | 421 | __ieee80211_stop_queue(hw, queue, reason, refcounted); |
408 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 422 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
409 | } | 423 | } |
410 | 424 | ||
411 | void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) | 425 | void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) |
412 | { | 426 | { |
413 | ieee80211_stop_queue_by_reason(hw, queue, | 427 | ieee80211_stop_queue_by_reason(hw, queue, |
414 | IEEE80211_QUEUE_STOP_REASON_DRIVER); | 428 | IEEE80211_QUEUE_STOP_REASON_DRIVER, |
429 | false); | ||
415 | } | 430 | } |
416 | EXPORT_SYMBOL(ieee80211_stop_queue); | 431 | EXPORT_SYMBOL(ieee80211_stop_queue); |
417 | 432 | ||
@@ -429,9 +444,11 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, | |||
429 | } | 444 | } |
430 | 445 | ||
431 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 446 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
432 | __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | 447 | __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD, |
448 | false); | ||
433 | __skb_queue_tail(&local->pending[queue], skb); | 449 | __skb_queue_tail(&local->pending[queue], skb); |
434 | __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | 450 | __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD, |
451 | false); | ||
435 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 452 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
436 | } | 453 | } |
437 | 454 | ||
@@ -455,20 +472,23 @@ void ieee80211_add_pending_skbs(struct ieee80211_local *local, | |||
455 | queue = info->hw_queue; | 472 | queue = info->hw_queue; |
456 | 473 | ||
457 | __ieee80211_stop_queue(hw, queue, | 474 | __ieee80211_stop_queue(hw, queue, |
458 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | 475 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD, |
476 | false); | ||
459 | 477 | ||
460 | __skb_queue_tail(&local->pending[queue], skb); | 478 | __skb_queue_tail(&local->pending[queue], skb); |
461 | } | 479 | } |
462 | 480 | ||
463 | for (i = 0; i < hw->queues; i++) | 481 | for (i = 0; i < hw->queues; i++) |
464 | __ieee80211_wake_queue(hw, i, | 482 | __ieee80211_wake_queue(hw, i, |
465 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | 483 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD, |
484 | false); | ||
466 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 485 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
467 | } | 486 | } |
468 | 487 | ||
469 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | 488 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, |
470 | unsigned long queues, | 489 | unsigned long queues, |
471 | enum queue_stop_reason reason) | 490 | enum queue_stop_reason reason, |
491 | bool refcounted) | ||
472 | { | 492 | { |
473 | struct ieee80211_local *local = hw_to_local(hw); | 493 | struct ieee80211_local *local = hw_to_local(hw); |
474 | unsigned long flags; | 494 | unsigned long flags; |
@@ -477,7 +497,7 @@ void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | |||
477 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 497 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
478 | 498 | ||
479 | for_each_set_bit(i, &queues, hw->queues) | 499 | for_each_set_bit(i, &queues, hw->queues) |
480 | __ieee80211_stop_queue(hw, i, reason); | 500 | __ieee80211_stop_queue(hw, i, reason, refcounted); |
481 | 501 | ||
482 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 502 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
483 | } | 503 | } |
@@ -485,7 +505,8 @@ void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | |||
485 | void ieee80211_stop_queues(struct ieee80211_hw *hw) | 505 | void ieee80211_stop_queues(struct ieee80211_hw *hw) |
486 | { | 506 | { |
487 | ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, | 507 | ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, |
488 | IEEE80211_QUEUE_STOP_REASON_DRIVER); | 508 | IEEE80211_QUEUE_STOP_REASON_DRIVER, |
509 | false); | ||
489 | } | 510 | } |
490 | EXPORT_SYMBOL(ieee80211_stop_queues); | 511 | EXPORT_SYMBOL(ieee80211_stop_queues); |
491 | 512 | ||
@@ -508,7 +529,8 @@ EXPORT_SYMBOL(ieee80211_queue_stopped); | |||
508 | 529 | ||
509 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | 530 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, |
510 | unsigned long queues, | 531 | unsigned long queues, |
511 | enum queue_stop_reason reason) | 532 | enum queue_stop_reason reason, |
533 | bool refcounted) | ||
512 | { | 534 | { |
513 | struct ieee80211_local *local = hw_to_local(hw); | 535 | struct ieee80211_local *local = hw_to_local(hw); |
514 | unsigned long flags; | 536 | unsigned long flags; |
@@ -517,7 +539,7 @@ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | |||
517 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 539 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
518 | 540 | ||
519 | for_each_set_bit(i, &queues, hw->queues) | 541 | for_each_set_bit(i, &queues, hw->queues) |
520 | __ieee80211_wake_queue(hw, i, reason); | 542 | __ieee80211_wake_queue(hw, i, reason, refcounted); |
521 | 543 | ||
522 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 544 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
523 | } | 545 | } |
@@ -525,17 +547,16 @@ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | |||
525 | void ieee80211_wake_queues(struct ieee80211_hw *hw) | 547 | void ieee80211_wake_queues(struct ieee80211_hw *hw) |
526 | { | 548 | { |
527 | ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, | 549 | ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, |
528 | IEEE80211_QUEUE_STOP_REASON_DRIVER); | 550 | IEEE80211_QUEUE_STOP_REASON_DRIVER, |
551 | false); | ||
529 | } | 552 | } |
530 | EXPORT_SYMBOL(ieee80211_wake_queues); | 553 | EXPORT_SYMBOL(ieee80211_wake_queues); |
531 | 554 | ||
532 | void ieee80211_flush_queues(struct ieee80211_local *local, | 555 | static unsigned int |
533 | struct ieee80211_sub_if_data *sdata) | 556 | ieee80211_get_vif_queues(struct ieee80211_local *local, |
557 | struct ieee80211_sub_if_data *sdata) | ||
534 | { | 558 | { |
535 | u32 queues; | 559 | unsigned int queues; |
536 | |||
537 | if (!local->ops->flush) | ||
538 | return; | ||
539 | 560 | ||
540 | if (sdata && local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) { | 561 | if (sdata && local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) { |
541 | int ac; | 562 | int ac; |
@@ -551,13 +572,46 @@ void ieee80211_flush_queues(struct ieee80211_local *local, | |||
551 | queues = BIT(local->hw.queues) - 1; | 572 | queues = BIT(local->hw.queues) - 1; |
552 | } | 573 | } |
553 | 574 | ||
554 | ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, | 575 | return queues; |
555 | IEEE80211_QUEUE_STOP_REASON_FLUSH); | 576 | } |
577 | |||
578 | void ieee80211_flush_queues(struct ieee80211_local *local, | ||
579 | struct ieee80211_sub_if_data *sdata) | ||
580 | { | ||
581 | unsigned int queues; | ||
582 | |||
583 | if (!local->ops->flush) | ||
584 | return; | ||
585 | |||
586 | queues = ieee80211_get_vif_queues(local, sdata); | ||
587 | |||
588 | ieee80211_stop_queues_by_reason(&local->hw, queues, | ||
589 | IEEE80211_QUEUE_STOP_REASON_FLUSH, | ||
590 | false); | ||
556 | 591 | ||
557 | drv_flush(local, sdata, queues, false); | 592 | drv_flush(local, sdata, queues, false); |
558 | 593 | ||
559 | ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, | 594 | ieee80211_wake_queues_by_reason(&local->hw, queues, |
560 | IEEE80211_QUEUE_STOP_REASON_FLUSH); | 595 | IEEE80211_QUEUE_STOP_REASON_FLUSH, |
596 | false); | ||
597 | } | ||
598 | |||
599 | void ieee80211_stop_vif_queues(struct ieee80211_local *local, | ||
600 | struct ieee80211_sub_if_data *sdata, | ||
601 | enum queue_stop_reason reason) | ||
602 | { | ||
603 | ieee80211_stop_queues_by_reason(&local->hw, | ||
604 | ieee80211_get_vif_queues(local, sdata), | ||
605 | reason, true); | ||
606 | } | ||
607 | |||
608 | void ieee80211_wake_vif_queues(struct ieee80211_local *local, | ||
609 | struct ieee80211_sub_if_data *sdata, | ||
610 | enum queue_stop_reason reason) | ||
611 | { | ||
612 | ieee80211_wake_queues_by_reason(&local->hw, | ||
613 | ieee80211_get_vif_queues(local, sdata), | ||
614 | reason, true); | ||
561 | } | 615 | } |
562 | 616 | ||
563 | static void __iterate_active_interfaces(struct ieee80211_local *local, | 617 | static void __iterate_active_interfaces(struct ieee80211_local *local, |
@@ -1165,14 +1219,17 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1165 | } | 1219 | } |
1166 | } | 1220 | } |
1167 | 1221 | ||
1168 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | 1222 | static int ieee80211_build_preq_ies_band(struct ieee80211_local *local, |
1169 | size_t buffer_len, const u8 *ie, size_t ie_len, | 1223 | u8 *buffer, size_t buffer_len, |
1170 | enum ieee80211_band band, u32 rate_mask, | 1224 | const u8 *ie, size_t ie_len, |
1171 | struct cfg80211_chan_def *chandef) | 1225 | enum ieee80211_band band, |
1226 | u32 rate_mask, | ||
1227 | struct cfg80211_chan_def *chandef, | ||
1228 | size_t *offset) | ||
1172 | { | 1229 | { |
1173 | struct ieee80211_supported_band *sband; | 1230 | struct ieee80211_supported_band *sband; |
1174 | u8 *pos = buffer, *end = buffer + buffer_len; | 1231 | u8 *pos = buffer, *end = buffer + buffer_len; |
1175 | size_t offset = 0, noffset; | 1232 | size_t noffset; |
1176 | int supp_rates_len, i; | 1233 | int supp_rates_len, i; |
1177 | u8 rates[32]; | 1234 | u8 rates[32]; |
1178 | int num_rates; | 1235 | int num_rates; |
@@ -1180,6 +1237,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1180 | int shift; | 1237 | int shift; |
1181 | u32 rate_flags; | 1238 | u32 rate_flags; |
1182 | 1239 | ||
1240 | *offset = 0; | ||
1241 | |||
1183 | sband = local->hw.wiphy->bands[band]; | 1242 | sband = local->hw.wiphy->bands[band]; |
1184 | if (WARN_ON_ONCE(!sband)) | 1243 | if (WARN_ON_ONCE(!sband)) |
1185 | return 0; | 1244 | return 0; |
@@ -1218,12 +1277,12 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1218 | noffset = ieee80211_ie_split(ie, ie_len, | 1277 | noffset = ieee80211_ie_split(ie, ie_len, |
1219 | before_extrates, | 1278 | before_extrates, |
1220 | ARRAY_SIZE(before_extrates), | 1279 | ARRAY_SIZE(before_extrates), |
1221 | offset); | 1280 | *offset); |
1222 | if (end - pos < noffset - offset) | 1281 | if (end - pos < noffset - *offset) |
1223 | goto out_err; | 1282 | goto out_err; |
1224 | memcpy(pos, ie + offset, noffset - offset); | 1283 | memcpy(pos, ie + *offset, noffset - *offset); |
1225 | pos += noffset - offset; | 1284 | pos += noffset - *offset; |
1226 | offset = noffset; | 1285 | *offset = noffset; |
1227 | } | 1286 | } |
1228 | 1287 | ||
1229 | ext_rates_len = num_rates - supp_rates_len; | 1288 | ext_rates_len = num_rates - supp_rates_len; |
@@ -1257,12 +1316,12 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1257 | }; | 1316 | }; |
1258 | noffset = ieee80211_ie_split(ie, ie_len, | 1317 | noffset = ieee80211_ie_split(ie, ie_len, |
1259 | before_ht, ARRAY_SIZE(before_ht), | 1318 | before_ht, ARRAY_SIZE(before_ht), |
1260 | offset); | 1319 | *offset); |
1261 | if (end - pos < noffset - offset) | 1320 | if (end - pos < noffset - *offset) |
1262 | goto out_err; | 1321 | goto out_err; |
1263 | memcpy(pos, ie + offset, noffset - offset); | 1322 | memcpy(pos, ie + *offset, noffset - *offset); |
1264 | pos += noffset - offset; | 1323 | pos += noffset - *offset; |
1265 | offset = noffset; | 1324 | *offset = noffset; |
1266 | } | 1325 | } |
1267 | 1326 | ||
1268 | if (sband->ht_cap.ht_supported) { | 1327 | if (sband->ht_cap.ht_supported) { |
@@ -1297,12 +1356,12 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1297 | }; | 1356 | }; |
1298 | noffset = ieee80211_ie_split(ie, ie_len, | 1357 | noffset = ieee80211_ie_split(ie, ie_len, |
1299 | before_vht, ARRAY_SIZE(before_vht), | 1358 | before_vht, ARRAY_SIZE(before_vht), |
1300 | offset); | 1359 | *offset); |
1301 | if (end - pos < noffset - offset) | 1360 | if (end - pos < noffset - *offset) |
1302 | goto out_err; | 1361 | goto out_err; |
1303 | memcpy(pos, ie + offset, noffset - offset); | 1362 | memcpy(pos, ie + *offset, noffset - *offset); |
1304 | pos += noffset - offset; | 1363 | pos += noffset - *offset; |
1305 | offset = noffset; | 1364 | *offset = noffset; |
1306 | } | 1365 | } |
1307 | 1366 | ||
1308 | if (sband->vht_cap.vht_supported) { | 1367 | if (sband->vht_cap.vht_supported) { |
@@ -1312,21 +1371,54 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1312 | sband->vht_cap.cap); | 1371 | sband->vht_cap.cap); |
1313 | } | 1372 | } |
1314 | 1373 | ||
1315 | /* add any remaining custom IEs */ | ||
1316 | if (ie && ie_len) { | ||
1317 | noffset = ie_len; | ||
1318 | if (end - pos < noffset - offset) | ||
1319 | goto out_err; | ||
1320 | memcpy(pos, ie + offset, noffset - offset); | ||
1321 | pos += noffset - offset; | ||
1322 | } | ||
1323 | |||
1324 | return pos - buffer; | 1374 | return pos - buffer; |
1325 | out_err: | 1375 | out_err: |
1326 | WARN_ONCE(1, "not enough space for preq IEs\n"); | 1376 | WARN_ONCE(1, "not enough space for preq IEs\n"); |
1327 | return pos - buffer; | 1377 | return pos - buffer; |
1328 | } | 1378 | } |
1329 | 1379 | ||
1380 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | ||
1381 | size_t buffer_len, | ||
1382 | struct ieee80211_scan_ies *ie_desc, | ||
1383 | const u8 *ie, size_t ie_len, | ||
1384 | u8 bands_used, u32 *rate_masks, | ||
1385 | struct cfg80211_chan_def *chandef) | ||
1386 | { | ||
1387 | size_t pos = 0, old_pos = 0, custom_ie_offset = 0; | ||
1388 | int i; | ||
1389 | |||
1390 | memset(ie_desc, 0, sizeof(*ie_desc)); | ||
1391 | |||
1392 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | ||
1393 | if (bands_used & BIT(i)) { | ||
1394 | pos += ieee80211_build_preq_ies_band(local, | ||
1395 | buffer + pos, | ||
1396 | buffer_len - pos, | ||
1397 | ie, ie_len, i, | ||
1398 | rate_masks[i], | ||
1399 | chandef, | ||
1400 | &custom_ie_offset); | ||
1401 | ie_desc->ies[i] = buffer + old_pos; | ||
1402 | ie_desc->len[i] = pos - old_pos; | ||
1403 | old_pos = pos; | ||
1404 | } | ||
1405 | } | ||
1406 | |||
1407 | /* add any remaining custom IEs */ | ||
1408 | if (ie && ie_len) { | ||
1409 | if (WARN_ONCE(buffer_len - pos < ie_len - custom_ie_offset, | ||
1410 | "not enough space for preq custom IEs\n")) | ||
1411 | return pos; | ||
1412 | memcpy(buffer + pos, ie + custom_ie_offset, | ||
1413 | ie_len - custom_ie_offset); | ||
1414 | ie_desc->common_ies = buffer + pos; | ||
1415 | ie_desc->common_ie_len = ie_len - custom_ie_offset; | ||
1416 | pos += ie_len - custom_ie_offset; | ||
1417 | } | ||
1418 | |||
1419 | return pos; | ||
1420 | }; | ||
1421 | |||
1330 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | 1422 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, |
1331 | u8 *dst, u32 ratemask, | 1423 | u8 *dst, u32 ratemask, |
1332 | struct ieee80211_channel *chan, | 1424 | struct ieee80211_channel *chan, |
@@ -1339,6 +1431,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1339 | struct sk_buff *skb; | 1431 | struct sk_buff *skb; |
1340 | struct ieee80211_mgmt *mgmt; | 1432 | struct ieee80211_mgmt *mgmt; |
1341 | int ies_len; | 1433 | int ies_len; |
1434 | u32 rate_masks[IEEE80211_NUM_BANDS] = {}; | ||
1435 | struct ieee80211_scan_ies dummy_ie_desc; | ||
1342 | 1436 | ||
1343 | /* | 1437 | /* |
1344 | * Do not send DS Channel parameter for directed probe requests | 1438 | * Do not send DS Channel parameter for directed probe requests |
@@ -1356,10 +1450,11 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1356 | if (!skb) | 1450 | if (!skb) |
1357 | return NULL; | 1451 | return NULL; |
1358 | 1452 | ||
1453 | rate_masks[chan->band] = ratemask; | ||
1359 | ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb), | 1454 | ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb), |
1360 | skb_tailroom(skb), | 1455 | skb_tailroom(skb), &dummy_ie_desc, |
1361 | ie, ie_len, chan->band, | 1456 | ie, ie_len, BIT(chan->band), |
1362 | ratemask, &chandef); | 1457 | rate_masks, &chandef); |
1363 | skb_put(skb, ies_len); | 1458 | skb_put(skb, ies_len); |
1364 | 1459 | ||
1365 | if (dst) { | 1460 | if (dst) { |
@@ -1603,7 +1698,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1603 | if (local->use_chanctx) { | 1698 | if (local->use_chanctx) { |
1604 | mutex_lock(&local->chanctx_mtx); | 1699 | mutex_lock(&local->chanctx_mtx); |
1605 | list_for_each_entry(ctx, &local->chanctx_list, list) | 1700 | list_for_each_entry(ctx, &local->chanctx_list, list) |
1606 | WARN_ON(drv_add_chanctx(local, ctx)); | 1701 | if (ctx->replace_state != |
1702 | IEEE80211_CHANCTX_REPLACES_OTHER) | ||
1703 | WARN_ON(drv_add_chanctx(local, ctx)); | ||
1607 | mutex_unlock(&local->chanctx_mtx); | 1704 | mutex_unlock(&local->chanctx_mtx); |
1608 | 1705 | ||
1609 | list_for_each_entry(sdata, &local->interfaces, list) { | 1706 | list_for_each_entry(sdata, &local->interfaces, list) { |
@@ -1797,7 +1894,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1797 | } | 1894 | } |
1798 | 1895 | ||
1799 | ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, | 1896 | ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, |
1800 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 1897 | IEEE80211_QUEUE_STOP_REASON_SUSPEND, |
1898 | false); | ||
1801 | 1899 | ||
1802 | /* | 1900 | /* |
1803 | * Reconfigure sched scan if it was interrupted by FW restart or | 1901 | * Reconfigure sched scan if it was interrupted by FW restart or |
@@ -2835,6 +2933,35 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local, | |||
2835 | ps->dtim_count = dtim_count; | 2933 | ps->dtim_count = dtim_count; |
2836 | } | 2934 | } |
2837 | 2935 | ||
2936 | static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local, | ||
2937 | struct ieee80211_chanctx *ctx) | ||
2938 | { | ||
2939 | struct ieee80211_sub_if_data *sdata; | ||
2940 | u8 radar_detect = 0; | ||
2941 | |||
2942 | lockdep_assert_held(&local->chanctx_mtx); | ||
2943 | |||
2944 | if (WARN_ON(ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)) | ||
2945 | return 0; | ||
2946 | |||
2947 | list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) | ||
2948 | if (sdata->reserved_radar_required) | ||
2949 | radar_detect |= BIT(sdata->reserved_chandef.width); | ||
2950 | |||
2951 | /* | ||
2952 | * An in-place reservation context should not have any assigned vifs | ||
2953 | * until it replaces the other context. | ||
2954 | */ | ||
2955 | WARN_ON(ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER && | ||
2956 | !list_empty(&ctx->assigned_vifs)); | ||
2957 | |||
2958 | list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list) | ||
2959 | if (sdata->radar_required) | ||
2960 | radar_detect |= BIT(sdata->vif.bss_conf.chandef.width); | ||
2961 | |||
2962 | return radar_detect; | ||
2963 | } | ||
2964 | |||
2838 | int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, | 2965 | int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, |
2839 | const struct cfg80211_chan_def *chandef, | 2966 | const struct cfg80211_chan_def *chandef, |
2840 | enum ieee80211_chanctx_mode chanmode, | 2967 | enum ieee80211_chanctx_mode chanmode, |
@@ -2876,8 +3003,9 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, | |||
2876 | num[iftype] = 1; | 3003 | num[iftype] = 1; |
2877 | 3004 | ||
2878 | list_for_each_entry(ctx, &local->chanctx_list, list) { | 3005 | list_for_each_entry(ctx, &local->chanctx_list, list) { |
2879 | if (ctx->conf.radar_enabled) | 3006 | if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) |
2880 | radar_detect |= BIT(ctx->conf.def.width); | 3007 | continue; |
3008 | radar_detect |= ieee80211_chanctx_radar_detect(local, ctx); | ||
2881 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) { | 3009 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) { |
2882 | num_different_channels++; | 3010 | num_different_channels++; |
2883 | continue; | 3011 | continue; |
@@ -2934,10 +3062,12 @@ int ieee80211_max_num_channels(struct ieee80211_local *local) | |||
2934 | lockdep_assert_held(&local->chanctx_mtx); | 3062 | lockdep_assert_held(&local->chanctx_mtx); |
2935 | 3063 | ||
2936 | list_for_each_entry(ctx, &local->chanctx_list, list) { | 3064 | list_for_each_entry(ctx, &local->chanctx_list, list) { |
3065 | if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) | ||
3066 | continue; | ||
3067 | |||
2937 | num_different_channels++; | 3068 | num_different_channels++; |
2938 | 3069 | ||
2939 | if (ctx->conf.radar_enabled) | 3070 | radar_detect |= ieee80211_chanctx_radar_detect(local, ctx); |
2940 | radar_detect |= BIT(ctx->conf.def.width); | ||
2941 | } | 3071 | } |
2942 | 3072 | ||
2943 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | 3073 | list_for_each_entry_rcu(sdata, &local->interfaces, list) |
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 6ee2b5863572..9181fb6d6437 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c | |||
@@ -271,22 +271,6 @@ static int ieee80211_wep_decrypt(struct ieee80211_local *local, | |||
271 | return ret; | 271 | return ret; |
272 | } | 272 | } |
273 | 273 | ||
274 | |||
275 | static bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, | ||
276 | struct ieee80211_key *key) | ||
277 | { | ||
278 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
279 | unsigned int hdrlen; | ||
280 | u8 *ivpos; | ||
281 | u32 iv; | ||
282 | |||
283 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
284 | ivpos = skb->data + hdrlen; | ||
285 | iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2]; | ||
286 | |||
287 | return ieee80211_wep_weak_iv(iv, key->conf.keylen); | ||
288 | } | ||
289 | |||
290 | ieee80211_rx_result | 274 | ieee80211_rx_result |
291 | ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) | 275 | ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) |
292 | { | 276 | { |
@@ -301,16 +285,12 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) | |||
301 | if (!(status->flag & RX_FLAG_DECRYPTED)) { | 285 | if (!(status->flag & RX_FLAG_DECRYPTED)) { |
302 | if (skb_linearize(rx->skb)) | 286 | if (skb_linearize(rx->skb)) |
303 | return RX_DROP_UNUSABLE; | 287 | return RX_DROP_UNUSABLE; |
304 | if (rx->sta && ieee80211_wep_is_weak_iv(rx->skb, rx->key)) | ||
305 | rx->sta->wep_weak_iv_count++; | ||
306 | if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) | 288 | if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) |
307 | return RX_DROP_UNUSABLE; | 289 | return RX_DROP_UNUSABLE; |
308 | } else if (!(status->flag & RX_FLAG_IV_STRIPPED)) { | 290 | } else if (!(status->flag & RX_FLAG_IV_STRIPPED)) { |
309 | if (!pskb_may_pull(rx->skb, ieee80211_hdrlen(fc) + | 291 | if (!pskb_may_pull(rx->skb, ieee80211_hdrlen(fc) + |
310 | IEEE80211_WEP_IV_LEN)) | 292 | IEEE80211_WEP_IV_LEN)) |
311 | return RX_DROP_UNUSABLE; | 293 | return RX_DROP_UNUSABLE; |
312 | if (rx->sta && ieee80211_wep_is_weak_iv(rx->skb, rx->key)) | ||
313 | rx->sta->wep_weak_iv_count++; | ||
314 | ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); | 294 | ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); |
315 | /* remove ICV */ | 295 | /* remove ICV */ |
316 | if (pskb_trim(rx->skb, rx->skb->len - IEEE80211_WEP_ICV_LEN)) | 296 | if (pskb_trim(rx->skb, rx->skb->len - IEEE80211_WEP_ICV_LEN)) |
diff --git a/net/wireless/core.c b/net/wireless/core.c index a1c40654dd9b..afee5e0455ea 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include "sysfs.h" | 25 | #include "sysfs.h" |
26 | #include "debugfs.h" | 26 | #include "debugfs.h" |
27 | #include "wext-compat.h" | 27 | #include "wext-compat.h" |
28 | #include "ethtool.h" | ||
29 | #include "rdev-ops.h" | 28 | #include "rdev-ops.h" |
30 | 29 | ||
31 | /* name for sysfs, %d is appended */ | 30 | /* name for sysfs, %d is appended */ |
@@ -927,8 +926,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
927 | /* allow mac80211 to determine the timeout */ | 926 | /* allow mac80211 to determine the timeout */ |
928 | wdev->ps_timeout = -1; | 927 | wdev->ps_timeout = -1; |
929 | 928 | ||
930 | netdev_set_default_ethtool_ops(dev, &cfg80211_ethtool_ops); | ||
931 | |||
932 | if ((wdev->iftype == NL80211_IFTYPE_STATION || | 929 | if ((wdev->iftype == NL80211_IFTYPE_STATION || |
933 | wdev->iftype == NL80211_IFTYPE_P2P_CLIENT || | 930 | wdev->iftype == NL80211_IFTYPE_P2P_CLIENT || |
934 | wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr) | 931 | wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr) |
diff --git a/net/wireless/ethtool.c b/net/wireless/ethtool.c index d4860bfc020e..e9e91298c70d 100644 --- a/net/wireless/ethtool.c +++ b/net/wireless/ethtool.c | |||
@@ -1,11 +1,9 @@ | |||
1 | #include <linux/utsname.h> | 1 | #include <linux/utsname.h> |
2 | #include <net/cfg80211.h> | 2 | #include <net/cfg80211.h> |
3 | #include "core.h" | 3 | #include "core.h" |
4 | #include "ethtool.h" | ||
5 | #include "rdev-ops.h" | 4 | #include "rdev-ops.h" |
6 | 5 | ||
7 | static void cfg80211_get_drvinfo(struct net_device *dev, | 6 | void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) |
8 | struct ethtool_drvinfo *info) | ||
9 | { | 7 | { |
10 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 8 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
11 | 9 | ||
@@ -23,84 +21,4 @@ static void cfg80211_get_drvinfo(struct net_device *dev, | |||
23 | strlcpy(info->bus_info, dev_name(wiphy_dev(wdev->wiphy)), | 21 | strlcpy(info->bus_info, dev_name(wiphy_dev(wdev->wiphy)), |
24 | sizeof(info->bus_info)); | 22 | sizeof(info->bus_info)); |
25 | } | 23 | } |
26 | 24 | EXPORT_SYMBOL(cfg80211_get_drvinfo); | |
27 | static int cfg80211_get_regs_len(struct net_device *dev) | ||
28 | { | ||
29 | /* For now, return 0... */ | ||
30 | return 0; | ||
31 | } | ||
32 | |||
33 | static void cfg80211_get_regs(struct net_device *dev, struct ethtool_regs *regs, | ||
34 | void *data) | ||
35 | { | ||
36 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
37 | |||
38 | regs->version = wdev->wiphy->hw_version; | ||
39 | regs->len = 0; | ||
40 | } | ||
41 | |||
42 | static void cfg80211_get_ringparam(struct net_device *dev, | ||
43 | struct ethtool_ringparam *rp) | ||
44 | { | ||
45 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
46 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | ||
47 | |||
48 | memset(rp, 0, sizeof(*rp)); | ||
49 | |||
50 | if (rdev->ops->get_ringparam) | ||
51 | rdev_get_ringparam(rdev, &rp->tx_pending, &rp->tx_max_pending, | ||
52 | &rp->rx_pending, &rp->rx_max_pending); | ||
53 | } | ||
54 | |||
55 | static int cfg80211_set_ringparam(struct net_device *dev, | ||
56 | struct ethtool_ringparam *rp) | ||
57 | { | ||
58 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
59 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | ||
60 | |||
61 | if (rp->rx_mini_pending != 0 || rp->rx_jumbo_pending != 0) | ||
62 | return -EINVAL; | ||
63 | |||
64 | if (rdev->ops->set_ringparam) | ||
65 | return rdev_set_ringparam(rdev, rp->tx_pending, rp->rx_pending); | ||
66 | |||
67 | return -ENOTSUPP; | ||
68 | } | ||
69 | |||
70 | static int cfg80211_get_sset_count(struct net_device *dev, int sset) | ||
71 | { | ||
72 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
73 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | ||
74 | if (rdev->ops->get_et_sset_count) | ||
75 | return rdev_get_et_sset_count(rdev, dev, sset); | ||
76 | return -EOPNOTSUPP; | ||
77 | } | ||
78 | |||
79 | static void cfg80211_get_stats(struct net_device *dev, | ||
80 | struct ethtool_stats *stats, u64 *data) | ||
81 | { | ||
82 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
83 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | ||
84 | if (rdev->ops->get_et_stats) | ||
85 | rdev_get_et_stats(rdev, dev, stats, data); | ||
86 | } | ||
87 | |||
88 | static void cfg80211_get_strings(struct net_device *dev, u32 sset, u8 *data) | ||
89 | { | ||
90 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
91 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | ||
92 | if (rdev->ops->get_et_strings) | ||
93 | rdev_get_et_strings(rdev, dev, sset, data); | ||
94 | } | ||
95 | |||
96 | const struct ethtool_ops cfg80211_ethtool_ops = { | ||
97 | .get_drvinfo = cfg80211_get_drvinfo, | ||
98 | .get_regs_len = cfg80211_get_regs_len, | ||
99 | .get_regs = cfg80211_get_regs, | ||
100 | .get_link = ethtool_op_get_link, | ||
101 | .get_ringparam = cfg80211_get_ringparam, | ||
102 | .set_ringparam = cfg80211_set_ringparam, | ||
103 | .get_strings = cfg80211_get_strings, | ||
104 | .get_ethtool_stats = cfg80211_get_stats, | ||
105 | .get_sset_count = cfg80211_get_sset_count, | ||
106 | }; | ||
diff --git a/net/wireless/ethtool.h b/net/wireless/ethtool.h deleted file mode 100644 index 695ecad20bd6..000000000000 --- a/net/wireless/ethtool.h +++ /dev/null | |||
@@ -1,6 +0,0 @@ | |||
1 | #ifndef __CFG80211_ETHTOOL__ | ||
2 | #define __CFG80211_ETHTOOL__ | ||
3 | |||
4 | extern const struct ethtool_ops cfg80211_ethtool_ops; | ||
5 | |||
6 | #endif /* __CFG80211_ETHTOOL__ */ | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ba4f1723c83a..c10295138eb5 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -337,6 +337,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
337 | [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 }, | 337 | [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 }, |
338 | [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG }, | 338 | [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG }, |
339 | [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG }, | 339 | [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG }, |
340 | [NL80211_ATTR_TDLS_INITIATOR] = { .type = NLA_FLAG }, | ||
340 | [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG }, | 341 | [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG }, |
341 | [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY, | 342 | [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY, |
342 | .len = IEEE80211_MAX_DATA_LEN }, | 343 | .len = IEEE80211_MAX_DATA_LEN }, |
@@ -6012,17 +6013,6 @@ skip_beacons: | |||
6012 | params.radar_required = true; | 6013 | params.radar_required = true; |
6013 | } | 6014 | } |
6014 | 6015 | ||
6015 | /* TODO: I left this here for now. With channel switch, the | ||
6016 | * verification is a bit more complicated, because we only do | ||
6017 | * it later when the channel switch really happens. | ||
6018 | */ | ||
6019 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, | ||
6020 | params.chandef.chan, | ||
6021 | CHAN_MODE_SHARED, | ||
6022 | radar_detect_width); | ||
6023 | if (err) | ||
6024 | return err; | ||
6025 | |||
6026 | if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX]) | 6016 | if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX]) |
6027 | params.block_tx = true; | 6017 | params.block_tx = true; |
6028 | 6018 | ||
@@ -7365,6 +7355,7 @@ static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
7365 | u32 peer_capability = 0; | 7355 | u32 peer_capability = 0; |
7366 | u16 status_code; | 7356 | u16 status_code; |
7367 | u8 *peer; | 7357 | u8 *peer; |
7358 | bool initiator; | ||
7368 | 7359 | ||
7369 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) || | 7360 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) || |
7370 | !rdev->ops->tdls_mgmt) | 7361 | !rdev->ops->tdls_mgmt) |
@@ -7381,12 +7372,14 @@ static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
7381 | action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]); | 7372 | action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]); |
7382 | status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]); | 7373 | status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]); |
7383 | dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]); | 7374 | dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]); |
7375 | initiator = nla_get_flag(info->attrs[NL80211_ATTR_TDLS_INITIATOR]); | ||
7384 | if (info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]) | 7376 | if (info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]) |
7385 | peer_capability = | 7377 | peer_capability = |
7386 | nla_get_u32(info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]); | 7378 | nla_get_u32(info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]); |
7387 | 7379 | ||
7388 | return rdev_tdls_mgmt(rdev, dev, peer, action_code, | 7380 | return rdev_tdls_mgmt(rdev, dev, peer, action_code, |
7389 | dialog_token, status_code, peer_capability, | 7381 | dialog_token, status_code, peer_capability, |
7382 | initiator, | ||
7390 | nla_data(info->attrs[NL80211_ATTR_IE]), | 7383 | nla_data(info->attrs[NL80211_ATTR_IE]), |
7391 | nla_len(info->attrs[NL80211_ATTR_IE])); | 7384 | nla_len(info->attrs[NL80211_ATTR_IE])); |
7392 | } | 7385 | } |
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index d95bbe348138..56c2240c30ce 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h | |||
@@ -714,25 +714,6 @@ static inline int rdev_get_antenna(struct cfg80211_registered_device *rdev, | |||
714 | return ret; | 714 | return ret; |
715 | } | 715 | } |
716 | 716 | ||
717 | static inline int rdev_set_ringparam(struct cfg80211_registered_device *rdev, | ||
718 | u32 tx, u32 rx) | ||
719 | { | ||
720 | int ret; | ||
721 | trace_rdev_set_ringparam(&rdev->wiphy, tx, rx); | ||
722 | ret = rdev->ops->set_ringparam(&rdev->wiphy, tx, rx); | ||
723 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
724 | return ret; | ||
725 | } | ||
726 | |||
727 | static inline void rdev_get_ringparam(struct cfg80211_registered_device *rdev, | ||
728 | u32 *tx, u32 *tx_max, u32 *rx, | ||
729 | u32 *rx_max) | ||
730 | { | ||
731 | trace_rdev_get_ringparam(&rdev->wiphy); | ||
732 | rdev->ops->get_ringparam(&rdev->wiphy, tx, tx_max, rx, rx_max); | ||
733 | trace_rdev_return_void_tx_rx(&rdev->wiphy, *tx, *tx_max, *rx, *rx_max); | ||
734 | } | ||
735 | |||
736 | static inline int | 717 | static inline int |
737 | rdev_sched_scan_start(struct cfg80211_registered_device *rdev, | 718 | rdev_sched_scan_start(struct cfg80211_registered_device *rdev, |
738 | struct net_device *dev, | 719 | struct net_device *dev, |
@@ -770,15 +751,15 @@ static inline int rdev_tdls_mgmt(struct cfg80211_registered_device *rdev, | |||
770 | struct net_device *dev, u8 *peer, | 751 | struct net_device *dev, u8 *peer, |
771 | u8 action_code, u8 dialog_token, | 752 | u8 action_code, u8 dialog_token, |
772 | u16 status_code, u32 peer_capability, | 753 | u16 status_code, u32 peer_capability, |
773 | const u8 *buf, size_t len) | 754 | bool initiator, const u8 *buf, size_t len) |
774 | { | 755 | { |
775 | int ret; | 756 | int ret; |
776 | trace_rdev_tdls_mgmt(&rdev->wiphy, dev, peer, action_code, | 757 | trace_rdev_tdls_mgmt(&rdev->wiphy, dev, peer, action_code, |
777 | dialog_token, status_code, peer_capability, | 758 | dialog_token, status_code, peer_capability, |
778 | buf, len); | 759 | initiator, buf, len); |
779 | ret = rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code, | 760 | ret = rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code, |
780 | dialog_token, status_code, peer_capability, | 761 | dialog_token, status_code, peer_capability, |
781 | buf, len); | 762 | initiator, buf, len); |
782 | trace_rdev_return_int(&rdev->wiphy, ret); | 763 | trace_rdev_return_int(&rdev->wiphy, ret); |
783 | return ret; | 764 | return ret; |
784 | } | 765 | } |
@@ -816,35 +797,6 @@ static inline int rdev_set_noack_map(struct cfg80211_registered_device *rdev, | |||
816 | } | 797 | } |
817 | 798 | ||
818 | static inline int | 799 | static inline int |
819 | rdev_get_et_sset_count(struct cfg80211_registered_device *rdev, | ||
820 | struct net_device *dev, int sset) | ||
821 | { | ||
822 | int ret; | ||
823 | trace_rdev_get_et_sset_count(&rdev->wiphy, dev, sset); | ||
824 | ret = rdev->ops->get_et_sset_count(&rdev->wiphy, dev, sset); | ||
825 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
826 | return ret; | ||
827 | } | ||
828 | |||
829 | static inline void rdev_get_et_stats(struct cfg80211_registered_device *rdev, | ||
830 | struct net_device *dev, | ||
831 | struct ethtool_stats *stats, u64 *data) | ||
832 | { | ||
833 | trace_rdev_get_et_stats(&rdev->wiphy, dev); | ||
834 | rdev->ops->get_et_stats(&rdev->wiphy, dev, stats, data); | ||
835 | trace_rdev_return_void(&rdev->wiphy); | ||
836 | } | ||
837 | |||
838 | static inline void rdev_get_et_strings(struct cfg80211_registered_device *rdev, | ||
839 | struct net_device *dev, u32 sset, | ||
840 | u8 *data) | ||
841 | { | ||
842 | trace_rdev_get_et_strings(&rdev->wiphy, dev, sset); | ||
843 | rdev->ops->get_et_strings(&rdev->wiphy, dev, sset, data); | ||
844 | trace_rdev_return_void(&rdev->wiphy); | ||
845 | } | ||
846 | |||
847 | static inline int | ||
848 | rdev_get_channel(struct cfg80211_registered_device *rdev, | 800 | rdev_get_channel(struct cfg80211_registered_device *rdev, |
849 | struct wireless_dev *wdev, | 801 | struct wireless_dev *wdev, |
850 | struct cfg80211_chan_def *chandef) | 802 | struct cfg80211_chan_def *chandef) |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 560ed77084e9..85474ee501eb 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -298,11 +298,6 @@ DEFINE_EVENT(wiphy_only_evt, rdev_return_void, | |||
298 | TP_ARGS(wiphy) | 298 | TP_ARGS(wiphy) |
299 | ); | 299 | ); |
300 | 300 | ||
301 | DEFINE_EVENT(wiphy_only_evt, rdev_get_ringparam, | ||
302 | TP_PROTO(struct wiphy *wiphy), | ||
303 | TP_ARGS(wiphy) | ||
304 | ); | ||
305 | |||
306 | DEFINE_EVENT(wiphy_only_evt, rdev_get_antenna, | 301 | DEFINE_EVENT(wiphy_only_evt, rdev_get_antenna, |
307 | TP_PROTO(struct wiphy *wiphy), | 302 | TP_PROTO(struct wiphy *wiphy), |
308 | TP_ARGS(wiphy) | 303 | TP_ARGS(wiphy) |
@@ -580,11 +575,6 @@ DEFINE_EVENT(wiphy_netdev_evt, rdev_stop_ap, | |||
580 | TP_ARGS(wiphy, netdev) | 575 | TP_ARGS(wiphy, netdev) |
581 | ); | 576 | ); |
582 | 577 | ||
583 | DEFINE_EVENT(wiphy_netdev_evt, rdev_get_et_stats, | ||
584 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), | ||
585 | TP_ARGS(wiphy, netdev) | ||
586 | ); | ||
587 | |||
588 | DEFINE_EVENT(wiphy_netdev_evt, rdev_sched_scan_stop, | 578 | DEFINE_EVENT(wiphy_netdev_evt, rdev_sched_scan_stop, |
589 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), | 579 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), |
590 | TP_ARGS(wiphy, netdev) | 580 | TP_ARGS(wiphy, netdev) |
@@ -1439,11 +1429,6 @@ DECLARE_EVENT_CLASS(tx_rx_evt, | |||
1439 | WIPHY_PR_ARG, __entry->tx, __entry->rx) | 1429 | WIPHY_PR_ARG, __entry->tx, __entry->rx) |
1440 | ); | 1430 | ); |
1441 | 1431 | ||
1442 | DEFINE_EVENT(tx_rx_evt, rdev_set_ringparam, | ||
1443 | TP_PROTO(struct wiphy *wiphy, u32 tx, u32 rx), | ||
1444 | TP_ARGS(wiphy, rx, tx) | ||
1445 | ); | ||
1446 | |||
1447 | DEFINE_EVENT(tx_rx_evt, rdev_set_antenna, | 1432 | DEFINE_EVENT(tx_rx_evt, rdev_set_antenna, |
1448 | TP_PROTO(struct wiphy *wiphy, u32 tx, u32 rx), | 1433 | TP_PROTO(struct wiphy *wiphy, u32 tx, u32 rx), |
1449 | TP_ARGS(wiphy, rx, tx) | 1434 | TP_ARGS(wiphy, rx, tx) |
@@ -1469,9 +1454,9 @@ TRACE_EVENT(rdev_tdls_mgmt, | |||
1469 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | 1454 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, |
1470 | u8 *peer, u8 action_code, u8 dialog_token, | 1455 | u8 *peer, u8 action_code, u8 dialog_token, |
1471 | u16 status_code, u32 peer_capability, | 1456 | u16 status_code, u32 peer_capability, |
1472 | const u8 *buf, size_t len), | 1457 | bool initiator, const u8 *buf, size_t len), |
1473 | TP_ARGS(wiphy, netdev, peer, action_code, dialog_token, status_code, | 1458 | TP_ARGS(wiphy, netdev, peer, action_code, dialog_token, status_code, |
1474 | peer_capability, buf, len), | 1459 | peer_capability, initiator, buf, len), |
1475 | TP_STRUCT__entry( | 1460 | TP_STRUCT__entry( |
1476 | WIPHY_ENTRY | 1461 | WIPHY_ENTRY |
1477 | NETDEV_ENTRY | 1462 | NETDEV_ENTRY |
@@ -1480,6 +1465,7 @@ TRACE_EVENT(rdev_tdls_mgmt, | |||
1480 | __field(u8, dialog_token) | 1465 | __field(u8, dialog_token) |
1481 | __field(u16, status_code) | 1466 | __field(u16, status_code) |
1482 | __field(u32, peer_capability) | 1467 | __field(u32, peer_capability) |
1468 | __field(bool, initiator) | ||
1483 | __dynamic_array(u8, buf, len) | 1469 | __dynamic_array(u8, buf, len) |
1484 | ), | 1470 | ), |
1485 | TP_fast_assign( | 1471 | TP_fast_assign( |
@@ -1490,13 +1476,16 @@ TRACE_EVENT(rdev_tdls_mgmt, | |||
1490 | __entry->dialog_token = dialog_token; | 1476 | __entry->dialog_token = dialog_token; |
1491 | __entry->status_code = status_code; | 1477 | __entry->status_code = status_code; |
1492 | __entry->peer_capability = peer_capability; | 1478 | __entry->peer_capability = peer_capability; |
1479 | __entry->initiator = initiator; | ||
1493 | memcpy(__get_dynamic_array(buf), buf, len); | 1480 | memcpy(__get_dynamic_array(buf), buf, len); |
1494 | ), | 1481 | ), |
1495 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ", action_code: %u, " | 1482 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ", action_code: %u, " |
1496 | "dialog_token: %u, status_code: %u, peer_capability: %u buf: %#.2x ", | 1483 | "dialog_token: %u, status_code: %u, peer_capability: %u " |
1484 | "initiator: %s buf: %#.2x ", | ||
1497 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), | 1485 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), |
1498 | __entry->action_code, __entry->dialog_token, | 1486 | __entry->action_code, __entry->dialog_token, |
1499 | __entry->status_code, __entry->peer_capability, | 1487 | __entry->status_code, __entry->peer_capability, |
1488 | BOOL_TO_STR(__entry->initiator), | ||
1500 | ((u8 *)__get_dynamic_array(buf))[0]) | 1489 | ((u8 *)__get_dynamic_array(buf))[0]) |
1501 | ); | 1490 | ); |
1502 | 1491 | ||
@@ -1725,40 +1714,6 @@ TRACE_EVENT(rdev_set_noack_map, | |||
1725 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->noack_map) | 1714 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->noack_map) |
1726 | ); | 1715 | ); |
1727 | 1716 | ||
1728 | TRACE_EVENT(rdev_get_et_sset_count, | ||
1729 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int sset), | ||
1730 | TP_ARGS(wiphy, netdev, sset), | ||
1731 | TP_STRUCT__entry( | ||
1732 | WIPHY_ENTRY | ||
1733 | NETDEV_ENTRY | ||
1734 | __field(int, sset) | ||
1735 | ), | ||
1736 | TP_fast_assign( | ||
1737 | WIPHY_ASSIGN; | ||
1738 | NETDEV_ASSIGN; | ||
1739 | __entry->sset = sset; | ||
1740 | ), | ||
1741 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", sset: %d", | ||
1742 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sset) | ||
1743 | ); | ||
1744 | |||
1745 | TRACE_EVENT(rdev_get_et_strings, | ||
1746 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u32 sset), | ||
1747 | TP_ARGS(wiphy, netdev, sset), | ||
1748 | TP_STRUCT__entry( | ||
1749 | WIPHY_ENTRY | ||
1750 | NETDEV_ENTRY | ||
1751 | __field(u32, sset) | ||
1752 | ), | ||
1753 | TP_fast_assign( | ||
1754 | WIPHY_ASSIGN; | ||
1755 | NETDEV_ASSIGN; | ||
1756 | __entry->sset = sset; | ||
1757 | ), | ||
1758 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", sset: %u", | ||
1759 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sset) | ||
1760 | ); | ||
1761 | |||
1762 | DEFINE_EVENT(wiphy_wdev_evt, rdev_get_channel, | 1717 | DEFINE_EVENT(wiphy_wdev_evt, rdev_get_channel, |
1763 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), | 1718 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), |
1764 | TP_ARGS(wiphy, wdev) | 1719 | TP_ARGS(wiphy, wdev) |