diff options
author | John W. Linville <linville@tuxdriver.com> | 2014-11-20 16:09:30 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-11-20 16:09:30 -0500 |
commit | 9a638ddfb09e5aa17158842c95526e1aa79f92e6 (patch) | |
tree | 7edf2e128b23f711cf28273dca3ff69f3706925a | |
parent | b4c1b70823721e9edb19a839188e4dae50ce878d (diff) | |
parent | 75769c80e381653994293b5aa5a8cfec50088f9f (diff) |
Merge tag 'mac80211-next-for-john-2014-11-20' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Johannes Berg <johannes@sipsolutions.net> says:
"It has been a while since my last pull request, so we accumulated
another relatively large set of changes:
* TDLS off-channel support set from Arik/Liad, with some support
patches I did
* custom regulatory fixes from Arik
* minstrel VHT fix (and a small optimisation) from Felix
* add back radiotap vendor namespace support (myself)
* random MAC address scanning for cfg80211/mac80211/hwsim (myself)
* CSA improvements (Luca)
* WoWLAN Net Detect (wake on network found) support (Luca)
* and lots of other smaller changes from many people"
Signed-off-by: John W. Linville <linville@tuxdriver.com>
48 files changed, 2951 insertions, 384 deletions
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index ab2709a43768..19eab2a69ad5 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c | |||
@@ -547,7 +547,9 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
547 | 547 | ||
548 | 548 | ||
549 | static void | 549 | static void |
550 | ath5k_sw_scan_start(struct ieee80211_hw *hw) | 550 | ath5k_sw_scan_start(struct ieee80211_hw *hw, |
551 | struct ieee80211_vif *vif, | ||
552 | const u8 *mac_addr) | ||
551 | { | 553 | { |
552 | struct ath5k_hw *ah = hw->priv; | 554 | struct ath5k_hw *ah = hw->priv; |
553 | if (!ah->assoc) | 555 | if (!ah->assoc) |
@@ -556,7 +558,7 @@ ath5k_sw_scan_start(struct ieee80211_hw *hw) | |||
556 | 558 | ||
557 | 559 | ||
558 | static void | 560 | static void |
559 | ath5k_sw_scan_complete(struct ieee80211_hw *hw) | 561 | ath5k_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) |
560 | { | 562 | { |
561 | struct ath5k_hw *ah = hw->priv; | 563 | struct ath5k_hw *ah = hw->priv; |
562 | ath5k_hw_set_ledstate(ah, ah->assoc ? | 564 | ath5k_hw_set_ledstate(ah, ah->assoc ? |
diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 794d52016437..206665059d66 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c | |||
@@ -963,7 +963,7 @@ static void ath_scan_send_probe(struct ath_softc *sc, | |||
963 | struct ieee80211_tx_info *info; | 963 | struct ieee80211_tx_info *info; |
964 | int band = sc->offchannel.chan.chandef.chan->band; | 964 | int band = sc->offchannel.chan.chandef.chan->band; |
965 | 965 | ||
966 | skb = ieee80211_probereq_get(sc->hw, vif, | 966 | skb = ieee80211_probereq_get(sc->hw, vif->addr, |
967 | ssid->ssid, ssid->ssid_len, req->ie_len); | 967 | ssid->ssid, ssid->ssid_len, req->ie_len); |
968 | if (!skb) | 968 | if (!skb) |
969 | return; | 969 | return; |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index c7d12efaa86a..92d5a6c5a225 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c | |||
@@ -1691,7 +1691,9 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, | |||
1691 | return ret; | 1691 | return ret; |
1692 | } | 1692 | } |
1693 | 1693 | ||
1694 | static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw) | 1694 | static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw, |
1695 | struct ieee80211_vif *vif, | ||
1696 | const u8 *mac_addr) | ||
1695 | { | 1697 | { |
1696 | struct ath9k_htc_priv *priv = hw->priv; | 1698 | struct ath9k_htc_priv *priv = hw->priv; |
1697 | struct ath_common *common = ath9k_hw_common(priv->ah); | 1699 | struct ath_common *common = ath9k_hw_common(priv->ah); |
@@ -1705,7 +1707,8 @@ static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw) | |||
1705 | mutex_unlock(&priv->mutex); | 1707 | mutex_unlock(&priv->mutex); |
1706 | } | 1708 | } |
1707 | 1709 | ||
1708 | static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw) | 1710 | static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw, |
1711 | struct ieee80211_vif *vif) | ||
1709 | { | 1712 | { |
1710 | struct ath9k_htc_priv *priv = hw->priv; | 1713 | struct ath9k_htc_priv *priv = hw->priv; |
1711 | struct ath_common *common = ath9k_hw_common(priv->ah); | 1714 | struct ath_common *common = ath9k_hw_common(priv->ah); |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index f95283f3c350..7c63976b5b0c 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -2183,14 +2183,17 @@ static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) | |||
2183 | return 0; | 2183 | return 0; |
2184 | } | 2184 | } |
2185 | 2185 | ||
2186 | static void ath9k_sw_scan_start(struct ieee80211_hw *hw) | 2186 | static void ath9k_sw_scan_start(struct ieee80211_hw *hw, |
2187 | struct ieee80211_vif *vif, | ||
2188 | const u8 *mac_addr) | ||
2187 | { | 2189 | { |
2188 | struct ath_softc *sc = hw->priv; | 2190 | struct ath_softc *sc = hw->priv; |
2189 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 2191 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
2190 | set_bit(ATH_OP_SCANNING, &common->op_flags); | 2192 | set_bit(ATH_OP_SCANNING, &common->op_flags); |
2191 | } | 2193 | } |
2192 | 2194 | ||
2193 | static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) | 2195 | static void ath9k_sw_scan_complete(struct ieee80211_hw *hw, |
2196 | struct ieee80211_vif *vif) | ||
2194 | { | 2197 | { |
2195 | struct ath_softc *sc = hw->priv; | 2198 | struct ath_softc *sc = hw->priv; |
2196 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 2199 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index b71d2b33532d..267c35d1f699 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c | |||
@@ -494,7 +494,9 @@ out: | |||
494 | return ret; | 494 | return ret; |
495 | } | 495 | } |
496 | 496 | ||
497 | static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw) | 497 | static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw, |
498 | struct ieee80211_vif *vif, | ||
499 | const u8 *mac_addr) | ||
498 | { | 500 | { |
499 | struct wcn36xx *wcn = hw->priv; | 501 | struct wcn36xx *wcn = hw->priv; |
500 | 502 | ||
@@ -502,7 +504,8 @@ static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw) | |||
502 | wcn36xx_smd_start_scan(wcn); | 504 | wcn36xx_smd_start_scan(wcn); |
503 | } | 505 | } |
504 | 506 | ||
505 | static void wcn36xx_sw_scan_complete(struct ieee80211_hw *hw) | 507 | static void wcn36xx_sw_scan_complete(struct ieee80211_hw *hw, |
508 | struct ieee80211_vif *vif) | ||
506 | { | 509 | { |
507 | struct wcn36xx *wcn = hw->priv; | 510 | struct wcn36xx *wcn = hw->priv; |
508 | 511 | ||
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 5d4173ee55bc..47731cb0d815 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -5110,7 +5110,9 @@ static void b43_op_sta_notify(struct ieee80211_hw *hw, | |||
5110 | B43_WARN_ON(!vif || wl->vif != vif); | 5110 | B43_WARN_ON(!vif || wl->vif != vif); |
5111 | } | 5111 | } |
5112 | 5112 | ||
5113 | static void b43_op_sw_scan_start_notifier(struct ieee80211_hw *hw) | 5113 | static void b43_op_sw_scan_start_notifier(struct ieee80211_hw *hw, |
5114 | struct ieee80211_vif *vif, | ||
5115 | const u8 *mac_addr) | ||
5114 | { | 5116 | { |
5115 | struct b43_wl *wl = hw_to_b43_wl(hw); | 5117 | struct b43_wl *wl = hw_to_b43_wl(hw); |
5116 | struct b43_wldev *dev; | 5118 | struct b43_wldev *dev; |
@@ -5124,7 +5126,8 @@ static void b43_op_sw_scan_start_notifier(struct ieee80211_hw *hw) | |||
5124 | mutex_unlock(&wl->mutex); | 5126 | mutex_unlock(&wl->mutex); |
5125 | } | 5127 | } |
5126 | 5128 | ||
5127 | static void b43_op_sw_scan_complete_notifier(struct ieee80211_hw *hw) | 5129 | static void b43_op_sw_scan_complete_notifier(struct ieee80211_hw *hw, |
5130 | struct ieee80211_vif *vif) | ||
5128 | { | 5131 | { |
5129 | struct b43_wl *wl = hw_to_b43_wl(hw); | 5132 | struct b43_wl *wl = hw_to_b43_wl(hw); |
5130 | struct b43_wldev *dev; | 5133 | struct b43_wldev *dev; |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 43c71bfaa474..f95b52442281 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | |||
@@ -764,7 +764,9 @@ brcms_ops_configure_filter(struct ieee80211_hw *hw, | |||
764 | return; | 764 | return; |
765 | } | 765 | } |
766 | 766 | ||
767 | static void brcms_ops_sw_scan_start(struct ieee80211_hw *hw) | 767 | static void brcms_ops_sw_scan_start(struct ieee80211_hw *hw, |
768 | struct ieee80211_vif *vif, | ||
769 | const u8 *mac_addr) | ||
768 | { | 770 | { |
769 | struct brcms_info *wl = hw->priv; | 771 | struct brcms_info *wl = hw->priv; |
770 | spin_lock_bh(&wl->lock); | 772 | spin_lock_bh(&wl->lock); |
@@ -773,7 +775,8 @@ static void brcms_ops_sw_scan_start(struct ieee80211_hw *hw) | |||
773 | return; | 775 | return; |
774 | } | 776 | } |
775 | 777 | ||
776 | static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw) | 778 | static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw, |
779 | struct ieee80211_vif *vif) | ||
777 | { | 780 | { |
778 | struct brcms_info *wl = hw->priv; | 781 | struct brcms_info *wl = hw->priv; |
779 | spin_lock_bh(&wl->lock); | 782 | spin_lock_bh(&wl->lock); |
diff --git a/drivers/net/wireless/cw1200/scan.c b/drivers/net/wireless/cw1200/scan.c index b2fb6c632092..f2e276faca70 100644 --- a/drivers/net/wireless/cw1200/scan.c +++ b/drivers/net/wireless/cw1200/scan.c | |||
@@ -78,7 +78,7 @@ int cw1200_hw_scan(struct ieee80211_hw *hw, | |||
78 | if (req->n_ssids > WSM_SCAN_MAX_NUM_OF_SSIDS) | 78 | if (req->n_ssids > WSM_SCAN_MAX_NUM_OF_SSIDS) |
79 | return -EINVAL; | 79 | return -EINVAL; |
80 | 80 | ||
81 | frame.skb = ieee80211_probereq_get(hw, priv->vif, NULL, 0, | 81 | frame.skb = ieee80211_probereq_get(hw, priv->vif->addr, NULL, 0, |
82 | req->ie_len); | 82 | req->ie_len); |
83 | if (!frame.skb) | 83 | if (!frame.skb) |
84 | return -ENOMEM; | 84 | return -ENOMEM; |
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 77fbf3035038..2371d11e4190 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -415,6 +415,8 @@ struct mac80211_hwsim_data { | |||
415 | bool destroy_on_close; | 415 | bool destroy_on_close; |
416 | struct work_struct destroy_work; | 416 | struct work_struct destroy_work; |
417 | u32 portid; | 417 | u32 portid; |
418 | char alpha2[2]; | ||
419 | const struct ieee80211_regdomain *regd; | ||
418 | 420 | ||
419 | struct ieee80211_channel *tmp_chan; | 421 | struct ieee80211_channel *tmp_chan; |
420 | struct delayed_work roc_done; | 422 | struct delayed_work roc_done; |
@@ -422,6 +424,7 @@ struct mac80211_hwsim_data { | |||
422 | struct cfg80211_scan_request *hw_scan_request; | 424 | struct cfg80211_scan_request *hw_scan_request; |
423 | struct ieee80211_vif *hw_scan_vif; | 425 | struct ieee80211_vif *hw_scan_vif; |
424 | int scan_chan_idx; | 426 | int scan_chan_idx; |
427 | u8 scan_addr[ETH_ALEN]; | ||
425 | 428 | ||
426 | struct ieee80211_channel *channel; | 429 | struct ieee80211_channel *channel; |
427 | u64 beacon_int /* beacon interval in us */; | 430 | u64 beacon_int /* beacon interval in us */; |
@@ -830,6 +833,9 @@ static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data, | |||
830 | .ret = false, | 833 | .ret = false, |
831 | }; | 834 | }; |
832 | 835 | ||
836 | if (data->scanning && memcmp(addr, data->scan_addr, ETH_ALEN) == 0) | ||
837 | return true; | ||
838 | |||
833 | memcpy(md.addr, addr, ETH_ALEN); | 839 | memcpy(md.addr, addr, ETH_ALEN); |
834 | 840 | ||
835 | ieee80211_iterate_active_interfaces_atomic(data->hw, | 841 | ieee80211_iterate_active_interfaces_atomic(data->hw, |
@@ -984,6 +990,53 @@ static void mac80211_hwsim_tx_iter(void *_data, u8 *addr, | |||
984 | data->receive = true; | 990 | data->receive = true; |
985 | } | 991 | } |
986 | 992 | ||
993 | static void mac80211_hwsim_add_vendor_rtap(struct sk_buff *skb) | ||
994 | { | ||
995 | /* | ||
996 | * To enable this code, #define the HWSIM_RADIOTAP_OUI, | ||
997 | * e.g. like this: | ||
998 | * #define HWSIM_RADIOTAP_OUI "\x02\x00\x00" | ||
999 | * (but you should use a valid OUI, not that) | ||
1000 | * | ||
1001 | * If anyone wants to 'donate' a radiotap OUI/subns code | ||
1002 | * please send a patch removing this #ifdef and changing | ||
1003 | * the values accordingly. | ||
1004 | */ | ||
1005 | #ifdef HWSIM_RADIOTAP_OUI | ||
1006 | struct ieee80211_vendor_radiotap *rtap; | ||
1007 | |||
1008 | /* | ||
1009 | * Note that this code requires the headroom in the SKB | ||
1010 | * that was allocated earlier. | ||
1011 | */ | ||
1012 | rtap = (void *)skb_push(skb, sizeof(*rtap) + 8 + 4); | ||
1013 | rtap->oui[0] = HWSIM_RADIOTAP_OUI[0]; | ||
1014 | rtap->oui[1] = HWSIM_RADIOTAP_OUI[1]; | ||
1015 | rtap->oui[2] = HWSIM_RADIOTAP_OUI[2]; | ||
1016 | rtap->subns = 127; | ||
1017 | |||
1018 | /* | ||
1019 | * Radiotap vendor namespaces can (and should) also be | ||
1020 | * split into fields by using the standard radiotap | ||
1021 | * presence bitmap mechanism. Use just BIT(0) here for | ||
1022 | * the presence bitmap. | ||
1023 | */ | ||
1024 | rtap->present = BIT(0); | ||
1025 | /* We have 8 bytes of (dummy) data */ | ||
1026 | rtap->len = 8; | ||
1027 | /* For testing, also require it to be aligned */ | ||
1028 | rtap->align = 8; | ||
1029 | /* And also test that padding works, 4 bytes */ | ||
1030 | rtap->pad = 4; | ||
1031 | /* push the data */ | ||
1032 | memcpy(rtap->data, "ABCDEFGH", 8); | ||
1033 | /* make sure to clear padding, mac80211 doesn't */ | ||
1034 | memset(rtap->data + 8, 0, 4); | ||
1035 | |||
1036 | IEEE80211_SKB_RXCB(skb)->flag |= RX_FLAG_RADIOTAP_VENDOR_DATA; | ||
1037 | #endif | ||
1038 | } | ||
1039 | |||
987 | static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, | 1040 | static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, |
988 | struct sk_buff *skb, | 1041 | struct sk_buff *skb, |
989 | struct ieee80211_channel *chan) | 1042 | struct ieee80211_channel *chan) |
@@ -1098,6 +1151,9 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, | |||
1098 | rx_status.mactime = now + data2->tsf_offset; | 1151 | rx_status.mactime = now + data2->tsf_offset; |
1099 | 1152 | ||
1100 | memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status)); | 1153 | memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status)); |
1154 | |||
1155 | mac80211_hwsim_add_vendor_rtap(nskb); | ||
1156 | |||
1101 | data2->rx_pkts++; | 1157 | data2->rx_pkts++; |
1102 | data2->rx_bytes += nskb->len; | 1158 | data2->rx_bytes += nskb->len; |
1103 | ieee80211_rx_irqsafe(data2->hw, nskb); | 1159 | ieee80211_rx_irqsafe(data2->hw, nskb); |
@@ -1752,7 +1808,7 @@ static void hw_scan_work(struct work_struct *work) | |||
1752 | struct sk_buff *probe; | 1808 | struct sk_buff *probe; |
1753 | 1809 | ||
1754 | probe = ieee80211_probereq_get(hwsim->hw, | 1810 | probe = ieee80211_probereq_get(hwsim->hw, |
1755 | hwsim->hw_scan_vif, | 1811 | hwsim->scan_addr, |
1756 | req->ssids[i].ssid, | 1812 | req->ssids[i].ssid, |
1757 | req->ssids[i].ssid_len, | 1813 | req->ssids[i].ssid_len, |
1758 | req->ie_len); | 1814 | req->ie_len); |
@@ -1790,6 +1846,12 @@ static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, | |||
1790 | hwsim->hw_scan_request = req; | 1846 | hwsim->hw_scan_request = req; |
1791 | hwsim->hw_scan_vif = vif; | 1847 | hwsim->hw_scan_vif = vif; |
1792 | hwsim->scan_chan_idx = 0; | 1848 | hwsim->scan_chan_idx = 0; |
1849 | if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) | ||
1850 | get_random_mask_addr(hwsim->scan_addr, | ||
1851 | hw_req->req.mac_addr, | ||
1852 | hw_req->req.mac_addr_mask); | ||
1853 | else | ||
1854 | memcpy(hwsim->scan_addr, vif->addr, ETH_ALEN); | ||
1793 | mutex_unlock(&hwsim->mutex); | 1855 | mutex_unlock(&hwsim->mutex); |
1794 | 1856 | ||
1795 | wiphy_debug(hw->wiphy, "hwsim hw_scan request\n"); | 1857 | wiphy_debug(hw->wiphy, "hwsim hw_scan request\n"); |
@@ -1816,7 +1878,9 @@ static void mac80211_hwsim_cancel_hw_scan(struct ieee80211_hw *hw, | |||
1816 | mutex_unlock(&hwsim->mutex); | 1878 | mutex_unlock(&hwsim->mutex); |
1817 | } | 1879 | } |
1818 | 1880 | ||
1819 | static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw) | 1881 | static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw, |
1882 | struct ieee80211_vif *vif, | ||
1883 | const u8 *mac_addr) | ||
1820 | { | 1884 | { |
1821 | struct mac80211_hwsim_data *hwsim = hw->priv; | 1885 | struct mac80211_hwsim_data *hwsim = hw->priv; |
1822 | 1886 | ||
@@ -1828,13 +1892,16 @@ static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw) | |||
1828 | } | 1892 | } |
1829 | 1893 | ||
1830 | printk(KERN_DEBUG "hwsim sw_scan request, prepping stuff\n"); | 1894 | printk(KERN_DEBUG "hwsim sw_scan request, prepping stuff\n"); |
1895 | |||
1896 | memcpy(hwsim->scan_addr, mac_addr, ETH_ALEN); | ||
1831 | hwsim->scanning = true; | 1897 | hwsim->scanning = true; |
1832 | 1898 | ||
1833 | out: | 1899 | out: |
1834 | mutex_unlock(&hwsim->mutex); | 1900 | mutex_unlock(&hwsim->mutex); |
1835 | } | 1901 | } |
1836 | 1902 | ||
1837 | static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw) | 1903 | static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw, |
1904 | struct ieee80211_vif *vif) | ||
1838 | { | 1905 | { |
1839 | struct mac80211_hwsim_data *hwsim = hw->priv; | 1906 | struct mac80211_hwsim_data *hwsim = hw->priv; |
1840 | 1907 | ||
@@ -1842,6 +1909,7 @@ static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw) | |||
1842 | 1909 | ||
1843 | printk(KERN_DEBUG "hwsim sw_scan_complete\n"); | 1910 | printk(KERN_DEBUG "hwsim sw_scan_complete\n"); |
1844 | hwsim->scanning = false; | 1911 | hwsim->scanning = false; |
1912 | memset(hwsim->scan_addr, 0, ETH_ALEN); | ||
1845 | 1913 | ||
1846 | mutex_unlock(&hwsim->mutex); | 1914 | mutex_unlock(&hwsim->mutex); |
1847 | } | 1915 | } |
@@ -2057,36 +2125,26 @@ static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb, | |||
2057 | HWSIM_MCGRP_CONFIG, GFP_KERNEL); | 2125 | HWSIM_MCGRP_CONFIG, GFP_KERNEL); |
2058 | } | 2126 | } |
2059 | 2127 | ||
2060 | static struct sk_buff *build_radio_msg(int cmd, int id, | 2128 | static int append_radio_msg(struct sk_buff *skb, int id, |
2061 | struct hwsim_new_radio_params *param) | 2129 | struct hwsim_new_radio_params *param) |
2062 | { | 2130 | { |
2063 | struct sk_buff *skb; | ||
2064 | void *data; | ||
2065 | int ret; | 2131 | int ret; |
2066 | 2132 | ||
2067 | skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
2068 | if (!skb) | ||
2069 | return NULL; | ||
2070 | |||
2071 | data = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, cmd); | ||
2072 | if (!data) | ||
2073 | goto error; | ||
2074 | |||
2075 | ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id); | 2133 | ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id); |
2076 | if (ret < 0) | 2134 | if (ret < 0) |
2077 | goto error; | 2135 | return ret; |
2078 | 2136 | ||
2079 | if (param->channels) { | 2137 | if (param->channels) { |
2080 | ret = nla_put_u32(skb, HWSIM_ATTR_CHANNELS, param->channels); | 2138 | ret = nla_put_u32(skb, HWSIM_ATTR_CHANNELS, param->channels); |
2081 | if (ret < 0) | 2139 | if (ret < 0) |
2082 | goto error; | 2140 | return ret; |
2083 | } | 2141 | } |
2084 | 2142 | ||
2085 | if (param->reg_alpha2) { | 2143 | if (param->reg_alpha2) { |
2086 | ret = nla_put(skb, HWSIM_ATTR_REG_HINT_ALPHA2, 2, | 2144 | ret = nla_put(skb, HWSIM_ATTR_REG_HINT_ALPHA2, 2, |
2087 | param->reg_alpha2); | 2145 | param->reg_alpha2); |
2088 | if (ret < 0) | 2146 | if (ret < 0) |
2089 | goto error; | 2147 | return ret; |
2090 | } | 2148 | } |
2091 | 2149 | ||
2092 | if (param->regd) { | 2150 | if (param->regd) { |
@@ -2099,54 +2157,64 @@ static struct sk_buff *build_radio_msg(int cmd, int id, | |||
2099 | if (i < ARRAY_SIZE(hwsim_world_regdom_custom)) { | 2157 | if (i < ARRAY_SIZE(hwsim_world_regdom_custom)) { |
2100 | ret = nla_put_u32(skb, HWSIM_ATTR_REG_CUSTOM_REG, i); | 2158 | ret = nla_put_u32(skb, HWSIM_ATTR_REG_CUSTOM_REG, i); |
2101 | if (ret < 0) | 2159 | if (ret < 0) |
2102 | goto error; | 2160 | return ret; |
2103 | } | 2161 | } |
2104 | } | 2162 | } |
2105 | 2163 | ||
2106 | if (param->reg_strict) { | 2164 | if (param->reg_strict) { |
2107 | ret = nla_put_flag(skb, HWSIM_ATTR_REG_STRICT_REG); | 2165 | ret = nla_put_flag(skb, HWSIM_ATTR_REG_STRICT_REG); |
2108 | if (ret < 0) | 2166 | if (ret < 0) |
2109 | goto error; | 2167 | return ret; |
2110 | } | 2168 | } |
2111 | 2169 | ||
2112 | if (param->p2p_device) { | 2170 | if (param->p2p_device) { |
2113 | ret = nla_put_flag(skb, HWSIM_ATTR_SUPPORT_P2P_DEVICE); | 2171 | ret = nla_put_flag(skb, HWSIM_ATTR_SUPPORT_P2P_DEVICE); |
2114 | if (ret < 0) | 2172 | if (ret < 0) |
2115 | goto error; | 2173 | return ret; |
2116 | } | 2174 | } |
2117 | 2175 | ||
2118 | if (param->use_chanctx) { | 2176 | if (param->use_chanctx) { |
2119 | ret = nla_put_flag(skb, HWSIM_ATTR_USE_CHANCTX); | 2177 | ret = nla_put_flag(skb, HWSIM_ATTR_USE_CHANCTX); |
2120 | if (ret < 0) | 2178 | if (ret < 0) |
2121 | goto error; | 2179 | return ret; |
2122 | } | 2180 | } |
2123 | 2181 | ||
2124 | if (param->hwname) { | 2182 | if (param->hwname) { |
2125 | ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, | 2183 | ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, |
2126 | strlen(param->hwname), param->hwname); | 2184 | strlen(param->hwname), param->hwname); |
2127 | if (ret < 0) | 2185 | if (ret < 0) |
2128 | goto error; | 2186 | return ret; |
2129 | } | 2187 | } |
2130 | 2188 | ||
2131 | genlmsg_end(skb, data); | 2189 | return 0; |
2132 | |||
2133 | return skb; | ||
2134 | |||
2135 | error: | ||
2136 | nlmsg_free(skb); | ||
2137 | return NULL; | ||
2138 | } | 2190 | } |
2139 | 2191 | ||
2140 | static void hswim_mcast_new_radio(int id, struct genl_info *info, | 2192 | static void hwsim_mcast_new_radio(int id, struct genl_info *info, |
2141 | struct hwsim_new_radio_params *param) | 2193 | struct hwsim_new_radio_params *param) |
2142 | { | 2194 | { |
2143 | struct sk_buff *mcast_skb; | 2195 | struct sk_buff *mcast_skb; |
2196 | void *data; | ||
2144 | 2197 | ||
2145 | mcast_skb = build_radio_msg(HWSIM_CMD_NEW_RADIO, id, param); | 2198 | mcast_skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); |
2146 | if (!mcast_skb) | 2199 | if (!mcast_skb) |
2147 | return; | 2200 | return; |
2148 | 2201 | ||
2202 | data = genlmsg_put(mcast_skb, 0, 0, &hwsim_genl_family, 0, | ||
2203 | HWSIM_CMD_NEW_RADIO); | ||
2204 | if (!data) | ||
2205 | goto out_err; | ||
2206 | |||
2207 | if (append_radio_msg(mcast_skb, id, param) < 0) | ||
2208 | goto out_err; | ||
2209 | |||
2210 | genlmsg_end(mcast_skb, data); | ||
2211 | |||
2149 | hwsim_mcast_config_msg(mcast_skb, info); | 2212 | hwsim_mcast_config_msg(mcast_skb, info); |
2213 | return; | ||
2214 | |||
2215 | out_err: | ||
2216 | genlmsg_cancel(mcast_skb, data); | ||
2217 | nlmsg_free(mcast_skb); | ||
2150 | } | 2218 | } |
2151 | 2219 | ||
2152 | static int mac80211_hwsim_new_radio(struct genl_info *info, | 2220 | static int mac80211_hwsim_new_radio(struct genl_info *info, |
@@ -2267,7 +2335,8 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, | |||
2267 | hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR | | 2335 | hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR | |
2268 | NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | | 2336 | NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | |
2269 | NL80211_FEATURE_STATIC_SMPS | | 2337 | NL80211_FEATURE_STATIC_SMPS | |
2270 | NL80211_FEATURE_DYNAMIC_SMPS; | 2338 | NL80211_FEATURE_DYNAMIC_SMPS | |
2339 | NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; | ||
2271 | 2340 | ||
2272 | /* ask mac80211 to reserve space for magic */ | 2341 | /* ask mac80211 to reserve space for magic */ |
2273 | hw->vif_data_size = sizeof(struct hwsim_vif_priv); | 2342 | hw->vif_data_size = sizeof(struct hwsim_vif_priv); |
@@ -2353,6 +2422,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, | |||
2353 | if (param->reg_strict) | 2422 | if (param->reg_strict) |
2354 | hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG; | 2423 | hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG; |
2355 | if (param->regd) { | 2424 | if (param->regd) { |
2425 | data->regd = param->regd; | ||
2356 | hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; | 2426 | hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; |
2357 | wiphy_apply_custom_regulatory(hw->wiphy, param->regd); | 2427 | wiphy_apply_custom_regulatory(hw->wiphy, param->regd); |
2358 | /* give the regulatory workqueue a chance to run */ | 2428 | /* give the regulatory workqueue a chance to run */ |
@@ -2371,8 +2441,11 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, | |||
2371 | 2441 | ||
2372 | wiphy_debug(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr); | 2442 | wiphy_debug(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr); |
2373 | 2443 | ||
2374 | if (param->reg_alpha2) | 2444 | if (param->reg_alpha2) { |
2445 | data->alpha2[0] = param->reg_alpha2[0]; | ||
2446 | data->alpha2[1] = param->reg_alpha2[1]; | ||
2375 | regulatory_hint(hw->wiphy, param->reg_alpha2); | 2447 | regulatory_hint(hw->wiphy, param->reg_alpha2); |
2448 | } | ||
2376 | 2449 | ||
2377 | data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir); | 2450 | data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir); |
2378 | debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps); | 2451 | debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps); |
@@ -2392,7 +2465,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, | |||
2392 | spin_unlock_bh(&hwsim_radio_lock); | 2465 | spin_unlock_bh(&hwsim_radio_lock); |
2393 | 2466 | ||
2394 | if (idx > 0) | 2467 | if (idx > 0) |
2395 | hswim_mcast_new_radio(idx, info, param); | 2468 | hwsim_mcast_new_radio(idx, info, param); |
2396 | 2469 | ||
2397 | return idx; | 2470 | return idx; |
2398 | 2471 | ||
@@ -2426,12 +2499,10 @@ static void hwsim_mcast_del_radio(int id, const char *hwname, | |||
2426 | if (ret < 0) | 2499 | if (ret < 0) |
2427 | goto error; | 2500 | goto error; |
2428 | 2501 | ||
2429 | if (hwname) { | 2502 | ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, strlen(hwname), |
2430 | ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, strlen(hwname), | 2503 | hwname); |
2431 | hwname); | 2504 | if (ret < 0) |
2432 | if (ret < 0) | 2505 | goto error; |
2433 | goto error; | ||
2434 | } | ||
2435 | 2506 | ||
2436 | genlmsg_end(skb, data); | 2507 | genlmsg_end(skb, data); |
2437 | 2508 | ||
@@ -2455,6 +2526,44 @@ static void mac80211_hwsim_del_radio(struct mac80211_hwsim_data *data, | |||
2455 | ieee80211_free_hw(data->hw); | 2526 | ieee80211_free_hw(data->hw); |
2456 | } | 2527 | } |
2457 | 2528 | ||
2529 | static int mac80211_hwsim_get_radio(struct sk_buff *skb, | ||
2530 | struct mac80211_hwsim_data *data, | ||
2531 | u32 portid, u32 seq, | ||
2532 | struct netlink_callback *cb, int flags) | ||
2533 | { | ||
2534 | void *hdr; | ||
2535 | struct hwsim_new_radio_params param = { }; | ||
2536 | int res = -EMSGSIZE; | ||
2537 | |||
2538 | hdr = genlmsg_put(skb, portid, seq, &hwsim_genl_family, flags, | ||
2539 | HWSIM_CMD_GET_RADIO); | ||
2540 | if (!hdr) | ||
2541 | return -EMSGSIZE; | ||
2542 | |||
2543 | if (cb) | ||
2544 | genl_dump_check_consistent(cb, hdr, &hwsim_genl_family); | ||
2545 | |||
2546 | param.reg_alpha2 = data->alpha2; | ||
2547 | param.reg_strict = !!(data->hw->wiphy->regulatory_flags & | ||
2548 | REGULATORY_STRICT_REG); | ||
2549 | param.p2p_device = !!(data->hw->wiphy->interface_modes & | ||
2550 | BIT(NL80211_IFTYPE_P2P_DEVICE)); | ||
2551 | param.use_chanctx = data->use_chanctx; | ||
2552 | param.regd = data->regd; | ||
2553 | param.channels = data->channels; | ||
2554 | param.hwname = wiphy_name(data->hw->wiphy); | ||
2555 | |||
2556 | res = append_radio_msg(skb, data->idx, ¶m); | ||
2557 | if (res < 0) | ||
2558 | goto out_err; | ||
2559 | |||
2560 | return genlmsg_end(skb, hdr); | ||
2561 | |||
2562 | out_err: | ||
2563 | genlmsg_cancel(skb, hdr); | ||
2564 | return res; | ||
2565 | } | ||
2566 | |||
2458 | static void mac80211_hwsim_free(void) | 2567 | static void mac80211_hwsim_free(void) |
2459 | { | 2568 | { |
2460 | struct mac80211_hwsim_data *data; | 2569 | struct mac80211_hwsim_data *data; |
@@ -2465,7 +2574,8 @@ static void mac80211_hwsim_free(void) | |||
2465 | list))) { | 2574 | list))) { |
2466 | list_del(&data->list); | 2575 | list_del(&data->list); |
2467 | spin_unlock_bh(&hwsim_radio_lock); | 2576 | spin_unlock_bh(&hwsim_radio_lock); |
2468 | mac80211_hwsim_del_radio(data, NULL, NULL); | 2577 | mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), |
2578 | NULL); | ||
2469 | spin_lock_bh(&hwsim_radio_lock); | 2579 | spin_lock_bh(&hwsim_radio_lock); |
2470 | } | 2580 | } |
2471 | spin_unlock_bh(&hwsim_radio_lock); | 2581 | spin_unlock_bh(&hwsim_radio_lock); |
@@ -2744,14 +2854,14 @@ static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info) | |||
2744 | if (data->idx != idx) | 2854 | if (data->idx != idx) |
2745 | continue; | 2855 | continue; |
2746 | } else { | 2856 | } else { |
2747 | if (hwname && | 2857 | if (strcmp(hwname, wiphy_name(data->hw->wiphy))) |
2748 | strcmp(hwname, wiphy_name(data->hw->wiphy))) | ||
2749 | continue; | 2858 | continue; |
2750 | } | 2859 | } |
2751 | 2860 | ||
2752 | list_del(&data->list); | 2861 | list_del(&data->list); |
2753 | spin_unlock_bh(&hwsim_radio_lock); | 2862 | spin_unlock_bh(&hwsim_radio_lock); |
2754 | mac80211_hwsim_del_radio(data, hwname, info); | 2863 | mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), |
2864 | info); | ||
2755 | return 0; | 2865 | return 0; |
2756 | } | 2866 | } |
2757 | spin_unlock_bh(&hwsim_radio_lock); | 2867 | spin_unlock_bh(&hwsim_radio_lock); |
@@ -2759,6 +2869,77 @@ static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info) | |||
2759 | return -ENODEV; | 2869 | return -ENODEV; |
2760 | } | 2870 | } |
2761 | 2871 | ||
2872 | static int hwsim_get_radio_nl(struct sk_buff *msg, struct genl_info *info) | ||
2873 | { | ||
2874 | struct mac80211_hwsim_data *data; | ||
2875 | struct sk_buff *skb; | ||
2876 | int idx, res = -ENODEV; | ||
2877 | |||
2878 | if (!info->attrs[HWSIM_ATTR_RADIO_ID]) | ||
2879 | return -EINVAL; | ||
2880 | idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]); | ||
2881 | |||
2882 | spin_lock_bh(&hwsim_radio_lock); | ||
2883 | list_for_each_entry(data, &hwsim_radios, list) { | ||
2884 | if (data->idx != idx) | ||
2885 | continue; | ||
2886 | |||
2887 | skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
2888 | if (!skb) { | ||
2889 | res = -ENOMEM; | ||
2890 | goto out_err; | ||
2891 | } | ||
2892 | |||
2893 | res = mac80211_hwsim_get_radio(skb, data, info->snd_portid, | ||
2894 | info->snd_seq, NULL, 0); | ||
2895 | if (res < 0) { | ||
2896 | nlmsg_free(skb); | ||
2897 | goto out_err; | ||
2898 | } | ||
2899 | |||
2900 | genlmsg_reply(skb, info); | ||
2901 | break; | ||
2902 | } | ||
2903 | |||
2904 | out_err: | ||
2905 | spin_unlock_bh(&hwsim_radio_lock); | ||
2906 | |||
2907 | return res; | ||
2908 | } | ||
2909 | |||
2910 | static int hwsim_dump_radio_nl(struct sk_buff *skb, | ||
2911 | struct netlink_callback *cb) | ||
2912 | { | ||
2913 | int idx = cb->args[0]; | ||
2914 | struct mac80211_hwsim_data *data = NULL; | ||
2915 | int res; | ||
2916 | |||
2917 | spin_lock_bh(&hwsim_radio_lock); | ||
2918 | |||
2919 | if (idx == hwsim_radio_idx) | ||
2920 | goto done; | ||
2921 | |||
2922 | list_for_each_entry(data, &hwsim_radios, list) { | ||
2923 | if (data->idx < idx) | ||
2924 | continue; | ||
2925 | |||
2926 | res = mac80211_hwsim_get_radio(skb, data, | ||
2927 | NETLINK_CB(cb->skb).portid, | ||
2928 | cb->nlh->nlmsg_seq, cb, | ||
2929 | NLM_F_MULTI); | ||
2930 | if (res < 0) | ||
2931 | break; | ||
2932 | |||
2933 | idx = data->idx + 1; | ||
2934 | } | ||
2935 | |||
2936 | cb->args[0] = idx; | ||
2937 | |||
2938 | done: | ||
2939 | spin_unlock_bh(&hwsim_radio_lock); | ||
2940 | return skb->len; | ||
2941 | } | ||
2942 | |||
2762 | /* Generic Netlink operations array */ | 2943 | /* Generic Netlink operations array */ |
2763 | static const struct genl_ops hwsim_ops[] = { | 2944 | static const struct genl_ops hwsim_ops[] = { |
2764 | { | 2945 | { |
@@ -2789,6 +2970,12 @@ static const struct genl_ops hwsim_ops[] = { | |||
2789 | .doit = hwsim_del_radio_nl, | 2970 | .doit = hwsim_del_radio_nl, |
2790 | .flags = GENL_ADMIN_PERM, | 2971 | .flags = GENL_ADMIN_PERM, |
2791 | }, | 2972 | }, |
2973 | { | ||
2974 | .cmd = HWSIM_CMD_GET_RADIO, | ||
2975 | .policy = hwsim_genl_policy, | ||
2976 | .doit = hwsim_get_radio_nl, | ||
2977 | .dumpit = hwsim_dump_radio_nl, | ||
2978 | }, | ||
2792 | }; | 2979 | }; |
2793 | 2980 | ||
2794 | static void destroy_radio(struct work_struct *work) | 2981 | static void destroy_radio(struct work_struct *work) |
@@ -2796,7 +2983,7 @@ static void destroy_radio(struct work_struct *work) | |||
2796 | struct mac80211_hwsim_data *data = | 2983 | struct mac80211_hwsim_data *data = |
2797 | container_of(work, struct mac80211_hwsim_data, destroy_work); | 2984 | container_of(work, struct mac80211_hwsim_data, destroy_work); |
2798 | 2985 | ||
2799 | mac80211_hwsim_del_radio(data, NULL, NULL); | 2986 | mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), NULL); |
2800 | } | 2987 | } |
2801 | 2988 | ||
2802 | static void remove_user_radios(u32 portid) | 2989 | static void remove_user_radios(u32 portid) |
diff --git a/drivers/net/wireless/mac80211_hwsim.h b/drivers/net/wireless/mac80211_hwsim.h index f08debdd639b..66e1c73bd507 100644 --- a/drivers/net/wireless/mac80211_hwsim.h +++ b/drivers/net/wireless/mac80211_hwsim.h | |||
@@ -69,6 +69,8 @@ enum hwsim_tx_control_flags { | |||
69 | * returns the radio ID (>= 0) or negative on errors, if successful | 69 | * returns the radio ID (>= 0) or negative on errors, if successful |
70 | * then multicast the result | 70 | * then multicast the result |
71 | * @HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted | 71 | * @HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted |
72 | * @HWSIM_CMD_GET_RADIO: fetch information about existing radios, uses: | ||
73 | * %HWSIM_ATTR_RADIO_ID | ||
72 | * @__HWSIM_CMD_MAX: enum limit | 74 | * @__HWSIM_CMD_MAX: enum limit |
73 | */ | 75 | */ |
74 | enum { | 76 | enum { |
@@ -78,6 +80,7 @@ enum { | |||
78 | HWSIM_CMD_TX_INFO_FRAME, | 80 | HWSIM_CMD_TX_INFO_FRAME, |
79 | HWSIM_CMD_NEW_RADIO, | 81 | HWSIM_CMD_NEW_RADIO, |
80 | HWSIM_CMD_DEL_RADIO, | 82 | HWSIM_CMD_DEL_RADIO, |
83 | HWSIM_CMD_GET_RADIO, | ||
81 | __HWSIM_CMD_MAX, | 84 | __HWSIM_CMD_MAX, |
82 | }; | 85 | }; |
83 | #define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1) | 86 | #define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1) |
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index ef1104476bd8..b8d1e04aa9b9 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -5548,7 +5548,9 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
5548 | return rc; | 5548 | return rc; |
5549 | } | 5549 | } |
5550 | 5550 | ||
5551 | static void mwl8k_sw_scan_start(struct ieee80211_hw *hw) | 5551 | static void mwl8k_sw_scan_start(struct ieee80211_hw *hw, |
5552 | struct ieee80211_vif *vif, | ||
5553 | const u8 *mac_addr) | ||
5552 | { | 5554 | { |
5553 | struct mwl8k_priv *priv = hw->priv; | 5555 | struct mwl8k_priv *priv = hw->priv; |
5554 | u8 tmp; | 5556 | u8 tmp; |
@@ -5565,7 +5567,8 @@ static void mwl8k_sw_scan_start(struct ieee80211_hw *hw) | |||
5565 | priv->sw_scan_start = true; | 5567 | priv->sw_scan_start = true; |
5566 | } | 5568 | } |
5567 | 5569 | ||
5568 | static void mwl8k_sw_scan_complete(struct ieee80211_hw *hw) | 5570 | static void mwl8k_sw_scan_complete(struct ieee80211_hw *hw, |
5571 | struct ieee80211_vif *vif) | ||
5569 | { | 5572 | { |
5570 | struct mwl8k_priv *priv = hw->priv; | 5573 | struct mwl8k_priv *priv = hw->priv; |
5571 | u8 tmp; | 5574 | u8 tmp; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index d13f25cd70d5..1ff81afb672c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -1437,8 +1437,11 @@ int rt2x00mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
1437 | struct ieee80211_sta *sta); | 1437 | struct ieee80211_sta *sta); |
1438 | int rt2x00mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 1438 | int rt2x00mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
1439 | struct ieee80211_sta *sta); | 1439 | struct ieee80211_sta *sta); |
1440 | void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw); | 1440 | void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw, |
1441 | void rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw); | 1441 | struct ieee80211_vif *vif, |
1442 | const u8 *mac_addr); | ||
1443 | void rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw, | ||
1444 | struct ieee80211_vif *vif); | ||
1442 | int rt2x00mac_get_stats(struct ieee80211_hw *hw, | 1445 | int rt2x00mac_get_stats(struct ieee80211_hw *hw, |
1443 | struct ieee80211_low_level_stats *stats); | 1446 | struct ieee80211_low_level_stats *stats); |
1444 | void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, | 1447 | void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, |
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index ad6e5a8d1e10..cb40245a0695 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c | |||
@@ -568,7 +568,9 @@ int rt2x00mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
568 | } | 568 | } |
569 | EXPORT_SYMBOL_GPL(rt2x00mac_sta_remove); | 569 | EXPORT_SYMBOL_GPL(rt2x00mac_sta_remove); |
570 | 570 | ||
571 | void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw) | 571 | void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw, |
572 | struct ieee80211_vif *vif, | ||
573 | const u8 *mac_addr) | ||
572 | { | 574 | { |
573 | struct rt2x00_dev *rt2x00dev = hw->priv; | 575 | struct rt2x00_dev *rt2x00dev = hw->priv; |
574 | set_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); | 576 | set_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); |
@@ -576,7 +578,8 @@ void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw) | |||
576 | } | 578 | } |
577 | EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_start); | 579 | EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_start); |
578 | 580 | ||
579 | void rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw) | 581 | void rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw, |
582 | struct ieee80211_vif *vif) | ||
580 | { | 583 | { |
581 | struct rt2x00_dev *rt2x00dev = hw->priv; | 584 | struct rt2x00_dev *rt2x00dev = hw->priv; |
582 | clear_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); | 585 | clear_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); |
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 07dae0d44abc..af52f0bdb71e 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c | |||
@@ -1361,7 +1361,9 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw, | |||
1361 | return 0; | 1361 | return 0; |
1362 | } | 1362 | } |
1363 | 1363 | ||
1364 | static void rtl_op_sw_scan_start(struct ieee80211_hw *hw) | 1364 | static void rtl_op_sw_scan_start(struct ieee80211_hw *hw, |
1365 | struct ieee80211_vif *vif, | ||
1366 | const u8 *mac_addr) | ||
1365 | { | 1367 | { |
1366 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 1368 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
1367 | struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); | 1369 | struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); |
@@ -1396,7 +1398,8 @@ static void rtl_op_sw_scan_start(struct ieee80211_hw *hw) | |||
1396 | rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_BACKUP_BAND0); | 1398 | rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_BACKUP_BAND0); |
1397 | } | 1399 | } |
1398 | 1400 | ||
1399 | static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw) | 1401 | static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw, |
1402 | struct ieee80211_vif *vif) | ||
1400 | { | 1403 | { |
1401 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 1404 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
1402 | struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); | 1405 | struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); |
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index 38234851457e..0b30a7b4d663 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c | |||
@@ -1029,7 +1029,7 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw, | |||
1029 | goto out_sleep; | 1029 | goto out_sleep; |
1030 | } | 1030 | } |
1031 | 1031 | ||
1032 | skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, | 1032 | skb = ieee80211_probereq_get(wl->hw, wl->vif->addr, ssid, ssid_len, |
1033 | req->ie_len); | 1033 | req->ie_len); |
1034 | if (!skb) { | 1034 | if (!skb) { |
1035 | ret = -ENOMEM; | 1035 | ret = -ENOMEM; |
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index dd2e448c3e2b..b82661962d33 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c | |||
@@ -1145,7 +1145,7 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
1145 | 1145 | ||
1146 | wl1271_debug(DEBUG_SCAN, "build probe request band %d", band); | 1146 | wl1271_debug(DEBUG_SCAN, "build probe request band %d", band); |
1147 | 1147 | ||
1148 | skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, | 1148 | skb = ieee80211_probereq_get(wl->hw, vif->addr, ssid, ssid_len, |
1149 | ie0_len + ie1_len); | 1149 | ie0_len + ie1_len); |
1150 | if (!skb) { | 1150 | if (!skb) { |
1151 | ret = -ENOMEM; | 1151 | ret = -ENOMEM; |
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index 2fbff907ce8a..dbc311c3dc37 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c | |||
@@ -856,7 +856,9 @@ static int vnt_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
856 | return 0; | 856 | return 0; |
857 | } | 857 | } |
858 | 858 | ||
859 | static void vnt_sw_scan_start(struct ieee80211_hw *hw) | 859 | static void vnt_sw_scan_start(struct ieee80211_hw *hw, |
860 | struct ieee80211_vif *vif, | ||
861 | const u8 *addr) | ||
860 | { | 862 | { |
861 | struct vnt_private *priv = hw->priv; | 863 | struct vnt_private *priv = hw->priv; |
862 | 864 | ||
@@ -865,7 +867,8 @@ static void vnt_sw_scan_start(struct ieee80211_hw *hw) | |||
865 | vnt_update_pre_ed_threshold(priv, true); | 867 | vnt_update_pre_ed_threshold(priv, true); |
866 | } | 868 | } |
867 | 869 | ||
868 | static void vnt_sw_scan_complete(struct ieee80211_hw *hw) | 870 | static void vnt_sw_scan_complete(struct ieee80211_hw *hw, |
871 | struct ieee80211_vif *vif) | ||
869 | { | 872 | { |
870 | struct vnt_private *priv = hw->priv; | 873 | struct vnt_private *priv = hw->priv; |
871 | 874 | ||
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index f65b5446d983..4f4eea8a6288 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/types.h> | 19 | #include <linux/types.h> |
20 | #include <linux/if_ether.h> | 20 | #include <linux/if_ether.h> |
21 | #include <asm/byteorder.h> | 21 | #include <asm/byteorder.h> |
22 | #include <asm/unaligned.h> | ||
22 | 23 | ||
23 | /* | 24 | /* |
24 | * DS bit usage | 25 | * DS bit usage |
@@ -1066,6 +1067,12 @@ struct ieee80211_pspoll { | |||
1066 | 1067 | ||
1067 | /* TDLS */ | 1068 | /* TDLS */ |
1068 | 1069 | ||
1070 | /* Channel switch timing */ | ||
1071 | struct ieee80211_ch_switch_timing { | ||
1072 | __le16 switch_time; | ||
1073 | __le16 switch_timeout; | ||
1074 | } __packed; | ||
1075 | |||
1069 | /* Link-id information element */ | 1076 | /* Link-id information element */ |
1070 | struct ieee80211_tdls_lnkie { | 1077 | struct ieee80211_tdls_lnkie { |
1071 | u8 ie_type; /* Link Identifier IE */ | 1078 | u8 ie_type; /* Link Identifier IE */ |
@@ -1107,6 +1114,15 @@ struct ieee80211_tdls_data { | |||
1107 | u8 dialog_token; | 1114 | u8 dialog_token; |
1108 | u8 variable[0]; | 1115 | u8 variable[0]; |
1109 | } __packed discover_req; | 1116 | } __packed discover_req; |
1117 | struct { | ||
1118 | u8 target_channel; | ||
1119 | u8 oper_class; | ||
1120 | u8 variable[0]; | ||
1121 | } __packed chan_switch_req; | ||
1122 | struct { | ||
1123 | __le16 status_code; | ||
1124 | u8 variable[0]; | ||
1125 | } __packed chan_switch_resp; | ||
1110 | } u; | 1126 | } u; |
1111 | } __packed; | 1127 | } __packed; |
1112 | 1128 | ||
@@ -2018,6 +2034,11 @@ enum ieee80211_tdls_actioncode { | |||
2018 | */ | 2034 | */ |
2019 | #define WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING BIT(2) | 2035 | #define WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING BIT(2) |
2020 | 2036 | ||
2037 | /* TDLS capabilities in the the 4th byte of @WLAN_EID_EXT_CAPABILITY */ | ||
2038 | #define WLAN_EXT_CAPA4_TDLS_BUFFER_STA BIT(4) | ||
2039 | #define WLAN_EXT_CAPA4_TDLS_PEER_PSM BIT(5) | ||
2040 | #define WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH BIT(6) | ||
2041 | |||
2021 | /* Interworking capabilities are set in 7th bit of 4th byte of the | 2042 | /* Interworking capabilities are set in 7th bit of 4th byte of the |
2022 | * @WLAN_EID_EXT_CAPABILITY information element | 2043 | * @WLAN_EID_EXT_CAPABILITY information element |
2023 | */ | 2044 | */ |
@@ -2029,6 +2050,7 @@ enum ieee80211_tdls_actioncode { | |||
2029 | */ | 2050 | */ |
2030 | #define WLAN_EXT_CAPA5_TDLS_ENABLED BIT(5) | 2051 | #define WLAN_EXT_CAPA5_TDLS_ENABLED BIT(5) |
2031 | #define WLAN_EXT_CAPA5_TDLS_PROHIBITED BIT(6) | 2052 | #define WLAN_EXT_CAPA5_TDLS_PROHIBITED BIT(6) |
2053 | #define WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED BIT(7) | ||
2032 | 2054 | ||
2033 | #define WLAN_EXT_CAPA8_OPMODE_NOTIF BIT(6) | 2055 | #define WLAN_EXT_CAPA8_OPMODE_NOTIF BIT(6) |
2034 | #define WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED BIT(7) | 2056 | #define WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED BIT(7) |
@@ -2036,6 +2058,9 @@ enum ieee80211_tdls_actioncode { | |||
2036 | /* TDLS specific payload type in the LLC/SNAP header */ | 2058 | /* TDLS specific payload type in the LLC/SNAP header */ |
2037 | #define WLAN_TDLS_SNAP_RFTYPE 0x2 | 2059 | #define WLAN_TDLS_SNAP_RFTYPE 0x2 |
2038 | 2060 | ||
2061 | /* BSS Coex IE information field bits */ | ||
2062 | #define WLAN_BSS_COEX_INFORMATION_REQUEST BIT(0) | ||
2063 | |||
2039 | /** | 2064 | /** |
2040 | * enum - mesh synchronization method identifier | 2065 | * enum - mesh synchronization method identifier |
2041 | * | 2066 | * |
@@ -2418,6 +2443,30 @@ static inline bool ieee80211_check_tim(const struct ieee80211_tim_ie *tim, | |||
2418 | return !!(tim->virtual_map[index] & mask); | 2443 | return !!(tim->virtual_map[index] & mask); |
2419 | } | 2444 | } |
2420 | 2445 | ||
2446 | /** | ||
2447 | * ieee80211_get_tdls_action - get tdls packet action (or -1, if not tdls packet) | ||
2448 | * @skb: the skb containing the frame, length will not be checked | ||
2449 | * @hdr_size: the size of the ieee80211_hdr that starts at skb->data | ||
2450 | * | ||
2451 | * This function assumes the frame is a data frame, and that the network header | ||
2452 | * is in the correct place. | ||
2453 | */ | ||
2454 | static inline int ieee80211_get_tdls_action(struct sk_buff *skb, u32 hdr_size) | ||
2455 | { | ||
2456 | if (!skb_is_nonlinear(skb) && | ||
2457 | skb->len > (skb_network_offset(skb) + 2)) { | ||
2458 | /* Point to where the indication of TDLS should start */ | ||
2459 | const u8 *tdls_data = skb_network_header(skb) - 2; | ||
2460 | |||
2461 | if (get_unaligned_be16(tdls_data) == ETH_P_TDLS && | ||
2462 | tdls_data[2] == WLAN_TDLS_SNAP_RFTYPE && | ||
2463 | tdls_data[3] == WLAN_CATEGORY_TDLS) | ||
2464 | return tdls_data[4]; | ||
2465 | } | ||
2466 | |||
2467 | return -1; | ||
2468 | } | ||
2469 | |||
2421 | /* convert time units */ | 2470 | /* convert time units */ |
2422 | #define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024)) | 2471 | #define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024)) |
2423 | #define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x)) | 2472 | #define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x)) |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 5c3acd07acd9..bb748c4da5af 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -1437,6 +1437,10 @@ struct cfg80211_ssid { | |||
1437 | * @aborted: (internal) scan request was notified as aborted | 1437 | * @aborted: (internal) scan request was notified as aborted |
1438 | * @notified: (internal) scan request was notified as done or aborted | 1438 | * @notified: (internal) scan request was notified as done or aborted |
1439 | * @no_cck: used to send probe requests at non CCK rate in 2GHz band | 1439 | * @no_cck: used to send probe requests at non CCK rate in 2GHz band |
1440 | * @mac_addr: MAC address used with randomisation | ||
1441 | * @mac_addr_mask: MAC address mask used with randomisation, bits that | ||
1442 | * are 0 in the mask should be randomised, bits that are 1 should | ||
1443 | * be taken from the @mac_addr | ||
1440 | */ | 1444 | */ |
1441 | struct cfg80211_scan_request { | 1445 | struct cfg80211_scan_request { |
1442 | struct cfg80211_ssid *ssids; | 1446 | struct cfg80211_ssid *ssids; |
@@ -1451,6 +1455,9 @@ struct cfg80211_scan_request { | |||
1451 | 1455 | ||
1452 | struct wireless_dev *wdev; | 1456 | struct wireless_dev *wdev; |
1453 | 1457 | ||
1458 | u8 mac_addr[ETH_ALEN] __aligned(2); | ||
1459 | u8 mac_addr_mask[ETH_ALEN] __aligned(2); | ||
1460 | |||
1454 | /* internal */ | 1461 | /* internal */ |
1455 | struct wiphy *wiphy; | 1462 | struct wiphy *wiphy; |
1456 | unsigned long scan_start; | 1463 | unsigned long scan_start; |
@@ -1461,6 +1468,17 @@ struct cfg80211_scan_request { | |||
1461 | struct ieee80211_channel *channels[0]; | 1468 | struct ieee80211_channel *channels[0]; |
1462 | }; | 1469 | }; |
1463 | 1470 | ||
1471 | static inline void get_random_mask_addr(u8 *buf, const u8 *addr, const u8 *mask) | ||
1472 | { | ||
1473 | int i; | ||
1474 | |||
1475 | get_random_bytes(buf, ETH_ALEN); | ||
1476 | for (i = 0; i < ETH_ALEN; i++) { | ||
1477 | buf[i] &= ~mask[i]; | ||
1478 | buf[i] |= addr[i] & mask[i]; | ||
1479 | } | ||
1480 | } | ||
1481 | |||
1464 | /** | 1482 | /** |
1465 | * struct cfg80211_match_set - sets of attributes to match | 1483 | * struct cfg80211_match_set - sets of attributes to match |
1466 | * | 1484 | * |
@@ -1494,6 +1512,10 @@ struct cfg80211_match_set { | |||
1494 | * @channels: channels to scan | 1512 | * @channels: channels to scan |
1495 | * @min_rssi_thold: for drivers only supporting a single threshold, this | 1513 | * @min_rssi_thold: for drivers only supporting a single threshold, this |
1496 | * contains the minimum over all matchsets | 1514 | * contains the minimum over all matchsets |
1515 | * @mac_addr: MAC address used with randomisation | ||
1516 | * @mac_addr_mask: MAC address mask used with randomisation, bits that | ||
1517 | * are 0 in the mask should be randomised, bits that are 1 should | ||
1518 | * be taken from the @mac_addr | ||
1497 | */ | 1519 | */ |
1498 | struct cfg80211_sched_scan_request { | 1520 | struct cfg80211_sched_scan_request { |
1499 | struct cfg80211_ssid *ssids; | 1521 | struct cfg80211_ssid *ssids; |
@@ -1508,6 +1530,9 @@ struct cfg80211_sched_scan_request { | |||
1508 | int n_match_sets; | 1530 | int n_match_sets; |
1509 | s32 min_rssi_thold; | 1531 | s32 min_rssi_thold; |
1510 | 1532 | ||
1533 | u8 mac_addr[ETH_ALEN] __aligned(2); | ||
1534 | u8 mac_addr_mask[ETH_ALEN] __aligned(2); | ||
1535 | |||
1511 | /* internal */ | 1536 | /* internal */ |
1512 | struct wiphy *wiphy; | 1537 | struct wiphy *wiphy; |
1513 | struct net_device *dev; | 1538 | struct net_device *dev; |
@@ -1940,6 +1965,7 @@ struct cfg80211_wowlan_tcp { | |||
1940 | * @rfkill_release: wake up when rfkill is released | 1965 | * @rfkill_release: wake up when rfkill is released |
1941 | * @tcp: TCP connection establishment/wakeup parameters, see nl80211.h. | 1966 | * @tcp: TCP connection establishment/wakeup parameters, see nl80211.h. |
1942 | * NULL if not configured. | 1967 | * NULL if not configured. |
1968 | * @nd_config: configuration for the scan to be used for net detect wake. | ||
1943 | */ | 1969 | */ |
1944 | struct cfg80211_wowlan { | 1970 | struct cfg80211_wowlan { |
1945 | bool any, disconnect, magic_pkt, gtk_rekey_failure, | 1971 | bool any, disconnect, magic_pkt, gtk_rekey_failure, |
@@ -1948,6 +1974,7 @@ struct cfg80211_wowlan { | |||
1948 | struct cfg80211_pkt_pattern *patterns; | 1974 | struct cfg80211_pkt_pattern *patterns; |
1949 | struct cfg80211_wowlan_tcp *tcp; | 1975 | struct cfg80211_wowlan_tcp *tcp; |
1950 | int n_patterns; | 1976 | int n_patterns; |
1977 | struct cfg80211_sched_scan_request *nd_config; | ||
1951 | }; | 1978 | }; |
1952 | 1979 | ||
1953 | /** | 1980 | /** |
@@ -1980,6 +2007,35 @@ struct cfg80211_coalesce { | |||
1980 | }; | 2007 | }; |
1981 | 2008 | ||
1982 | /** | 2009 | /** |
2010 | * struct cfg80211_wowlan_nd_match - information about the match | ||
2011 | * | ||
2012 | * @ssid: SSID of the match that triggered the wake up | ||
2013 | * @n_channels: Number of channels where the match occurred. This | ||
2014 | * value may be zero if the driver can't report the channels. | ||
2015 | * @channels: center frequencies of the channels where a match | ||
2016 | * occurred (in MHz) | ||
2017 | */ | ||
2018 | struct cfg80211_wowlan_nd_match { | ||
2019 | struct cfg80211_ssid ssid; | ||
2020 | int n_channels; | ||
2021 | u32 channels[]; | ||
2022 | }; | ||
2023 | |||
2024 | /** | ||
2025 | * struct cfg80211_wowlan_nd_info - net detect wake up information | ||
2026 | * | ||
2027 | * @n_matches: Number of match information instances provided in | ||
2028 | * @matches. This value may be zero if the driver can't provide | ||
2029 | * match information. | ||
2030 | * @matches: Array of pointers to matches containing information about | ||
2031 | * the matches that triggered the wake up. | ||
2032 | */ | ||
2033 | struct cfg80211_wowlan_nd_info { | ||
2034 | int n_matches; | ||
2035 | struct cfg80211_wowlan_nd_match *matches[]; | ||
2036 | }; | ||
2037 | |||
2038 | /** | ||
1983 | * struct cfg80211_wowlan_wakeup - wakeup report | 2039 | * struct cfg80211_wowlan_wakeup - wakeup report |
1984 | * @disconnect: woke up by getting disconnected | 2040 | * @disconnect: woke up by getting disconnected |
1985 | * @magic_pkt: woke up by receiving magic packet | 2041 | * @magic_pkt: woke up by receiving magic packet |
@@ -1998,6 +2054,7 @@ struct cfg80211_coalesce { | |||
1998 | * @tcp_match: TCP wakeup packet received | 2054 | * @tcp_match: TCP wakeup packet received |
1999 | * @tcp_connlost: TCP connection lost or failed to establish | 2055 | * @tcp_connlost: TCP connection lost or failed to establish |
2000 | * @tcp_nomoretokens: TCP data ran out of tokens | 2056 | * @tcp_nomoretokens: TCP data ran out of tokens |
2057 | * @net_detect: if not %NULL, woke up because of net detect | ||
2001 | */ | 2058 | */ |
2002 | struct cfg80211_wowlan_wakeup { | 2059 | struct cfg80211_wowlan_wakeup { |
2003 | bool disconnect, magic_pkt, gtk_rekey_failure, | 2060 | bool disconnect, magic_pkt, gtk_rekey_failure, |
@@ -2007,6 +2064,7 @@ struct cfg80211_wowlan_wakeup { | |||
2007 | s32 pattern_idx; | 2064 | s32 pattern_idx; |
2008 | u32 packet_present_len, packet_len; | 2065 | u32 packet_present_len, packet_len; |
2009 | const void *packet; | 2066 | const void *packet; |
2067 | struct cfg80211_wowlan_nd_info *net_detect; | ||
2010 | }; | 2068 | }; |
2011 | 2069 | ||
2012 | /** | 2070 | /** |
@@ -2367,6 +2425,12 @@ struct cfg80211_qos_map { | |||
2367 | * (invoked with the wireless_dev mutex held) | 2425 | * (invoked with the wireless_dev mutex held) |
2368 | * @leave_ocb: leave the current OCB network | 2426 | * @leave_ocb: leave the current OCB network |
2369 | * (invoked with the wireless_dev mutex held) | 2427 | * (invoked with the wireless_dev mutex held) |
2428 | * | ||
2429 | * @tdls_channel_switch: Start channel-switching with a TDLS peer. The driver | ||
2430 | * is responsible for continually initiating channel-switching operations | ||
2431 | * and returning to the base channel for communication with the AP. | ||
2432 | * @tdls_cancel_channel_switch: Stop channel-switching with a TDLS peer. Both | ||
2433 | * peers must be on the base channel when the call completes. | ||
2370 | */ | 2434 | */ |
2371 | struct cfg80211_ops { | 2435 | struct cfg80211_ops { |
2372 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); | 2436 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); |
@@ -2622,6 +2686,14 @@ struct cfg80211_ops { | |||
2622 | u16 admitted_time); | 2686 | u16 admitted_time); |
2623 | int (*del_tx_ts)(struct wiphy *wiphy, struct net_device *dev, | 2687 | int (*del_tx_ts)(struct wiphy *wiphy, struct net_device *dev, |
2624 | u8 tsid, const u8 *peer); | 2688 | u8 tsid, const u8 *peer); |
2689 | |||
2690 | int (*tdls_channel_switch)(struct wiphy *wiphy, | ||
2691 | struct net_device *dev, | ||
2692 | const u8 *addr, u8 oper_class, | ||
2693 | struct cfg80211_chan_def *chandef); | ||
2694 | void (*tdls_cancel_channel_switch)(struct wiphy *wiphy, | ||
2695 | struct net_device *dev, | ||
2696 | const u8 *addr); | ||
2625 | }; | 2697 | }; |
2626 | 2698 | ||
2627 | /* | 2699 | /* |
@@ -2796,6 +2868,7 @@ struct ieee80211_txrx_stypes { | |||
2796 | * @WIPHY_WOWLAN_EAP_IDENTITY_REQ: supports wakeup on EAP identity request | 2868 | * @WIPHY_WOWLAN_EAP_IDENTITY_REQ: supports wakeup on EAP identity request |
2797 | * @WIPHY_WOWLAN_4WAY_HANDSHAKE: supports wakeup on 4-way handshake failure | 2869 | * @WIPHY_WOWLAN_4WAY_HANDSHAKE: supports wakeup on 4-way handshake failure |
2798 | * @WIPHY_WOWLAN_RFKILL_RELEASE: supports wakeup on RF-kill release | 2870 | * @WIPHY_WOWLAN_RFKILL_RELEASE: supports wakeup on RF-kill release |
2871 | * @WIPHY_WOWLAN_NET_DETECT: supports wakeup on network detection | ||
2799 | */ | 2872 | */ |
2800 | enum wiphy_wowlan_support_flags { | 2873 | enum wiphy_wowlan_support_flags { |
2801 | WIPHY_WOWLAN_ANY = BIT(0), | 2874 | WIPHY_WOWLAN_ANY = BIT(0), |
@@ -2806,6 +2879,7 @@ enum wiphy_wowlan_support_flags { | |||
2806 | WIPHY_WOWLAN_EAP_IDENTITY_REQ = BIT(5), | 2879 | WIPHY_WOWLAN_EAP_IDENTITY_REQ = BIT(5), |
2807 | WIPHY_WOWLAN_4WAY_HANDSHAKE = BIT(6), | 2880 | WIPHY_WOWLAN_4WAY_HANDSHAKE = BIT(6), |
2808 | WIPHY_WOWLAN_RFKILL_RELEASE = BIT(7), | 2881 | WIPHY_WOWLAN_RFKILL_RELEASE = BIT(7), |
2882 | WIPHY_WOWLAN_NET_DETECT = BIT(8), | ||
2809 | }; | 2883 | }; |
2810 | 2884 | ||
2811 | struct wiphy_wowlan_tcp_support { | 2885 | struct wiphy_wowlan_tcp_support { |
@@ -2824,6 +2898,11 @@ struct wiphy_wowlan_tcp_support { | |||
2824 | * @pattern_max_len: maximum length of each pattern | 2898 | * @pattern_max_len: maximum length of each pattern |
2825 | * @pattern_min_len: minimum length of each pattern | 2899 | * @pattern_min_len: minimum length of each pattern |
2826 | * @max_pkt_offset: maximum Rx packet offset | 2900 | * @max_pkt_offset: maximum Rx packet offset |
2901 | * @max_nd_match_sets: maximum number of matchsets for net-detect, | ||
2902 | * similar, but not necessarily identical, to max_match_sets for | ||
2903 | * scheduled scans. | ||
2904 | * See &struct cfg80211_sched_scan_request.@match_sets for more | ||
2905 | * details. | ||
2827 | * @tcp: TCP wakeup support information | 2906 | * @tcp: TCP wakeup support information |
2828 | */ | 2907 | */ |
2829 | struct wiphy_wowlan_support { | 2908 | struct wiphy_wowlan_support { |
@@ -2832,6 +2911,7 @@ struct wiphy_wowlan_support { | |||
2832 | int pattern_max_len; | 2911 | int pattern_max_len; |
2833 | int pattern_min_len; | 2912 | int pattern_min_len; |
2834 | int max_pkt_offset; | 2913 | int max_pkt_offset; |
2914 | int max_nd_match_sets; | ||
2835 | const struct wiphy_wowlan_tcp_support *tcp; | 2915 | const struct wiphy_wowlan_tcp_support *tcp; |
2836 | }; | 2916 | }; |
2837 | 2917 | ||
@@ -4719,6 +4799,20 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy, | |||
4719 | void cfg80211_ch_switch_notify(struct net_device *dev, | 4799 | void cfg80211_ch_switch_notify(struct net_device *dev, |
4720 | struct cfg80211_chan_def *chandef); | 4800 | struct cfg80211_chan_def *chandef); |
4721 | 4801 | ||
4802 | /* | ||
4803 | * cfg80211_ch_switch_started_notify - notify channel switch start | ||
4804 | * @dev: the device on which the channel switch started | ||
4805 | * @chandef: the future channel definition | ||
4806 | * @count: the number of TBTTs until the channel switch happens | ||
4807 | * | ||
4808 | * Inform the userspace about the channel switch that has just | ||
4809 | * started, so that it can take appropriate actions (eg. starting | ||
4810 | * channel switch on other vifs), if necessary. | ||
4811 | */ | ||
4812 | void cfg80211_ch_switch_started_notify(struct net_device *dev, | ||
4813 | struct cfg80211_chan_def *chandef, | ||
4814 | u8 count); | ||
4815 | |||
4722 | /** | 4816 | /** |
4723 | * ieee80211_operating_class_to_band - convert operating class to band | 4817 | * ieee80211_operating_class_to_band - convert operating class to band |
4724 | * | 4818 | * |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5f203a6a5e7e..cff3a26a9dae 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -882,6 +882,9 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) | |||
882 | * subframes share the same sequence number. Reported subframes can be | 882 | * subframes share the same sequence number. Reported subframes can be |
883 | * either regular MSDU or singly A-MSDUs. Subframes must not be | 883 | * either regular MSDU or singly A-MSDUs. Subframes must not be |
884 | * interleaved with other frames. | 884 | * interleaved with other frames. |
885 | * @RX_FLAG_RADIOTAP_VENDOR_DATA: This frame contains vendor-specific | ||
886 | * radiotap data in the skb->data (before the frame) as described by | ||
887 | * the &struct ieee80211_vendor_radiotap. | ||
885 | */ | 888 | */ |
886 | enum mac80211_rx_flags { | 889 | enum mac80211_rx_flags { |
887 | RX_FLAG_MMIC_ERROR = BIT(0), | 890 | RX_FLAG_MMIC_ERROR = BIT(0), |
@@ -911,6 +914,7 @@ enum mac80211_rx_flags { | |||
911 | RX_FLAG_10MHZ = BIT(28), | 914 | RX_FLAG_10MHZ = BIT(28), |
912 | RX_FLAG_5MHZ = BIT(29), | 915 | RX_FLAG_5MHZ = BIT(29), |
913 | RX_FLAG_AMSDU_MORE = BIT(30), | 916 | RX_FLAG_AMSDU_MORE = BIT(30), |
917 | RX_FLAG_RADIOTAP_VENDOR_DATA = BIT(31), | ||
914 | }; | 918 | }; |
915 | 919 | ||
916 | #define RX_FLAG_STBC_SHIFT 26 | 920 | #define RX_FLAG_STBC_SHIFT 26 |
@@ -982,6 +986,39 @@ struct ieee80211_rx_status { | |||
982 | }; | 986 | }; |
983 | 987 | ||
984 | /** | 988 | /** |
989 | * struct ieee80211_vendor_radiotap - vendor radiotap data information | ||
990 | * @present: presence bitmap for this vendor namespace | ||
991 | * (this could be extended in the future if any vendor needs more | ||
992 | * bits, the radiotap spec does allow for that) | ||
993 | * @align: radiotap vendor namespace alignment. This defines the needed | ||
994 | * alignment for the @data field below, not for the vendor namespace | ||
995 | * description itself (which has a fixed 2-byte alignment) | ||
996 | * Must be a power of two, and be set to at least 1! | ||
997 | * @oui: radiotap vendor namespace OUI | ||
998 | * @subns: radiotap vendor sub namespace | ||
999 | * @len: radiotap vendor sub namespace skip length, if alignment is done | ||
1000 | * then that's added to this, i.e. this is only the length of the | ||
1001 | * @data field. | ||
1002 | * @pad: number of bytes of padding after the @data, this exists so that | ||
1003 | * the skb data alignment can be preserved even if the data has odd | ||
1004 | * length | ||
1005 | * @data: the actual vendor namespace data | ||
1006 | * | ||
1007 | * This struct, including the vendor data, goes into the skb->data before | ||
1008 | * the 802.11 header. It's split up in mac80211 using the align/oui/subns | ||
1009 | * data. | ||
1010 | */ | ||
1011 | struct ieee80211_vendor_radiotap { | ||
1012 | u32 present; | ||
1013 | u8 align; | ||
1014 | u8 oui[3]; | ||
1015 | u8 subns; | ||
1016 | u8 pad; | ||
1017 | u16 len; | ||
1018 | u8 data[]; | ||
1019 | } __packed; | ||
1020 | |||
1021 | /** | ||
985 | * enum ieee80211_conf_flags - configuration flags | 1022 | * enum ieee80211_conf_flags - configuration flags |
986 | * | 1023 | * |
987 | * Flags to define PHY configuration options | 1024 | * Flags to define PHY configuration options |
@@ -1790,6 +1827,31 @@ struct ieee80211_scan_request { | |||
1790 | }; | 1827 | }; |
1791 | 1828 | ||
1792 | /** | 1829 | /** |
1830 | * struct ieee80211_tdls_ch_sw_params - TDLS channel switch parameters | ||
1831 | * | ||
1832 | * @sta: peer this TDLS channel-switch request/response came from | ||
1833 | * @chandef: channel referenced in a TDLS channel-switch request | ||
1834 | * @action_code: see &enum ieee80211_tdls_actioncode | ||
1835 | * @status: channel-switch response status | ||
1836 | * @timestamp: time at which the frame was received | ||
1837 | * @switch_time: switch-timing parameter received in the frame | ||
1838 | * @switch_timeout: switch-timing parameter received in the frame | ||
1839 | * @tmpl_skb: TDLS switch-channel response template | ||
1840 | * @ch_sw_tm_ie: offset of the channel-switch timing IE inside @tmpl_skb | ||
1841 | */ | ||
1842 | struct ieee80211_tdls_ch_sw_params { | ||
1843 | struct ieee80211_sta *sta; | ||
1844 | struct cfg80211_chan_def *chandef; | ||
1845 | u8 action_code; | ||
1846 | u32 status; | ||
1847 | u32 timestamp; | ||
1848 | u16 switch_time; | ||
1849 | u16 switch_timeout; | ||
1850 | struct sk_buff *tmpl_skb; | ||
1851 | u32 ch_sw_tm_ie; | ||
1852 | }; | ||
1853 | |||
1854 | /** | ||
1793 | * wiphy_to_ieee80211_hw - return a mac80211 driver hw struct from a wiphy | 1855 | * wiphy_to_ieee80211_hw - return a mac80211 driver hw struct from a wiphy |
1794 | * | 1856 | * |
1795 | * @wiphy: the &struct wiphy which we want to query | 1857 | * @wiphy: the &struct wiphy which we want to query |
@@ -2560,7 +2622,9 @@ enum ieee80211_reconfig_type { | |||
2560 | * | 2622 | * |
2561 | * @sw_scan_start: Notifier function that is called just before a software scan | 2623 | * @sw_scan_start: Notifier function that is called just before a software scan |
2562 | * is started. Can be NULL, if the driver doesn't need this notification. | 2624 | * is started. Can be NULL, if the driver doesn't need this notification. |
2563 | * The callback can sleep. | 2625 | * The mac_addr parameter allows supporting NL80211_SCAN_FLAG_RANDOM_ADDR, |
2626 | * the driver may set the NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR flag if it | ||
2627 | * can use this parameter. The callback can sleep. | ||
2564 | * | 2628 | * |
2565 | * @sw_scan_complete: Notifier function that is called just after a | 2629 | * @sw_scan_complete: Notifier function that is called just after a |
2566 | * software scan finished. Can be NULL, if the driver doesn't need | 2630 | * software scan finished. Can be NULL, if the driver doesn't need |
@@ -2631,6 +2695,9 @@ enum ieee80211_reconfig_type { | |||
2631 | * uses hardware rate control (%IEEE80211_HW_HAS_RATE_CONTROL) since | 2695 | * uses hardware rate control (%IEEE80211_HW_HAS_RATE_CONTROL) since |
2632 | * otherwise the rate control algorithm is notified directly. | 2696 | * otherwise the rate control algorithm is notified directly. |
2633 | * Must be atomic. | 2697 | * Must be atomic. |
2698 | * @sta_rate_tbl_update: Notifies the driver that the rate table changed. This | ||
2699 | * is only used if the configured rate control algorithm actually uses | ||
2700 | * the new rate table API, and is therefore optional. Must be atomic. | ||
2634 | * | 2701 | * |
2635 | * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), | 2702 | * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), |
2636 | * bursting) for a hardware TX queue. | 2703 | * bursting) for a hardware TX queue. |
@@ -2878,6 +2945,23 @@ enum ieee80211_reconfig_type { | |||
2878 | * | 2945 | * |
2879 | * @get_txpower: get current maximum tx power (in dBm) based on configuration | 2946 | * @get_txpower: get current maximum tx power (in dBm) based on configuration |
2880 | * and hardware limits. | 2947 | * and hardware limits. |
2948 | * | ||
2949 | * @tdls_channel_switch: Start channel-switching with a TDLS peer. The driver | ||
2950 | * is responsible for continually initiating channel-switching operations | ||
2951 | * and returning to the base channel for communication with the AP. The | ||
2952 | * driver receives a channel-switch request template and the location of | ||
2953 | * the switch-timing IE within the template as part of the invocation. | ||
2954 | * The template is valid only within the call, and the driver can | ||
2955 | * optionally copy the skb for further re-use. | ||
2956 | * @tdls_cancel_channel_switch: Stop channel-switching with a TDLS peer. Both | ||
2957 | * peers must be on the base channel when the call completes. | ||
2958 | * @tdls_recv_channel_switch: a TDLS channel-switch related frame (request or | ||
2959 | * response) has been received from a remote peer. The driver gets | ||
2960 | * parameters parsed from the incoming frame and may use them to continue | ||
2961 | * an ongoing channel-switch operation. In addition, a channel-switch | ||
2962 | * response template is provided, together with the location of the | ||
2963 | * switch-timing IE within the template. The skb can only be used within | ||
2964 | * the function call. | ||
2881 | */ | 2965 | */ |
2882 | struct ieee80211_ops { | 2966 | struct ieee80211_ops { |
2883 | void (*tx)(struct ieee80211_hw *hw, | 2967 | void (*tx)(struct ieee80211_hw *hw, |
@@ -2937,8 +3021,11 @@ struct ieee80211_ops { | |||
2937 | struct ieee80211_scan_ies *ies); | 3021 | struct ieee80211_scan_ies *ies); |
2938 | int (*sched_scan_stop)(struct ieee80211_hw *hw, | 3022 | int (*sched_scan_stop)(struct ieee80211_hw *hw, |
2939 | struct ieee80211_vif *vif); | 3023 | struct ieee80211_vif *vif); |
2940 | void (*sw_scan_start)(struct ieee80211_hw *hw); | 3024 | void (*sw_scan_start)(struct ieee80211_hw *hw, |
2941 | void (*sw_scan_complete)(struct ieee80211_hw *hw); | 3025 | struct ieee80211_vif *vif, |
3026 | const u8 *mac_addr); | ||
3027 | void (*sw_scan_complete)(struct ieee80211_hw *hw, | ||
3028 | struct ieee80211_vif *vif); | ||
2942 | int (*get_stats)(struct ieee80211_hw *hw, | 3029 | int (*get_stats)(struct ieee80211_hw *hw, |
2943 | struct ieee80211_low_level_stats *stats); | 3030 | struct ieee80211_low_level_stats *stats); |
2944 | void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx, | 3031 | void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx, |
@@ -2972,6 +3059,9 @@ struct ieee80211_ops { | |||
2972 | struct ieee80211_vif *vif, | 3059 | struct ieee80211_vif *vif, |
2973 | struct ieee80211_sta *sta, | 3060 | struct ieee80211_sta *sta, |
2974 | u32 changed); | 3061 | u32 changed); |
3062 | void (*sta_rate_tbl_update)(struct ieee80211_hw *hw, | ||
3063 | struct ieee80211_vif *vif, | ||
3064 | struct ieee80211_sta *sta); | ||
2975 | int (*conf_tx)(struct ieee80211_hw *hw, | 3065 | int (*conf_tx)(struct ieee80211_hw *hw, |
2976 | struct ieee80211_vif *vif, u16 ac, | 3066 | struct ieee80211_vif *vif, u16 ac, |
2977 | const struct ieee80211_tx_queue_params *params); | 3067 | const struct ieee80211_tx_queue_params *params); |
@@ -3089,6 +3179,18 @@ struct ieee80211_ops { | |||
3089 | u32 (*get_expected_throughput)(struct ieee80211_sta *sta); | 3179 | u32 (*get_expected_throughput)(struct ieee80211_sta *sta); |
3090 | int (*get_txpower)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 3180 | int (*get_txpower)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
3091 | int *dbm); | 3181 | int *dbm); |
3182 | |||
3183 | int (*tdls_channel_switch)(struct ieee80211_hw *hw, | ||
3184 | struct ieee80211_vif *vif, | ||
3185 | struct ieee80211_sta *sta, u8 oper_class, | ||
3186 | struct cfg80211_chan_def *chandef, | ||
3187 | struct sk_buff *tmpl_skb, u32 ch_sw_tm_ie); | ||
3188 | void (*tdls_cancel_channel_switch)(struct ieee80211_hw *hw, | ||
3189 | struct ieee80211_vif *vif, | ||
3190 | struct ieee80211_sta *sta); | ||
3191 | void (*tdls_recv_channel_switch)(struct ieee80211_hw *hw, | ||
3192 | struct ieee80211_vif *vif, | ||
3193 | struct ieee80211_tdls_ch_sw_params *params); | ||
3092 | }; | 3194 | }; |
3093 | 3195 | ||
3094 | /** | 3196 | /** |
@@ -3729,7 +3831,7 @@ struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, | |||
3729 | /** | 3831 | /** |
3730 | * ieee80211_probereq_get - retrieve a Probe Request template | 3832 | * ieee80211_probereq_get - retrieve a Probe Request template |
3731 | * @hw: pointer obtained from ieee80211_alloc_hw(). | 3833 | * @hw: pointer obtained from ieee80211_alloc_hw(). |
3732 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. | 3834 | * @src_addr: source MAC address |
3733 | * @ssid: SSID buffer | 3835 | * @ssid: SSID buffer |
3734 | * @ssid_len: length of SSID | 3836 | * @ssid_len: length of SSID |
3735 | * @tailroom: tailroom to reserve at end of SKB for IEs | 3837 | * @tailroom: tailroom to reserve at end of SKB for IEs |
@@ -3740,7 +3842,7 @@ struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, | |||
3740 | * Return: The Probe Request template. %NULL on error. | 3842 | * Return: The Probe Request template. %NULL on error. |
3741 | */ | 3843 | */ |
3742 | struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, | 3844 | struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, |
3743 | struct ieee80211_vif *vif, | 3845 | const u8 *src_addr, |
3744 | const u8 *ssid, size_t ssid_len, | 3846 | const u8 *ssid, size_t ssid_len, |
3745 | size_t tailroom); | 3847 | size_t tailroom); |
3746 | 3848 | ||
@@ -4980,6 +5082,43 @@ void ieee80211_tdls_oper_request(struct ieee80211_vif *vif, const u8 *peer, | |||
4980 | u16 reason_code, gfp_t gfp); | 5082 | u16 reason_code, gfp_t gfp); |
4981 | 5083 | ||
4982 | /** | 5084 | /** |
5085 | * ieee80211_reserve_tid - request to reserve a specific TID | ||
5086 | * | ||
5087 | * There is sometimes a need (such as in TDLS) for blocking the driver from | ||
5088 | * using a specific TID so that the FW can use it for certain operations such | ||
5089 | * as sending PTI requests. To make sure that the driver doesn't use that TID, | ||
5090 | * this function must be called as it flushes out packets on this TID and marks | ||
5091 | * it as blocked, so that any transmit for the station on this TID will be | ||
5092 | * redirected to the alternative TID in the same AC. | ||
5093 | * | ||
5094 | * Note that this function blocks and may call back into the driver, so it | ||
5095 | * should be called without driver locks held. Also note this function should | ||
5096 | * only be called from the driver's @sta_state callback. | ||
5097 | * | ||
5098 | * @sta: the station to reserve the TID for | ||
5099 | * @tid: the TID to reserve | ||
5100 | * | ||
5101 | * Returns: 0 on success, else on failure | ||
5102 | */ | ||
5103 | int ieee80211_reserve_tid(struct ieee80211_sta *sta, u8 tid); | ||
5104 | |||
5105 | /** | ||
5106 | * ieee80211_unreserve_tid - request to unreserve a specific TID | ||
5107 | * | ||
5108 | * Once there is no longer any need for reserving a certain TID, this function | ||
5109 | * should be called, and no longer will packets have their TID modified for | ||
5110 | * preventing use of this TID in the driver. | ||
5111 | * | ||
5112 | * Note that this function blocks and acquires a lock, so it should be called | ||
5113 | * without driver locks held. Also note this function should only be called | ||
5114 | * from the driver's @sta_state callback. | ||
5115 | * | ||
5116 | * @sta: the station | ||
5117 | * @tid: the TID to unreserve | ||
5118 | */ | ||
5119 | void ieee80211_unreserve_tid(struct ieee80211_sta *sta, u8 tid); | ||
5120 | |||
5121 | /** | ||
4983 | * ieee80211_ie_split - split an IE buffer according to ordering | 5122 | * ieee80211_ie_split - split an IE buffer according to ordering |
4984 | * | 5123 | * |
4985 | * @ies: the IE buffer | 5124 | * @ies: the IE buffer |
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 9b3025e4377a..d77524510435 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h | |||
@@ -643,7 +643,18 @@ | |||
643 | * @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels | 643 | * @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels |
644 | * independently of the userspace SME, send this event indicating | 644 | * independently of the userspace SME, send this event indicating |
645 | * %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ and the | 645 | * %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ and the |
646 | * attributes determining channel width. | 646 | * attributes determining channel width. This indication may also be |
647 | * sent when a remotely-initiated switch (e.g., when a STA receives a CSA | ||
648 | * from the remote AP) is completed; | ||
649 | * | ||
650 | * @NL80211_CMD_CH_SWITCH_STARTED_NOTIFY: Notify that a channel switch | ||
651 | * has been started on an interface, regardless of the initiator | ||
652 | * (ie. whether it was requested from a remote device or | ||
653 | * initiated on our own). It indicates that | ||
654 | * %NL80211_ATTR_IFINDEX will be on %NL80211_ATTR_WIPHY_FREQ | ||
655 | * after %NL80211_ATTR_CH_SWITCH_COUNT TBTT's. The userspace may | ||
656 | * decide to react to this indication by requesting other | ||
657 | * interfaces to change channel as well. | ||
647 | * | 658 | * |
648 | * @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by | 659 | * @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by |
649 | * its %NL80211_ATTR_WDEV identifier. It must have been created with | 660 | * its %NL80211_ATTR_WDEV identifier. It must have been created with |
@@ -751,6 +762,18 @@ | |||
751 | * @NL80211_CMD_LEAVE_OCB: Leave the OCB network -- no special arguments, the | 762 | * @NL80211_CMD_LEAVE_OCB: Leave the OCB network -- no special arguments, the |
752 | * network is determined by the network interface. | 763 | * network is determined by the network interface. |
753 | * | 764 | * |
765 | * @NL80211_CMD_TDLS_CHANNEL_SWITCH: Start channel-switching with a TDLS peer, | ||
766 | * identified by the %NL80211_ATTR_MAC parameter. A target channel is | ||
767 | * provided via %NL80211_ATTR_WIPHY_FREQ and other attributes determining | ||
768 | * channel width/type. The target operating class is given via | ||
769 | * %NL80211_ATTR_OPER_CLASS. | ||
770 | * The driver is responsible for continually initiating channel-switching | ||
771 | * operations and returning to the base channel for communication with the | ||
772 | * AP. | ||
773 | * @NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH: Stop channel-switching with a TDLS | ||
774 | * peer given by %NL80211_ATTR_MAC. Both peers must be on the base channel | ||
775 | * when this command completes. | ||
776 | * | ||
754 | * @NL80211_CMD_MAX: highest used command number | 777 | * @NL80211_CMD_MAX: highest used command number |
755 | * @__NL80211_CMD_AFTER_LAST: internal use | 778 | * @__NL80211_CMD_AFTER_LAST: internal use |
756 | */ | 779 | */ |
@@ -930,6 +953,11 @@ enum nl80211_commands { | |||
930 | NL80211_CMD_JOIN_OCB, | 953 | NL80211_CMD_JOIN_OCB, |
931 | NL80211_CMD_LEAVE_OCB, | 954 | NL80211_CMD_LEAVE_OCB, |
932 | 955 | ||
956 | NL80211_CMD_CH_SWITCH_STARTED_NOTIFY, | ||
957 | |||
958 | NL80211_CMD_TDLS_CHANNEL_SWITCH, | ||
959 | NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH, | ||
960 | |||
933 | /* add new commands above here */ | 961 | /* add new commands above here */ |
934 | 962 | ||
935 | /* used to define NL80211_CMD_MAX below */ | 963 | /* used to define NL80211_CMD_MAX below */ |
@@ -1624,9 +1652,9 @@ enum nl80211_commands { | |||
1624 | * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32. | 1652 | * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32. |
1625 | * As specified in the &enum nl80211_tdls_peer_capability. | 1653 | * As specified in the &enum nl80211_tdls_peer_capability. |
1626 | * | 1654 | * |
1627 | * @NL80211_ATTR_IFACE_SOCKET_OWNER: flag attribute, if set during interface | 1655 | * @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface |
1628 | * creation then the new interface will be owned by the netlink socket | 1656 | * creation then the new interface will be owned by the netlink socket |
1629 | * that created it and will be destroyed when the socket is closed | 1657 | * that created it and will be destroyed when the socket is closed. |
1630 | * | 1658 | * |
1631 | * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is | 1659 | * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is |
1632 | * the TDLS link initiator. | 1660 | * the TDLS link initiator. |
@@ -1656,6 +1684,11 @@ enum nl80211_commands { | |||
1656 | * @NL80211_ATTR_SMPS_MODE: SMPS mode to use (ap mode). see | 1684 | * @NL80211_ATTR_SMPS_MODE: SMPS mode to use (ap mode). see |
1657 | * &enum nl80211_smps_mode. | 1685 | * &enum nl80211_smps_mode. |
1658 | * | 1686 | * |
1687 | * @NL80211_ATTR_OPER_CLASS: operating class | ||
1688 | * | ||
1689 | * @NL80211_ATTR_MAC_MASK: MAC address mask | ||
1690 | * | ||
1691 | * @NUM_NL80211_ATTR: total number of nl80211_attrs available | ||
1659 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 1692 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
1660 | * @__NL80211_ATTR_AFTER_LAST: internal use | 1693 | * @__NL80211_ATTR_AFTER_LAST: internal use |
1661 | */ | 1694 | */ |
@@ -1991,7 +2024,7 @@ enum nl80211_attrs { | |||
1991 | 2024 | ||
1992 | NL80211_ATTR_TDLS_PEER_CAPABILITY, | 2025 | NL80211_ATTR_TDLS_PEER_CAPABILITY, |
1993 | 2026 | ||
1994 | NL80211_ATTR_IFACE_SOCKET_OWNER, | 2027 | NL80211_ATTR_SOCKET_OWNER, |
1995 | 2028 | ||
1996 | NL80211_ATTR_CSA_C_OFFSETS_TX, | 2029 | NL80211_ATTR_CSA_C_OFFSETS_TX, |
1997 | NL80211_ATTR_MAX_CSA_COUNTERS, | 2030 | NL80211_ATTR_MAX_CSA_COUNTERS, |
@@ -2008,15 +2041,21 @@ enum nl80211_attrs { | |||
2008 | 2041 | ||
2009 | NL80211_ATTR_SMPS_MODE, | 2042 | NL80211_ATTR_SMPS_MODE, |
2010 | 2043 | ||
2044 | NL80211_ATTR_OPER_CLASS, | ||
2045 | |||
2046 | NL80211_ATTR_MAC_MASK, | ||
2047 | |||
2011 | /* add attributes here, update the policy in nl80211.c */ | 2048 | /* add attributes here, update the policy in nl80211.c */ |
2012 | 2049 | ||
2013 | __NL80211_ATTR_AFTER_LAST, | 2050 | __NL80211_ATTR_AFTER_LAST, |
2051 | NUM_NL80211_ATTR = __NL80211_ATTR_AFTER_LAST, | ||
2014 | NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 | 2052 | NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 |
2015 | }; | 2053 | }; |
2016 | 2054 | ||
2017 | /* source-level API compatibility */ | 2055 | /* source-level API compatibility */ |
2018 | #define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION | 2056 | #define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION |
2019 | #define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG | 2057 | #define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG |
2058 | #define NL80211_ATTR_IFACE_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER | ||
2020 | 2059 | ||
2021 | /* | 2060 | /* |
2022 | * Allow user space programs to use #ifdef on new attributes by defining them | 2061 | * Allow user space programs to use #ifdef on new attributes by defining them |
@@ -2652,6 +2691,11 @@ enum nl80211_sched_scan_match_attr { | |||
2652 | * @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated | 2691 | * @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated |
2653 | * base on contiguous rules and wider channels will be allowed to cross | 2692 | * base on contiguous rules and wider channels will be allowed to cross |
2654 | * multiple contiguous/overlapping frequency ranges. | 2693 | * multiple contiguous/overlapping frequency ranges. |
2694 | * @NL80211_RRF_GO_CONCURRENT: See &NL80211_FREQUENCY_ATTR_GO_CONCURRENT | ||
2695 | * @NL80211_RRF_NO_HT40MINUS: channels can't be used in HT40- operation | ||
2696 | * @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation | ||
2697 | * @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed | ||
2698 | * @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed | ||
2655 | */ | 2699 | */ |
2656 | enum nl80211_reg_rule_flags { | 2700 | enum nl80211_reg_rule_flags { |
2657 | NL80211_RRF_NO_OFDM = 1<<0, | 2701 | NL80211_RRF_NO_OFDM = 1<<0, |
@@ -2664,11 +2708,18 @@ enum nl80211_reg_rule_flags { | |||
2664 | NL80211_RRF_NO_IR = 1<<7, | 2708 | NL80211_RRF_NO_IR = 1<<7, |
2665 | __NL80211_RRF_NO_IBSS = 1<<8, | 2709 | __NL80211_RRF_NO_IBSS = 1<<8, |
2666 | NL80211_RRF_AUTO_BW = 1<<11, | 2710 | NL80211_RRF_AUTO_BW = 1<<11, |
2711 | NL80211_RRF_GO_CONCURRENT = 1<<12, | ||
2712 | NL80211_RRF_NO_HT40MINUS = 1<<13, | ||
2713 | NL80211_RRF_NO_HT40PLUS = 1<<14, | ||
2714 | NL80211_RRF_NO_80MHZ = 1<<15, | ||
2715 | NL80211_RRF_NO_160MHZ = 1<<16, | ||
2667 | }; | 2716 | }; |
2668 | 2717 | ||
2669 | #define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR | 2718 | #define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR |
2670 | #define NL80211_RRF_NO_IBSS NL80211_RRF_NO_IR | 2719 | #define NL80211_RRF_NO_IBSS NL80211_RRF_NO_IR |
2671 | #define NL80211_RRF_NO_IR NL80211_RRF_NO_IR | 2720 | #define NL80211_RRF_NO_IR NL80211_RRF_NO_IR |
2721 | #define NL80211_RRF_NO_HT40 (NL80211_RRF_NO_HT40MINUS |\ | ||
2722 | NL80211_RRF_NO_HT40PLUS) | ||
2672 | 2723 | ||
2673 | /* For backport compatibility with older userspace */ | 2724 | /* For backport compatibility with older userspace */ |
2674 | #define NL80211_RRF_NO_IR_ALL (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS) | 2725 | #define NL80211_RRF_NO_IR_ALL (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS) |
@@ -3566,6 +3617,25 @@ struct nl80211_pattern_support { | |||
3566 | * @NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS: For wakeup reporting only, | 3617 | * @NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS: For wakeup reporting only, |
3567 | * the TCP connection ran out of tokens to use for data to send to the | 3618 | * the TCP connection ran out of tokens to use for data to send to the |
3568 | * service | 3619 | * service |
3620 | * @NL80211_WOWLAN_TRIG_NET_DETECT: wake up when a configured network | ||
3621 | * is detected. This is a nested attribute that contains the | ||
3622 | * same attributes used with @NL80211_CMD_START_SCHED_SCAN. It | ||
3623 | * specifies how the scan is performed (e.g. the interval and the | ||
3624 | * channels to scan) as well as the scan results that will | ||
3625 | * trigger a wake (i.e. the matchsets). | ||
3626 | * @NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS: nested attribute | ||
3627 | * containing an array with information about what triggered the | ||
3628 | * wake up. If no elements are present in the array, it means | ||
3629 | * that the information is not available. If more than one | ||
3630 | * element is present, it means that more than one match | ||
3631 | * occurred. | ||
3632 | * Each element in the array is a nested attribute that contains | ||
3633 | * one optional %NL80211_ATTR_SSID attribute and one optional | ||
3634 | * %NL80211_ATTR_SCAN_FREQUENCIES attribute. At least one of | ||
3635 | * these attributes must be present. If | ||
3636 | * %NL80211_ATTR_SCAN_FREQUENCIES contains more than one | ||
3637 | * frequency, it means that the match occurred in more than one | ||
3638 | * channel. | ||
3569 | * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers | 3639 | * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers |
3570 | * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number | 3640 | * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number |
3571 | * | 3641 | * |
@@ -3591,6 +3661,8 @@ enum nl80211_wowlan_triggers { | |||
3591 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH, | 3661 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH, |
3592 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST, | 3662 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST, |
3593 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS, | 3663 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS, |
3664 | NL80211_WOWLAN_TRIG_NET_DETECT, | ||
3665 | NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS, | ||
3594 | 3666 | ||
3595 | /* keep last */ | 3667 | /* keep last */ |
3596 | NUM_NL80211_WOWLAN_TRIG, | 3668 | NUM_NL80211_WOWLAN_TRIG, |
@@ -4070,6 +4142,20 @@ enum nl80211_ap_sme_features { | |||
4070 | * @NL80211_FEATURE_MAC_ON_CREATE: Device supports configuring | 4142 | * @NL80211_FEATURE_MAC_ON_CREATE: Device supports configuring |
4071 | * the vif's MAC address upon creation. | 4143 | * the vif's MAC address upon creation. |
4072 | * See 'macaddr' field in the vif_params (cfg80211.h). | 4144 | * See 'macaddr' field in the vif_params (cfg80211.h). |
4145 | * @NL80211_FEATURE_TDLS_CHANNEL_SWITCH: Driver supports channel switching when | ||
4146 | * operating as a TDLS peer. | ||
4147 | * @NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR: This device/driver supports using a | ||
4148 | * random MAC address during scan (if the device is unassociated); the | ||
4149 | * %NL80211_SCAN_FLAG_RANDOM_ADDR flag may be set for scans and the MAC | ||
4150 | * address mask/value will be used. | ||
4151 | * @NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR: This device/driver supports | ||
4152 | * using a random MAC address for every scan iteration during scheduled | ||
4153 | * scan (while not associated), the %NL80211_SCAN_FLAG_RANDOM_ADDR may | ||
4154 | * be set for scheduled scan and the MAC address mask/value will be used. | ||
4155 | * @NL80211_FEATURE_ND_RANDOM_MAC_ADDR: This device/driver supports using a | ||
4156 | * random MAC address for every scan iteration during "net detect", i.e. | ||
4157 | * scan in unassociated WoWLAN, the %NL80211_SCAN_FLAG_RANDOM_ADDR may | ||
4158 | * be set for scheduled scan and the MAC address mask/value will be used. | ||
4073 | */ | 4159 | */ |
4074 | enum nl80211_feature_flags { | 4160 | enum nl80211_feature_flags { |
4075 | NL80211_FEATURE_SK_TX_STATUS = 1 << 0, | 4161 | NL80211_FEATURE_SK_TX_STATUS = 1 << 0, |
@@ -4100,6 +4186,10 @@ enum nl80211_feature_flags { | |||
4100 | NL80211_FEATURE_DYNAMIC_SMPS = 1 << 25, | 4186 | NL80211_FEATURE_DYNAMIC_SMPS = 1 << 25, |
4101 | NL80211_FEATURE_SUPPORTS_WMM_ADMISSION = 1 << 26, | 4187 | NL80211_FEATURE_SUPPORTS_WMM_ADMISSION = 1 << 26, |
4102 | NL80211_FEATURE_MAC_ON_CREATE = 1 << 27, | 4188 | NL80211_FEATURE_MAC_ON_CREATE = 1 << 27, |
4189 | NL80211_FEATURE_TDLS_CHANNEL_SWITCH = 1 << 28, | ||
4190 | NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR = 1 << 29, | ||
4191 | NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR = 1 << 30, | ||
4192 | NL80211_FEATURE_ND_RANDOM_MAC_ADDR = 1 << 31, | ||
4103 | }; | 4193 | }; |
4104 | 4194 | ||
4105 | /** | 4195 | /** |
@@ -4148,11 +4238,21 @@ enum nl80211_connect_failed_reason { | |||
4148 | * dangerous because will destroy stations performance as a lot of frames | 4238 | * dangerous because will destroy stations performance as a lot of frames |
4149 | * will be lost while scanning off-channel, therefore it must be used only | 4239 | * will be lost while scanning off-channel, therefore it must be used only |
4150 | * when really needed | 4240 | * when really needed |
4241 | * @NL80211_SCAN_FLAG_RANDOM_ADDR: use a random MAC address for this scan (or | ||
4242 | * for scheduled scan: a different one for every scan iteration). When the | ||
4243 | * flag is set, depending on device capabilities the @NL80211_ATTR_MAC and | ||
4244 | * @NL80211_ATTR_MAC_MASK attributes may also be given in which case only | ||
4245 | * the masked bits will be preserved from the MAC address and the remainder | ||
4246 | * randomised. If the attributes are not given full randomisation (46 bits, | ||
4247 | * locally administered 1, multicast 0) is assumed. | ||
4248 | * This flag must not be requested when the feature isn't supported, check | ||
4249 | * the nl80211 feature flags for the device. | ||
4151 | */ | 4250 | */ |
4152 | enum nl80211_scan_flags { | 4251 | enum nl80211_scan_flags { |
4153 | NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0, | 4252 | NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0, |
4154 | NL80211_SCAN_FLAG_FLUSH = 1<<1, | 4253 | NL80211_SCAN_FLAG_FLUSH = 1<<1, |
4155 | NL80211_SCAN_FLAG_AP = 1<<2, | 4254 | NL80211_SCAN_FLAG_AP = 1<<2, |
4255 | NL80211_SCAN_FLAG_RANDOM_ADDR = 1<<3, | ||
4156 | }; | 4256 | }; |
4157 | 4257 | ||
4158 | /** | 4258 | /** |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 9242c60048cf..a360c15cc978 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -509,6 +509,10 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, | |||
509 | struct tid_ampdu_tx *tid_tx; | 509 | struct tid_ampdu_tx *tid_tx; |
510 | int ret = 0; | 510 | int ret = 0; |
511 | 511 | ||
512 | if (WARN(sta->reserved_tid == tid, | ||
513 | "Requested to start BA session on reserved tid=%d", tid)) | ||
514 | return -EINVAL; | ||
515 | |||
512 | trace_api_start_tx_ba_session(pubsta, tid); | 516 | trace_api_start_tx_ba_session(pubsta, tid); |
513 | 517 | ||
514 | if (WARN_ON_ONCE(!local->ops->ampdu_action)) | 518 | if (WARN_ON_ONCE(!local->ops->ampdu_action)) |
@@ -765,6 +769,9 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
765 | goto unlock; | 769 | goto unlock; |
766 | } | 770 | } |
767 | 771 | ||
772 | WARN(sta->reserved_tid == tid, | ||
773 | "Requested to stop BA session on reserved tid=%d", tid); | ||
774 | |||
768 | if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { | 775 | if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { |
769 | /* already in progress stopping it */ | 776 | /* already in progress stopping it */ |
770 | ret = 0; | 777 | ret = 0; |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 06185940cbb6..e75d5c53e97b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1042,6 +1042,13 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1042 | clear_sta_flag(sta, WLAN_STA_TDLS_PEER); | 1042 | clear_sta_flag(sta, WLAN_STA_TDLS_PEER); |
1043 | } | 1043 | } |
1044 | 1044 | ||
1045 | /* mark TDLS channel switch support, if the AP allows it */ | ||
1046 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && | ||
1047 | !sdata->u.mgd.tdls_chan_switch_prohibited && | ||
1048 | params->ext_capab_len >= 4 && | ||
1049 | params->ext_capab[3] & WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH) | ||
1050 | set_sta_flag(sta, WLAN_STA_TDLS_CHAN_SWITCH); | ||
1051 | |||
1045 | if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD) { | 1052 | if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD) { |
1046 | sta->sta.uapsd_queues = params->uapsd_queues; | 1053 | sta->sta.uapsd_queues = params->uapsd_queues; |
1047 | sta->sta.max_sp = params->max_sp; | 1054 | sta->sta.max_sp = params->max_sp; |
@@ -3158,6 +3165,12 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3158 | goto out; | 3165 | goto out; |
3159 | } | 3166 | } |
3160 | 3167 | ||
3168 | ch_switch.timestamp = 0; | ||
3169 | ch_switch.device_timestamp = 0; | ||
3170 | ch_switch.block_tx = params->block_tx; | ||
3171 | ch_switch.chandef = params->chandef; | ||
3172 | ch_switch.count = params->count; | ||
3173 | |||
3161 | err = drv_pre_channel_switch(sdata, &ch_switch); | 3174 | err = drv_pre_channel_switch(sdata, &ch_switch); |
3162 | if (err) | 3175 | if (err) |
3163 | goto out; | 3176 | goto out; |
@@ -3175,12 +3188,6 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3175 | goto out; | 3188 | goto out; |
3176 | } | 3189 | } |
3177 | 3190 | ||
3178 | ch_switch.timestamp = 0; | ||
3179 | ch_switch.device_timestamp = 0; | ||
3180 | ch_switch.block_tx = params->block_tx; | ||
3181 | ch_switch.chandef = params->chandef; | ||
3182 | ch_switch.count = params->count; | ||
3183 | |||
3184 | err = ieee80211_set_csa_beacon(sdata, params, &changed); | 3191 | err = ieee80211_set_csa_beacon(sdata, params, &changed); |
3185 | if (err) { | 3192 | if (err) { |
3186 | ieee80211_vif_unreserve_chanctx(sdata); | 3193 | ieee80211_vif_unreserve_chanctx(sdata); |
@@ -3195,6 +3202,9 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3195 | ieee80211_stop_vif_queues(local, sdata, | 3202 | ieee80211_stop_vif_queues(local, sdata, |
3196 | IEEE80211_QUEUE_STOP_REASON_CSA); | 3203 | IEEE80211_QUEUE_STOP_REASON_CSA); |
3197 | 3204 | ||
3205 | cfg80211_ch_switch_started_notify(sdata->dev, &sdata->csa_chandef, | ||
3206 | params->count); | ||
3207 | |||
3198 | if (changed) { | 3208 | if (changed) { |
3199 | ieee80211_bss_info_change_notify(sdata, changed); | 3209 | ieee80211_bss_info_change_notify(sdata, changed); |
3200 | drv_channel_switch_beacon(sdata, ¶ms->chandef); | 3210 | drv_channel_switch_beacon(sdata, ¶ms->chandef); |
@@ -3511,6 +3521,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, | |||
3511 | 3521 | ||
3512 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS | | 3522 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS | |
3513 | IEEE80211_TX_INTFL_NL80211_FRAME_TX; | 3523 | IEEE80211_TX_INTFL_NL80211_FRAME_TX; |
3524 | info->band = band; | ||
3514 | 3525 | ||
3515 | skb_set_queue_mapping(skb, IEEE80211_AC_VO); | 3526 | skb_set_queue_mapping(skb, IEEE80211_AC_VO); |
3516 | skb->priority = 7; | 3527 | skb->priority = 7; |
@@ -3518,7 +3529,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, | |||
3518 | nullfunc->qos_ctrl = cpu_to_le16(7); | 3529 | nullfunc->qos_ctrl = cpu_to_le16(7); |
3519 | 3530 | ||
3520 | local_bh_disable(); | 3531 | local_bh_disable(); |
3521 | ieee80211_xmit(sdata, skb, band); | 3532 | ieee80211_xmit(sdata, skb); |
3522 | local_bh_enable(); | 3533 | local_bh_enable(); |
3523 | rcu_read_unlock(); | 3534 | rcu_read_unlock(); |
3524 | 3535 | ||
@@ -3741,6 +3752,8 @@ const struct cfg80211_ops mac80211_config_ops = { | |||
3741 | .set_rekey_data = ieee80211_set_rekey_data, | 3752 | .set_rekey_data = ieee80211_set_rekey_data, |
3742 | .tdls_oper = ieee80211_tdls_oper, | 3753 | .tdls_oper = ieee80211_tdls_oper, |
3743 | .tdls_mgmt = ieee80211_tdls_mgmt, | 3754 | .tdls_mgmt = ieee80211_tdls_mgmt, |
3755 | .tdls_channel_switch = ieee80211_tdls_channel_switch, | ||
3756 | .tdls_cancel_channel_switch = ieee80211_tdls_cancel_channel_switch, | ||
3744 | .probe_client = ieee80211_probe_client, | 3757 | .probe_client = ieee80211_probe_client, |
3745 | .set_noack_map = ieee80211_set_noack_map, | 3758 | .set_noack_map = ieee80211_set_noack_map, |
3746 | #ifdef CONFIG_PM | 3759 | #ifdef CONFIG_PM |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index bafe48916229..94c70091bbd7 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -74,7 +74,7 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | |||
74 | test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" | 74 | test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" |
75 | 75 | ||
76 | int res = scnprintf(buf, sizeof(buf), | 76 | int res = scnprintf(buf, sizeof(buf), |
77 | "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", | 77 | "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", |
78 | TEST(AUTH), TEST(ASSOC), TEST(PS_STA), | 78 | TEST(AUTH), TEST(ASSOC), TEST(PS_STA), |
79 | TEST(PS_DRIVER), TEST(AUTHORIZED), | 79 | TEST(PS_DRIVER), TEST(AUTHORIZED), |
80 | TEST(SHORT_PREAMBLE), | 80 | TEST(SHORT_PREAMBLE), |
@@ -82,10 +82,11 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | |||
82 | TEST(WDS), TEST(CLEAR_PS_FILT), | 82 | TEST(WDS), TEST(CLEAR_PS_FILT), |
83 | TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), | 83 | TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), |
84 | TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), | 84 | TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), |
85 | TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT), | 85 | TEST(TDLS_PEER_AUTH), TEST(TDLS_INITIATOR), |
86 | TEST(INSERTED), TEST(RATE_CONTROL), | 86 | TEST(TDLS_CHAN_SWITCH), TEST(TDLS_OFF_CHANNEL), |
87 | TEST(TOFFSET_KNOWN), TEST(MPSP_OWNER), | 87 | TEST(4ADDR_EVENT), TEST(INSERTED), |
88 | TEST(MPSP_RECIPIENT)); | 88 | TEST(RATE_CONTROL), TEST(TOFFSET_KNOWN), |
89 | TEST(MPSP_OWNER), TEST(MPSP_RECIPIENT)); | ||
89 | #undef TEST | 90 | #undef TEST |
90 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | 91 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); |
91 | } | 92 | } |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 9759dd1f0734..2ebc9ead9695 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -380,23 +380,26 @@ static inline int drv_sched_scan_stop(struct ieee80211_local *local, | |||
380 | return ret; | 380 | return ret; |
381 | } | 381 | } |
382 | 382 | ||
383 | static inline void drv_sw_scan_start(struct ieee80211_local *local) | 383 | static inline void drv_sw_scan_start(struct ieee80211_local *local, |
384 | struct ieee80211_sub_if_data *sdata, | ||
385 | const u8 *mac_addr) | ||
384 | { | 386 | { |
385 | might_sleep(); | 387 | might_sleep(); |
386 | 388 | ||
387 | trace_drv_sw_scan_start(local); | 389 | trace_drv_sw_scan_start(local, sdata, mac_addr); |
388 | if (local->ops->sw_scan_start) | 390 | if (local->ops->sw_scan_start) |
389 | local->ops->sw_scan_start(&local->hw); | 391 | local->ops->sw_scan_start(&local->hw, &sdata->vif, mac_addr); |
390 | trace_drv_return_void(local); | 392 | trace_drv_return_void(local); |
391 | } | 393 | } |
392 | 394 | ||
393 | static inline void drv_sw_scan_complete(struct ieee80211_local *local) | 395 | static inline void drv_sw_scan_complete(struct ieee80211_local *local, |
396 | struct ieee80211_sub_if_data *sdata) | ||
394 | { | 397 | { |
395 | might_sleep(); | 398 | might_sleep(); |
396 | 399 | ||
397 | trace_drv_sw_scan_complete(local); | 400 | trace_drv_sw_scan_complete(local, sdata); |
398 | if (local->ops->sw_scan_complete) | 401 | if (local->ops->sw_scan_complete) |
399 | local->ops->sw_scan_complete(&local->hw); | 402 | local->ops->sw_scan_complete(&local->hw, &sdata->vif); |
400 | trace_drv_return_void(local); | 403 | trace_drv_return_void(local); |
401 | } | 404 | } |
402 | 405 | ||
@@ -621,6 +624,21 @@ static inline void drv_sta_rc_update(struct ieee80211_local *local, | |||
621 | trace_drv_return_void(local); | 624 | trace_drv_return_void(local); |
622 | } | 625 | } |
623 | 626 | ||
627 | static inline void drv_sta_rate_tbl_update(struct ieee80211_local *local, | ||
628 | struct ieee80211_sub_if_data *sdata, | ||
629 | struct ieee80211_sta *sta) | ||
630 | { | ||
631 | sdata = get_bss_sdata(sdata); | ||
632 | if (!check_sdata_in_driver(sdata)) | ||
633 | return; | ||
634 | |||
635 | trace_drv_sta_rate_tbl_update(local, sdata, sta); | ||
636 | if (local->ops->sta_rate_tbl_update) | ||
637 | local->ops->sta_rate_tbl_update(&local->hw, &sdata->vif, sta); | ||
638 | |||
639 | trace_drv_return_void(local); | ||
640 | } | ||
641 | |||
624 | static inline int drv_conf_tx(struct ieee80211_local *local, | 642 | static inline int drv_conf_tx(struct ieee80211_local *local, |
625 | struct ieee80211_sub_if_data *sdata, u16 ac, | 643 | struct ieee80211_sub_if_data *sdata, u16 ac, |
626 | const struct ieee80211_tx_queue_params *params) | 644 | const struct ieee80211_tx_queue_params *params) |
@@ -1296,4 +1314,57 @@ static inline int drv_get_txpower(struct ieee80211_local *local, | |||
1296 | return ret; | 1314 | return ret; |
1297 | } | 1315 | } |
1298 | 1316 | ||
1317 | static inline int | ||
1318 | drv_tdls_channel_switch(struct ieee80211_local *local, | ||
1319 | struct ieee80211_sub_if_data *sdata, | ||
1320 | struct ieee80211_sta *sta, u8 oper_class, | ||
1321 | struct cfg80211_chan_def *chandef, | ||
1322 | struct sk_buff *tmpl_skb, u32 ch_sw_tm_ie) | ||
1323 | { | ||
1324 | int ret; | ||
1325 | |||
1326 | might_sleep(); | ||
1327 | if (!check_sdata_in_driver(sdata)) | ||
1328 | return -EIO; | ||
1329 | |||
1330 | if (!local->ops->tdls_channel_switch) | ||
1331 | return -EOPNOTSUPP; | ||
1332 | |||
1333 | trace_drv_tdls_channel_switch(local, sdata, sta, oper_class, chandef); | ||
1334 | ret = local->ops->tdls_channel_switch(&local->hw, &sdata->vif, sta, | ||
1335 | oper_class, chandef, tmpl_skb, | ||
1336 | ch_sw_tm_ie); | ||
1337 | trace_drv_return_int(local, ret); | ||
1338 | return ret; | ||
1339 | } | ||
1340 | |||
1341 | static inline void | ||
1342 | drv_tdls_cancel_channel_switch(struct ieee80211_local *local, | ||
1343 | struct ieee80211_sub_if_data *sdata, | ||
1344 | struct ieee80211_sta *sta) | ||
1345 | { | ||
1346 | might_sleep(); | ||
1347 | if (!check_sdata_in_driver(sdata)) | ||
1348 | return; | ||
1349 | |||
1350 | if (!local->ops->tdls_cancel_channel_switch) | ||
1351 | return; | ||
1352 | |||
1353 | trace_drv_tdls_cancel_channel_switch(local, sdata, sta); | ||
1354 | local->ops->tdls_cancel_channel_switch(&local->hw, &sdata->vif, sta); | ||
1355 | trace_drv_return_void(local); | ||
1356 | } | ||
1357 | |||
1358 | static inline void | ||
1359 | drv_tdls_recv_channel_switch(struct ieee80211_local *local, | ||
1360 | struct ieee80211_sub_if_data *sdata, | ||
1361 | struct ieee80211_tdls_ch_sw_params *params) | ||
1362 | { | ||
1363 | trace_drv_tdls_recv_channel_switch(local, sdata, params); | ||
1364 | if (local->ops->tdls_recv_channel_switch) | ||
1365 | local->ops->tdls_recv_channel_switch(&local->hw, &sdata->vif, | ||
1366 | params); | ||
1367 | trace_drv_return_void(local); | ||
1368 | } | ||
1369 | |||
1299 | #endif /* __MAC80211_DRIVER_OPS */ | 1370 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 842e0661fb57..cc6e964d9837 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -525,8 +525,13 @@ struct ieee80211_if_managed { | |||
525 | struct ieee80211_vht_cap vht_capa; /* configured VHT overrides */ | 525 | struct ieee80211_vht_cap vht_capa; /* configured VHT overrides */ |
526 | struct ieee80211_vht_cap vht_capa_mask; /* Valid parts of vht_capa */ | 526 | struct ieee80211_vht_cap vht_capa_mask; /* Valid parts of vht_capa */ |
527 | 527 | ||
528 | /* TDLS support */ | ||
528 | u8 tdls_peer[ETH_ALEN] __aligned(2); | 529 | u8 tdls_peer[ETH_ALEN] __aligned(2); |
529 | struct delayed_work tdls_peer_del_work; | 530 | struct delayed_work tdls_peer_del_work; |
531 | struct sk_buff *orig_teardown_skb; /* The original teardown skb */ | ||
532 | struct sk_buff *teardown_skb; /* A copy to send through the AP */ | ||
533 | spinlock_t teardown_lock; /* To lock changing teardown_skb */ | ||
534 | bool tdls_chan_switch_prohibited; | ||
530 | 535 | ||
531 | /* WMM-AC TSPEC support */ | 536 | /* WMM-AC TSPEC support */ |
532 | struct ieee80211_sta_tx_tspec tx_tspec[IEEE80211_NUM_ACS]; | 537 | struct ieee80211_sta_tx_tspec tx_tspec[IEEE80211_NUM_ACS]; |
@@ -988,6 +993,7 @@ enum sdata_queue_type { | |||
988 | IEEE80211_SDATA_QUEUE_AGG_STOP = 2, | 993 | IEEE80211_SDATA_QUEUE_AGG_STOP = 2, |
989 | IEEE80211_SDATA_QUEUE_RX_AGG_START = 3, | 994 | IEEE80211_SDATA_QUEUE_RX_AGG_START = 3, |
990 | IEEE80211_SDATA_QUEUE_RX_AGG_STOP = 4, | 995 | IEEE80211_SDATA_QUEUE_RX_AGG_STOP = 4, |
996 | IEEE80211_SDATA_QUEUE_TDLS_CHSW = 5, | ||
991 | }; | 997 | }; |
992 | 998 | ||
993 | enum { | 999 | enum { |
@@ -1005,6 +1011,7 @@ enum queue_stop_reason { | |||
1005 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, | 1011 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, |
1006 | IEEE80211_QUEUE_STOP_REASON_FLUSH, | 1012 | IEEE80211_QUEUE_STOP_REASON_FLUSH, |
1007 | IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN, | 1013 | IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN, |
1014 | IEEE80211_QUEUE_STOP_REASON_RESERVE_TID, | ||
1008 | 1015 | ||
1009 | IEEE80211_QUEUE_STOP_REASONS, | 1016 | IEEE80211_QUEUE_STOP_REASONS, |
1010 | }; | 1017 | }; |
@@ -1231,7 +1238,7 @@ struct ieee80211_local { | |||
1231 | unsigned long scanning; | 1238 | unsigned long scanning; |
1232 | struct cfg80211_ssid scan_ssid; | 1239 | struct cfg80211_ssid scan_ssid; |
1233 | struct cfg80211_scan_request *int_scan_req; | 1240 | struct cfg80211_scan_request *int_scan_req; |
1234 | struct cfg80211_scan_request *scan_req; | 1241 | struct cfg80211_scan_request __rcu *scan_req; |
1235 | struct ieee80211_scan_request *hw_scan_req; | 1242 | struct ieee80211_scan_request *hw_scan_req; |
1236 | struct cfg80211_chan_def scan_chandef; | 1243 | struct cfg80211_chan_def scan_chandef; |
1237 | enum ieee80211_band hw_scan_band; | 1244 | enum ieee80211_band hw_scan_band; |
@@ -1241,7 +1248,8 @@ struct ieee80211_local { | |||
1241 | 1248 | ||
1242 | struct work_struct sched_scan_stopped_work; | 1249 | struct work_struct sched_scan_stopped_work; |
1243 | struct ieee80211_sub_if_data __rcu *sched_scan_sdata; | 1250 | struct ieee80211_sub_if_data __rcu *sched_scan_sdata; |
1244 | struct cfg80211_sched_scan_request *sched_scan_req; | 1251 | struct cfg80211_sched_scan_request __rcu *sched_scan_req; |
1252 | u8 scan_addr[ETH_ALEN]; | ||
1245 | 1253 | ||
1246 | unsigned long leave_oper_channel_time; | 1254 | unsigned long leave_oper_channel_time; |
1247 | enum mac80211_scan_state next_scan_state; | 1255 | enum mac80211_scan_state next_scan_state; |
@@ -1395,6 +1403,9 @@ struct ieee802_11_elems { | |||
1395 | size_t total_len; | 1403 | size_t total_len; |
1396 | 1404 | ||
1397 | /* pointers to IEs */ | 1405 | /* pointers to IEs */ |
1406 | const struct ieee80211_tdls_lnkie *lnk_id; | ||
1407 | const struct ieee80211_ch_switch_timing *ch_sw_timing; | ||
1408 | const u8 *ext_capab; | ||
1398 | const u8 *ssid; | 1409 | const u8 *ssid; |
1399 | const u8 *supp_rates; | 1410 | const u8 *supp_rates; |
1400 | const u8 *ds_params; | 1411 | const u8 *ds_params; |
@@ -1429,6 +1440,7 @@ struct ieee802_11_elems { | |||
1429 | const struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie; | 1440 | const struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie; |
1430 | 1441 | ||
1431 | /* length of them, respectively */ | 1442 | /* length of them, respectively */ |
1443 | u8 ext_capab_len; | ||
1432 | u8 ssid_len; | 1444 | u8 ssid_len; |
1433 | u8 supp_rates_len; | 1445 | u8 supp_rates_len; |
1434 | u8 tim_len; | 1446 | u8 tim_len; |
@@ -1625,8 +1637,14 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
1625 | struct net_device *dev); | 1637 | struct net_device *dev); |
1626 | netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | 1638 | netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, |
1627 | struct net_device *dev); | 1639 | struct net_device *dev); |
1640 | void __ieee80211_subif_start_xmit(struct sk_buff *skb, | ||
1641 | struct net_device *dev, | ||
1642 | u32 info_flags); | ||
1628 | void ieee80211_purge_tx_queue(struct ieee80211_hw *hw, | 1643 | void ieee80211_purge_tx_queue(struct ieee80211_hw *hw, |
1629 | struct sk_buff_head *skbs); | 1644 | struct sk_buff_head *skbs); |
1645 | struct sk_buff * | ||
1646 | ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata, | ||
1647 | struct sk_buff *skb, u32 info_flags); | ||
1630 | 1648 | ||
1631 | /* HT */ | 1649 | /* HT */ |
1632 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | 1650 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, |
@@ -1753,8 +1771,7 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke | |||
1753 | gfp_t gfp); | 1771 | gfp_t gfp); |
1754 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | 1772 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, |
1755 | bool bss_notify); | 1773 | bool bss_notify); |
1756 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | 1774 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); |
1757 | enum ieee80211_band band); | ||
1758 | 1775 | ||
1759 | void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, | 1776 | void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, |
1760 | struct sk_buff *skb, int tid, | 1777 | struct sk_buff *skb, int tid, |
@@ -1865,6 +1882,9 @@ void ieee80211_add_pending_skbs(struct ieee80211_local *local, | |||
1865 | struct sk_buff_head *skbs); | 1882 | struct sk_buff_head *skbs); |
1866 | void ieee80211_flush_queues(struct ieee80211_local *local, | 1883 | void ieee80211_flush_queues(struct ieee80211_local *local, |
1867 | struct ieee80211_sub_if_data *sdata); | 1884 | struct ieee80211_sub_if_data *sdata); |
1885 | void __ieee80211_flush_queues(struct ieee80211_local *local, | ||
1886 | struct ieee80211_sub_if_data *sdata, | ||
1887 | unsigned int queues); | ||
1868 | 1888 | ||
1869 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | 1889 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, |
1870 | u16 transaction, u16 auth_alg, u16 status, | 1890 | u16 transaction, u16 auth_alg, u16 status, |
@@ -1881,12 +1901,14 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1881 | u8 bands_used, u32 *rate_masks, | 1901 | u8 bands_used, u32 *rate_masks, |
1882 | struct cfg80211_chan_def *chandef); | 1902 | struct cfg80211_chan_def *chandef); |
1883 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | 1903 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, |
1884 | u8 *dst, u32 ratemask, | 1904 | const u8 *src, const u8 *dst, |
1905 | u32 ratemask, | ||
1885 | struct ieee80211_channel *chan, | 1906 | struct ieee80211_channel *chan, |
1886 | const u8 *ssid, size_t ssid_len, | 1907 | const u8 *ssid, size_t ssid_len, |
1887 | const u8 *ie, size_t ie_len, | 1908 | const u8 *ie, size_t ie_len, |
1888 | bool directed); | 1909 | bool directed); |
1889 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 1910 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, |
1911 | const u8 *src, const u8 *dst, | ||
1890 | const u8 *ssid, size_t ssid_len, | 1912 | const u8 *ssid, size_t ssid_len, |
1891 | const u8 *ie, size_t ie_len, | 1913 | const u8 *ie, size_t ie_len, |
1892 | u32 ratemask, bool directed, u32 tx_flags, | 1914 | u32 ratemask, bool directed, u32 tx_flags, |
@@ -1992,6 +2014,14 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | |||
1992 | int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | 2014 | int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, |
1993 | const u8 *peer, enum nl80211_tdls_operation oper); | 2015 | const u8 *peer, enum nl80211_tdls_operation oper); |
1994 | void ieee80211_tdls_peer_del_work(struct work_struct *wk); | 2016 | void ieee80211_tdls_peer_del_work(struct work_struct *wk); |
2017 | int ieee80211_tdls_channel_switch(struct wiphy *wiphy, struct net_device *dev, | ||
2018 | const u8 *addr, u8 oper_class, | ||
2019 | struct cfg80211_chan_def *chandef); | ||
2020 | void ieee80211_tdls_cancel_channel_switch(struct wiphy *wiphy, | ||
2021 | struct net_device *dev, | ||
2022 | const u8 *addr); | ||
2023 | void ieee80211_process_tdls_channel_switch(struct ieee80211_sub_if_data *sdata, | ||
2024 | struct sk_buff *skb); | ||
1995 | 2025 | ||
1996 | extern const struct ethtool_ops ieee80211_ethtool_ops; | 2026 | extern const struct ethtool_ops ieee80211_ethtool_ops; |
1997 | 2027 | ||
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 9df26adb864a..538fe4ef5c85 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -1208,6 +1208,8 @@ static void ieee80211_iface_work(struct work_struct *work) | |||
1208 | WLAN_BACK_RECIPIENT, 0, | 1208 | WLAN_BACK_RECIPIENT, 0, |
1209 | false); | 1209 | false); |
1210 | mutex_unlock(&local->sta_mtx); | 1210 | mutex_unlock(&local->sta_mtx); |
1211 | } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_TDLS_CHSW) { | ||
1212 | ieee80211_process_tdls_channel_switch(sdata, skb); | ||
1211 | } else if (ieee80211_is_action(mgmt->frame_control) && | 1213 | } else if (ieee80211_is_action(mgmt->frame_control) && |
1212 | mgmt->u.action.category == WLAN_CATEGORY_BACK) { | 1214 | mgmt->u.action.category == WLAN_CATEGORY_BACK) { |
1213 | int len = skb->len; | 1215 | int len = skb->len; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 282a4f36eb92..6ab99da38db9 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -764,6 +764,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
764 | local->hw.offchannel_tx_hw_queue >= local->hw.queues)) | 764 | local->hw.offchannel_tx_hw_queue >= local->hw.queues)) |
765 | return -EINVAL; | 765 | return -EINVAL; |
766 | 766 | ||
767 | if ((hw->wiphy->features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH) && | ||
768 | (!local->ops->tdls_channel_switch || | ||
769 | !local->ops->tdls_cancel_channel_switch || | ||
770 | !local->ops->tdls_recv_channel_switch)) | ||
771 | return -EOPNOTSUPP; | ||
772 | |||
767 | #ifdef CONFIG_PM | 773 | #ifdef CONFIG_PM |
768 | if (hw->wiphy->wowlan && (!local->ops->suspend || !local->ops->resume)) | 774 | if (hw->wiphy->wowlan && (!local->ops->suspend || !local->ops->resume)) |
769 | return -EINVAL; | 775 | return -EINVAL; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0d166e766dad..ba06cd003375 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1049,6 +1049,8 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata) | |||
1049 | sdata->csa_block_tx = false; | 1049 | sdata->csa_block_tx = false; |
1050 | } | 1050 | } |
1051 | 1051 | ||
1052 | cfg80211_ch_switch_notify(sdata->dev, &sdata->reserved_chandef); | ||
1053 | |||
1052 | sdata->vif.csa_active = false; | 1054 | sdata->vif.csa_active = false; |
1053 | ifmgd->csa_waiting_bcn = false; | 1055 | ifmgd->csa_waiting_bcn = false; |
1054 | 1056 | ||
@@ -1205,6 +1207,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1205 | IEEE80211_QUEUE_STOP_REASON_CSA); | 1207 | IEEE80211_QUEUE_STOP_REASON_CSA); |
1206 | mutex_unlock(&local->mtx); | 1208 | mutex_unlock(&local->mtx); |
1207 | 1209 | ||
1210 | cfg80211_ch_switch_started_notify(sdata->dev, &csa_ie.chandef, | ||
1211 | csa_ie.count); | ||
1212 | |||
1208 | if (local->ops->channel_switch) { | 1213 | if (local->ops->channel_switch) { |
1209 | /* use driver's channel switch callback */ | 1214 | /* use driver's channel switch callback */ |
1210 | drv_channel_switch(local, sdata, &ch_switch); | 1215 | drv_channel_switch(local, sdata, &ch_switch); |
@@ -2221,7 +2226,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
2221 | else | 2226 | else |
2222 | ssid_len = ssid[1]; | 2227 | ssid_len = ssid[1]; |
2223 | 2228 | ||
2224 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL, | 2229 | ieee80211_send_probe_req(sdata, sdata->vif.addr, NULL, |
2230 | ssid + 2, ssid_len, NULL, | ||
2225 | 0, (u32) -1, true, 0, | 2231 | 0, (u32) -1, true, 0, |
2226 | ifmgd->associated->channel, false); | 2232 | ifmgd->associated->channel, false); |
2227 | rcu_read_unlock(); | 2233 | rcu_read_unlock(); |
@@ -2324,7 +2330,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
2324 | else | 2330 | else |
2325 | ssid_len = ssid[1]; | 2331 | ssid_len = ssid[1]; |
2326 | 2332 | ||
2327 | skb = ieee80211_build_probe_req(sdata, cbss->bssid, | 2333 | skb = ieee80211_build_probe_req(sdata, sdata->vif.addr, cbss->bssid, |
2328 | (u32) -1, cbss->channel, | 2334 | (u32) -1, cbss->channel, |
2329 | ssid + 2, ssid_len, | 2335 | ssid + 2, ssid_len, |
2330 | NULL, 0, true); | 2336 | NULL, 0, true); |
@@ -2798,6 +2804,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2798 | } | 2804 | } |
2799 | 2805 | ||
2800 | ifmgd->aid = aid; | 2806 | ifmgd->aid = aid; |
2807 | ifmgd->tdls_chan_switch_prohibited = | ||
2808 | elems.ext_capab && elems.ext_capab_len >= 5 && | ||
2809 | (elems.ext_capab[4] & WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED); | ||
2801 | 2810 | ||
2802 | /* | 2811 | /* |
2803 | * Some APs are erroneously not including some information in their | 2812 | * Some APs are erroneously not including some information in their |
@@ -3642,7 +3651,8 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | |||
3642 | * Direct probe is sent to broadcast address as some APs | 3651 | * Direct probe is sent to broadcast address as some APs |
3643 | * will not answer to direct packet in unassociated state. | 3652 | * will not answer to direct packet in unassociated state. |
3644 | */ | 3653 | */ |
3645 | ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], | 3654 | ieee80211_send_probe_req(sdata, sdata->vif.addr, NULL, |
3655 | ssidie + 2, ssidie[1], | ||
3646 | NULL, 0, (u32) -1, true, 0, | 3656 | NULL, 0, (u32) -1, true, 0, |
3647 | auth_data->bss->channel, false); | 3657 | auth_data->bss->channel, false); |
3648 | rcu_read_unlock(); | 3658 | rcu_read_unlock(); |
@@ -3999,6 +4009,11 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
3999 | ifmgd->req_smps = IEEE80211_SMPS_AUTOMATIC; | 4009 | ifmgd->req_smps = IEEE80211_SMPS_AUTOMATIC; |
4000 | else | 4010 | else |
4001 | ifmgd->req_smps = IEEE80211_SMPS_OFF; | 4011 | ifmgd->req_smps = IEEE80211_SMPS_OFF; |
4012 | |||
4013 | /* Setup TDLS data */ | ||
4014 | spin_lock_init(&ifmgd->teardown_lock); | ||
4015 | ifmgd->teardown_skb = NULL; | ||
4016 | ifmgd->orig_teardown_skb = NULL; | ||
4002 | } | 4017 | } |
4003 | 4018 | ||
4004 | /* scan finished notification */ | 4019 | /* scan finished notification */ |
@@ -4861,6 +4876,13 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata) | |||
4861 | } | 4876 | } |
4862 | if (ifmgd->auth_data) | 4877 | if (ifmgd->auth_data) |
4863 | ieee80211_destroy_auth_data(sdata, false); | 4878 | ieee80211_destroy_auth_data(sdata, false); |
4879 | spin_lock_bh(&ifmgd->teardown_lock); | ||
4880 | if (ifmgd->teardown_skb) { | ||
4881 | kfree_skb(ifmgd->teardown_skb); | ||
4882 | ifmgd->teardown_skb = NULL; | ||
4883 | ifmgd->orig_teardown_skb = NULL; | ||
4884 | } | ||
4885 | spin_unlock_bh(&ifmgd->teardown_lock); | ||
4864 | del_timer_sync(&ifmgd->timer); | 4886 | del_timer_sync(&ifmgd->timer); |
4865 | sdata_unlock(sdata); | 4887 | sdata_unlock(sdata); |
4866 | } | 4888 | } |
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 6081329784dd..08ab7d6d1517 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
@@ -385,7 +385,7 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, | |||
385 | *rate = alt_rate; | 385 | *rate = alt_rate; |
386 | return; | 386 | return; |
387 | } | 387 | } |
388 | } else { | 388 | } else if (!(rate->flags & IEEE80211_TX_RC_VHT_MCS)) { |
389 | /* handle legacy rates */ | 389 | /* handle legacy rates */ |
390 | if (rate_idx_match_legacy_mask(rate, sband->n_bitrates, mask)) | 390 | if (rate_idx_match_legacy_mask(rate, sband->n_bitrates, mask)) |
391 | return; | 391 | return; |
@@ -696,6 +696,7 @@ int rate_control_set_rates(struct ieee80211_hw *hw, | |||
696 | struct ieee80211_sta *pubsta, | 696 | struct ieee80211_sta *pubsta, |
697 | struct ieee80211_sta_rates *rates) | 697 | struct ieee80211_sta_rates *rates) |
698 | { | 698 | { |
699 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | ||
699 | struct ieee80211_sta_rates *old; | 700 | struct ieee80211_sta_rates *old; |
700 | 701 | ||
701 | /* | 702 | /* |
@@ -709,6 +710,8 @@ int rate_control_set_rates(struct ieee80211_hw *hw, | |||
709 | if (old) | 710 | if (old) |
710 | kfree_rcu(old, rcu_head); | 711 | kfree_rcu(old, rcu_head); |
711 | 712 | ||
713 | drv_sta_rate_tbl_update(hw_to_local(hw), sta->sdata, pubsta); | ||
714 | |||
712 | return 0; | 715 | return 0; |
713 | } | 716 | } |
714 | EXPORT_SYMBOL(rate_control_set_rates); | 717 | EXPORT_SYMBOL(rate_control_set_rates); |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index c50fd94d2aef..62ff7cfb2723 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -690,6 +690,9 @@ minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb) | |||
690 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | 690 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); |
691 | u16 tid; | 691 | u16 tid; |
692 | 692 | ||
693 | if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) | ||
694 | return; | ||
695 | |||
693 | if (unlikely(!ieee80211_is_data_qos(hdr->frame_control))) | 696 | if (unlikely(!ieee80211_is_data_qos(hdr->frame_control))) |
694 | return; | 697 | return; |
695 | 698 | ||
@@ -700,9 +703,6 @@ minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb) | |||
700 | if (likely(sta->ampdu_mlme.tid_tx[tid])) | 703 | if (likely(sta->ampdu_mlme.tid_tx[tid])) |
701 | return; | 704 | return; |
702 | 705 | ||
703 | if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) | ||
704 | return; | ||
705 | |||
706 | ieee80211_start_tx_ba_session(pubsta, tid, 5000); | 706 | ieee80211_start_tx_ba_session(pubsta, tid, 5000); |
707 | } | 707 | } |
708 | 708 | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index a726bb169302..49c23bdf08bb 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -39,7 +39,8 @@ | |||
39 | * only useful for monitoring. | 39 | * only useful for monitoring. |
40 | */ | 40 | */ |
41 | static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, | 41 | static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, |
42 | struct sk_buff *skb) | 42 | struct sk_buff *skb, |
43 | unsigned int rtap_vendor_space) | ||
43 | { | 44 | { |
44 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { | 45 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { |
45 | if (likely(skb->len > FCS_LEN)) | 46 | if (likely(skb->len > FCS_LEN)) |
@@ -52,20 +53,25 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, | |||
52 | } | 53 | } |
53 | } | 54 | } |
54 | 55 | ||
56 | __pskb_pull(skb, rtap_vendor_space); | ||
57 | |||
55 | return skb; | 58 | return skb; |
56 | } | 59 | } |
57 | 60 | ||
58 | static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len) | 61 | static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len, |
62 | unsigned int rtap_vendor_space) | ||
59 | { | 63 | { |
60 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 64 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
61 | struct ieee80211_hdr *hdr = (void *)skb->data; | 65 | struct ieee80211_hdr *hdr; |
66 | |||
67 | hdr = (void *)(skb->data + rtap_vendor_space); | ||
62 | 68 | ||
63 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | | 69 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | |
64 | RX_FLAG_FAILED_PLCP_CRC | | 70 | RX_FLAG_FAILED_PLCP_CRC | |
65 | RX_FLAG_AMPDU_IS_ZEROLEN)) | 71 | RX_FLAG_AMPDU_IS_ZEROLEN)) |
66 | return true; | 72 | return true; |
67 | 73 | ||
68 | if (unlikely(skb->len < 16 + present_fcs_len)) | 74 | if (unlikely(skb->len < 16 + present_fcs_len + rtap_vendor_space)) |
69 | return true; | 75 | return true; |
70 | 76 | ||
71 | if (ieee80211_is_ctl(hdr->frame_control) && | 77 | if (ieee80211_is_ctl(hdr->frame_control) && |
@@ -77,8 +83,9 @@ static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len) | |||
77 | } | 83 | } |
78 | 84 | ||
79 | static int | 85 | static int |
80 | ieee80211_rx_radiotap_space(struct ieee80211_local *local, | 86 | ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local, |
81 | struct ieee80211_rx_status *status) | 87 | struct ieee80211_rx_status *status, |
88 | struct sk_buff *skb) | ||
82 | { | 89 | { |
83 | int len; | 90 | int len; |
84 | 91 | ||
@@ -121,6 +128,21 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local, | |||
121 | len += 2 * hweight8(status->chains); | 128 | len += 2 * hweight8(status->chains); |
122 | } | 129 | } |
123 | 130 | ||
131 | if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { | ||
132 | struct ieee80211_vendor_radiotap *rtap = (void *)skb->data; | ||
133 | |||
134 | /* vendor presence bitmap */ | ||
135 | len += 4; | ||
136 | /* alignment for fixed 6-byte vendor data header */ | ||
137 | len = ALIGN(len, 2); | ||
138 | /* vendor data header */ | ||
139 | len += 6; | ||
140 | if (WARN_ON(rtap->align == 0)) | ||
141 | rtap->align = 1; | ||
142 | len = ALIGN(len, rtap->align); | ||
143 | len += rtap->len + rtap->pad; | ||
144 | } | ||
145 | |||
124 | return len; | 146 | return len; |
125 | } | 147 | } |
126 | 148 | ||
@@ -144,13 +166,20 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
144 | u16 channel_flags = 0; | 166 | u16 channel_flags = 0; |
145 | int mpdulen, chain; | 167 | int mpdulen, chain; |
146 | unsigned long chains = status->chains; | 168 | unsigned long chains = status->chains; |
169 | struct ieee80211_vendor_radiotap rtap = {}; | ||
170 | |||
171 | if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { | ||
172 | rtap = *(struct ieee80211_vendor_radiotap *)skb->data; | ||
173 | /* rtap.len and rtap.pad are undone immediately */ | ||
174 | skb_pull(skb, sizeof(rtap) + rtap.len + rtap.pad); | ||
175 | } | ||
147 | 176 | ||
148 | mpdulen = skb->len; | 177 | mpdulen = skb->len; |
149 | if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS))) | 178 | if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS))) |
150 | mpdulen += FCS_LEN; | 179 | mpdulen += FCS_LEN; |
151 | 180 | ||
152 | rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); | 181 | rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); |
153 | memset(rthdr, 0, rtap_len); | 182 | memset(rthdr, 0, rtap_len - rtap.len - rtap.pad); |
154 | it_present = &rthdr->it_present; | 183 | it_present = &rthdr->it_present; |
155 | 184 | ||
156 | /* radiotap header, set always present flags */ | 185 | /* radiotap header, set always present flags */ |
@@ -172,6 +201,14 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
172 | BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL); | 201 | BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL); |
173 | } | 202 | } |
174 | 203 | ||
204 | if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { | ||
205 | it_present_val |= BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE) | | ||
206 | BIT(IEEE80211_RADIOTAP_EXT); | ||
207 | put_unaligned_le32(it_present_val, it_present); | ||
208 | it_present++; | ||
209 | it_present_val = rtap.present; | ||
210 | } | ||
211 | |||
175 | put_unaligned_le32(it_present_val, it_present); | 212 | put_unaligned_le32(it_present_val, it_present); |
176 | 213 | ||
177 | pos = (void *)(it_present + 1); | 214 | pos = (void *)(it_present + 1); |
@@ -366,6 +403,22 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
366 | *pos++ = status->chain_signal[chain]; | 403 | *pos++ = status->chain_signal[chain]; |
367 | *pos++ = chain; | 404 | *pos++ = chain; |
368 | } | 405 | } |
406 | |||
407 | if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { | ||
408 | /* ensure 2 byte alignment for the vendor field as required */ | ||
409 | if ((pos - (u8 *)rthdr) & 1) | ||
410 | *pos++ = 0; | ||
411 | *pos++ = rtap.oui[0]; | ||
412 | *pos++ = rtap.oui[1]; | ||
413 | *pos++ = rtap.oui[2]; | ||
414 | *pos++ = rtap.subns; | ||
415 | put_unaligned_le16(rtap.len, pos); | ||
416 | pos += 2; | ||
417 | /* align the actual payload as requested */ | ||
418 | while ((pos - (u8 *)rthdr) & (rtap.align - 1)) | ||
419 | *pos++ = 0; | ||
420 | /* data (and possible padding) already follows */ | ||
421 | } | ||
369 | } | 422 | } |
370 | 423 | ||
371 | /* | 424 | /* |
@@ -379,10 +432,17 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
379 | { | 432 | { |
380 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb); | 433 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb); |
381 | struct ieee80211_sub_if_data *sdata; | 434 | struct ieee80211_sub_if_data *sdata; |
382 | int needed_headroom; | 435 | int rt_hdrlen, needed_headroom; |
383 | struct sk_buff *skb, *skb2; | 436 | struct sk_buff *skb, *skb2; |
384 | struct net_device *prev_dev = NULL; | 437 | struct net_device *prev_dev = NULL; |
385 | int present_fcs_len = 0; | 438 | int present_fcs_len = 0; |
439 | unsigned int rtap_vendor_space = 0; | ||
440 | |||
441 | if (unlikely(status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA)) { | ||
442 | struct ieee80211_vendor_radiotap *rtap = (void *)origskb->data; | ||
443 | |||
444 | rtap_vendor_space = sizeof(*rtap) + rtap->len + rtap->pad; | ||
445 | } | ||
386 | 446 | ||
387 | /* | 447 | /* |
388 | * First, we may need to make a copy of the skb because | 448 | * First, we may need to make a copy of the skb because |
@@ -396,25 +456,27 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
396 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) | 456 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) |
397 | present_fcs_len = FCS_LEN; | 457 | present_fcs_len = FCS_LEN; |
398 | 458 | ||
399 | /* ensure hdr->frame_control is in skb head */ | 459 | /* ensure hdr->frame_control and vendor radiotap data are in skb head */ |
400 | if (!pskb_may_pull(origskb, 2)) { | 460 | if (!pskb_may_pull(origskb, 2 + rtap_vendor_space)) { |
401 | dev_kfree_skb(origskb); | 461 | dev_kfree_skb(origskb); |
402 | return NULL; | 462 | return NULL; |
403 | } | 463 | } |
404 | 464 | ||
405 | if (!local->monitors) { | 465 | if (!local->monitors) { |
406 | if (should_drop_frame(origskb, present_fcs_len)) { | 466 | if (should_drop_frame(origskb, present_fcs_len, |
467 | rtap_vendor_space)) { | ||
407 | dev_kfree_skb(origskb); | 468 | dev_kfree_skb(origskb); |
408 | return NULL; | 469 | return NULL; |
409 | } | 470 | } |
410 | 471 | ||
411 | return remove_monitor_info(local, origskb); | 472 | return remove_monitor_info(local, origskb, rtap_vendor_space); |
412 | } | 473 | } |
413 | 474 | ||
414 | /* room for the radiotap header based on driver features */ | 475 | /* room for the radiotap header based on driver features */ |
415 | needed_headroom = ieee80211_rx_radiotap_space(local, status); | 476 | rt_hdrlen = ieee80211_rx_radiotap_hdrlen(local, status, origskb); |
477 | needed_headroom = rt_hdrlen - rtap_vendor_space; | ||
416 | 478 | ||
417 | if (should_drop_frame(origskb, present_fcs_len)) { | 479 | if (should_drop_frame(origskb, present_fcs_len, rtap_vendor_space)) { |
418 | /* only need to expand headroom if necessary */ | 480 | /* only need to expand headroom if necessary */ |
419 | skb = origskb; | 481 | skb = origskb; |
420 | origskb = NULL; | 482 | origskb = NULL; |
@@ -438,15 +500,15 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
438 | */ | 500 | */ |
439 | skb = skb_copy_expand(origskb, needed_headroom, 0, GFP_ATOMIC); | 501 | skb = skb_copy_expand(origskb, needed_headroom, 0, GFP_ATOMIC); |
440 | 502 | ||
441 | origskb = remove_monitor_info(local, origskb); | 503 | origskb = remove_monitor_info(local, origskb, |
504 | rtap_vendor_space); | ||
442 | 505 | ||
443 | if (!skb) | 506 | if (!skb) |
444 | return origskb; | 507 | return origskb; |
445 | } | 508 | } |
446 | 509 | ||
447 | /* prepend radiotap information */ | 510 | /* prepend radiotap information */ |
448 | ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom, | 511 | ieee80211_add_rx_radiotap_header(local, skb, rate, rt_hdrlen, true); |
449 | true); | ||
450 | 512 | ||
451 | skb_reset_mac_header(skb); | 513 | skb_reset_mac_header(skb); |
452 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 514 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
@@ -985,7 +1047,7 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx, | |||
985 | } | 1047 | } |
986 | 1048 | ||
987 | static ieee80211_rx_result debug_noinline | 1049 | static ieee80211_rx_result debug_noinline |
988 | ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | 1050 | ieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx) |
989 | { | 1051 | { |
990 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 1052 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
991 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | 1053 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); |
@@ -994,10 +1056,16 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | |||
994 | * Drop duplicate 802.11 retransmissions | 1056 | * Drop duplicate 802.11 retransmissions |
995 | * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery") | 1057 | * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery") |
996 | */ | 1058 | */ |
997 | if (rx->skb->len >= 24 && rx->sta && | 1059 | |
998 | !ieee80211_is_ctl(hdr->frame_control) && | 1060 | if (rx->skb->len < 24) |
999 | !ieee80211_is_qos_nullfunc(hdr->frame_control) && | 1061 | return RX_CONTINUE; |
1000 | !is_multicast_ether_addr(hdr->addr1)) { | 1062 | |
1063 | if (ieee80211_is_ctl(hdr->frame_control) || | ||
1064 | ieee80211_is_qos_nullfunc(hdr->frame_control) || | ||
1065 | is_multicast_ether_addr(hdr->addr1)) | ||
1066 | return RX_CONTINUE; | ||
1067 | |||
1068 | if (rx->sta) { | ||
1001 | if (unlikely(ieee80211_has_retry(hdr->frame_control) && | 1069 | if (unlikely(ieee80211_has_retry(hdr->frame_control) && |
1002 | rx->sta->last_seq_ctrl[rx->seqno_idx] == | 1070 | rx->sta->last_seq_ctrl[rx->seqno_idx] == |
1003 | hdr->seq_ctrl)) { | 1071 | hdr->seq_ctrl)) { |
@@ -1011,6 +1079,14 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | |||
1011 | } | 1079 | } |
1012 | } | 1080 | } |
1013 | 1081 | ||
1082 | return RX_CONTINUE; | ||
1083 | } | ||
1084 | |||
1085 | static ieee80211_rx_result debug_noinline | ||
1086 | ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | ||
1087 | { | ||
1088 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | ||
1089 | |||
1014 | if (unlikely(rx->skb->len < 16)) { | 1090 | if (unlikely(rx->skb->len < 16)) { |
1015 | I802_DEBUG_INC(rx->local->rx_handlers_drop_short); | 1091 | I802_DEBUG_INC(rx->local->rx_handlers_drop_short); |
1016 | return RX_DROP_MONITOR; | 1092 | return RX_DROP_MONITOR; |
@@ -2257,6 +2333,27 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | |||
2257 | if (!ieee80211_frame_allowed(rx, fc)) | 2333 | if (!ieee80211_frame_allowed(rx, fc)) |
2258 | return RX_DROP_MONITOR; | 2334 | return RX_DROP_MONITOR; |
2259 | 2335 | ||
2336 | /* directly handle TDLS channel switch requests/responses */ | ||
2337 | if (unlikely(((struct ethhdr *)rx->skb->data)->h_proto == | ||
2338 | cpu_to_be16(ETH_P_TDLS))) { | ||
2339 | struct ieee80211_tdls_data *tf = (void *)rx->skb->data; | ||
2340 | |||
2341 | if (pskb_may_pull(rx->skb, | ||
2342 | offsetof(struct ieee80211_tdls_data, u)) && | ||
2343 | tf->payload_type == WLAN_TDLS_SNAP_RFTYPE && | ||
2344 | tf->category == WLAN_CATEGORY_TDLS && | ||
2345 | (tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST || | ||
2346 | tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_RESPONSE)) { | ||
2347 | rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TDLS_CHSW; | ||
2348 | skb_queue_tail(&sdata->skb_queue, rx->skb); | ||
2349 | ieee80211_queue_work(&rx->local->hw, &sdata->work); | ||
2350 | if (rx->sta) | ||
2351 | rx->sta->rx_packets++; | ||
2352 | |||
2353 | return RX_QUEUED; | ||
2354 | } | ||
2355 | } | ||
2356 | |||
2260 | if (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && | 2357 | if (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && |
2261 | unlikely(port_control) && sdata->bss) { | 2358 | unlikely(port_control) && sdata->bss) { |
2262 | sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, | 2359 | sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, |
@@ -2892,8 +2989,10 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, | |||
2892 | if (!local->cooked_mntrs) | 2989 | if (!local->cooked_mntrs) |
2893 | goto out_free_skb; | 2990 | goto out_free_skb; |
2894 | 2991 | ||
2992 | /* vendor data is long removed here */ | ||
2993 | status->flag &= ~RX_FLAG_RADIOTAP_VENDOR_DATA; | ||
2895 | /* room for the radiotap header based on driver features */ | 2994 | /* room for the radiotap header based on driver features */ |
2896 | needed_headroom = ieee80211_rx_radiotap_space(local, status); | 2995 | needed_headroom = ieee80211_rx_radiotap_hdrlen(local, status, skb); |
2897 | 2996 | ||
2898 | if (skb_headroom(skb) < needed_headroom && | 2997 | if (skb_headroom(skb) < needed_headroom && |
2899 | pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) | 2998 | pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) |
@@ -3046,6 +3145,7 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) | |||
3046 | goto rxh_next; \ | 3145 | goto rxh_next; \ |
3047 | } while (0); | 3146 | } while (0); |
3048 | 3147 | ||
3148 | CALL_RXH(ieee80211_rx_h_check_dup) | ||
3049 | CALL_RXH(ieee80211_rx_h_check) | 3149 | CALL_RXH(ieee80211_rx_h_check) |
3050 | 3150 | ||
3051 | ieee80211_rx_reorder_ampdu(rx, &reorder_release); | 3151 | ieee80211_rx_reorder_ampdu(rx, &reorder_release); |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index af0d094b2f2f..ae842678b629 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -184,9 +184,21 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) | |||
184 | return; | 184 | return; |
185 | 185 | ||
186 | if (ieee80211_is_probe_resp(mgmt->frame_control)) { | 186 | if (ieee80211_is_probe_resp(mgmt->frame_control)) { |
187 | /* ignore ProbeResp to foreign address */ | 187 | struct cfg80211_scan_request *scan_req; |
188 | if ((!sdata1 || !ether_addr_equal(mgmt->da, sdata1->vif.addr)) && | 188 | struct cfg80211_sched_scan_request *sched_scan_req; |
189 | (!sdata2 || !ether_addr_equal(mgmt->da, sdata2->vif.addr))) | 189 | |
190 | scan_req = rcu_dereference(local->scan_req); | ||
191 | sched_scan_req = rcu_dereference(local->sched_scan_req); | ||
192 | |||
193 | /* ignore ProbeResp to foreign address unless scanning | ||
194 | * with randomised address | ||
195 | */ | ||
196 | if (!(sdata1 && | ||
197 | (ether_addr_equal(mgmt->da, sdata1->vif.addr) || | ||
198 | scan_req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)) && | ||
199 | !(sdata2 && | ||
200 | (ether_addr_equal(mgmt->da, sdata2->vif.addr) || | ||
201 | sched_scan_req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR))) | ||
190 | return; | 202 | return; |
191 | 203 | ||
192 | elements = mgmt->u.probe_resp.variable; | 204 | elements = mgmt->u.probe_resp.variable; |
@@ -234,11 +246,14 @@ ieee80211_prepare_scan_chandef(struct cfg80211_chan_def *chandef, | |||
234 | /* return false if no more work */ | 246 | /* return false if no more work */ |
235 | static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | 247 | static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) |
236 | { | 248 | { |
237 | struct cfg80211_scan_request *req = local->scan_req; | 249 | struct cfg80211_scan_request *req; |
238 | struct cfg80211_chan_def chandef; | 250 | struct cfg80211_chan_def chandef; |
239 | u8 bands_used = 0; | 251 | u8 bands_used = 0; |
240 | int i, ielen, n_chans; | 252 | int i, ielen, n_chans; |
241 | 253 | ||
254 | req = rcu_dereference_protected(local->scan_req, | ||
255 | lockdep_is_held(&local->mtx)); | ||
256 | |||
242 | if (test_bit(SCAN_HW_CANCELLED, &local->scanning)) | 257 | if (test_bit(SCAN_HW_CANCELLED, &local->scanning)) |
243 | return false; | 258 | return false; |
244 | 259 | ||
@@ -281,6 +296,9 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | |||
281 | bands_used, req->rates, &chandef); | 296 | bands_used, req->rates, &chandef); |
282 | local->hw_scan_req->req.ie_len = ielen; | 297 | local->hw_scan_req->req.ie_len = ielen; |
283 | local->hw_scan_req->req.no_cck = req->no_cck; | 298 | local->hw_scan_req->req.no_cck = req->no_cck; |
299 | ether_addr_copy(local->hw_scan_req->req.mac_addr, req->mac_addr); | ||
300 | ether_addr_copy(local->hw_scan_req->req.mac_addr_mask, | ||
301 | req->mac_addr_mask); | ||
284 | 302 | ||
285 | return true; | 303 | return true; |
286 | } | 304 | } |
@@ -290,6 +308,8 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
290 | struct ieee80211_local *local = hw_to_local(hw); | 308 | struct ieee80211_local *local = hw_to_local(hw); |
291 | bool hw_scan = local->ops->hw_scan; | 309 | bool hw_scan = local->ops->hw_scan; |
292 | bool was_scanning = local->scanning; | 310 | bool was_scanning = local->scanning; |
311 | struct cfg80211_scan_request *scan_req; | ||
312 | struct ieee80211_sub_if_data *scan_sdata; | ||
293 | 313 | ||
294 | lockdep_assert_held(&local->mtx); | 314 | lockdep_assert_held(&local->mtx); |
295 | 315 | ||
@@ -322,9 +342,15 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
322 | kfree(local->hw_scan_req); | 342 | kfree(local->hw_scan_req); |
323 | local->hw_scan_req = NULL; | 343 | local->hw_scan_req = NULL; |
324 | 344 | ||
325 | if (local->scan_req != local->int_scan_req) | 345 | scan_req = rcu_dereference_protected(local->scan_req, |
326 | cfg80211_scan_done(local->scan_req, aborted); | 346 | lockdep_is_held(&local->mtx)); |
327 | local->scan_req = NULL; | 347 | |
348 | if (scan_req != local->int_scan_req) | ||
349 | cfg80211_scan_done(scan_req, aborted); | ||
350 | RCU_INIT_POINTER(local->scan_req, NULL); | ||
351 | |||
352 | scan_sdata = rcu_dereference_protected(local->scan_sdata, | ||
353 | lockdep_is_held(&local->mtx)); | ||
328 | RCU_INIT_POINTER(local->scan_sdata, NULL); | 354 | RCU_INIT_POINTER(local->scan_sdata, NULL); |
329 | 355 | ||
330 | local->scanning = 0; | 356 | local->scanning = 0; |
@@ -335,7 +361,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
335 | 361 | ||
336 | if (!hw_scan) { | 362 | if (!hw_scan) { |
337 | ieee80211_configure_filter(local); | 363 | ieee80211_configure_filter(local); |
338 | drv_sw_scan_complete(local); | 364 | drv_sw_scan_complete(local, scan_sdata); |
339 | ieee80211_offchannel_return(local); | 365 | ieee80211_offchannel_return(local); |
340 | } | 366 | } |
341 | 367 | ||
@@ -361,7 +387,8 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
361 | } | 387 | } |
362 | EXPORT_SYMBOL(ieee80211_scan_completed); | 388 | EXPORT_SYMBOL(ieee80211_scan_completed); |
363 | 389 | ||
364 | static int ieee80211_start_sw_scan(struct ieee80211_local *local) | 390 | static int ieee80211_start_sw_scan(struct ieee80211_local *local, |
391 | struct ieee80211_sub_if_data *sdata) | ||
365 | { | 392 | { |
366 | /* Software scan is not supported in multi-channel cases */ | 393 | /* Software scan is not supported in multi-channel cases */ |
367 | if (local->use_chanctx) | 394 | if (local->use_chanctx) |
@@ -380,7 +407,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) | |||
380 | * nullfunc frames and probe requests will be dropped in | 407 | * nullfunc frames and probe requests will be dropped in |
381 | * ieee80211_tx_h_check_assoc(). | 408 | * ieee80211_tx_h_check_assoc(). |
382 | */ | 409 | */ |
383 | drv_sw_scan_start(local); | 410 | drv_sw_scan_start(local, sdata, local->scan_addr); |
384 | 411 | ||
385 | local->leave_oper_channel_time = jiffies; | 412 | local->leave_oper_channel_time = jiffies; |
386 | local->next_scan_state = SCAN_DECISION; | 413 | local->next_scan_state = SCAN_DECISION; |
@@ -440,23 +467,26 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, | |||
440 | { | 467 | { |
441 | int i; | 468 | int i; |
442 | struct ieee80211_sub_if_data *sdata; | 469 | struct ieee80211_sub_if_data *sdata; |
470 | struct cfg80211_scan_request *scan_req; | ||
443 | enum ieee80211_band band = local->hw.conf.chandef.chan->band; | 471 | enum ieee80211_band band = local->hw.conf.chandef.chan->band; |
444 | u32 tx_flags; | 472 | u32 tx_flags; |
445 | 473 | ||
474 | scan_req = rcu_dereference_protected(local->scan_req, | ||
475 | lockdep_is_held(&local->mtx)); | ||
476 | |||
446 | tx_flags = IEEE80211_TX_INTFL_OFFCHAN_TX_OK; | 477 | tx_flags = IEEE80211_TX_INTFL_OFFCHAN_TX_OK; |
447 | if (local->scan_req->no_cck) | 478 | if (scan_req->no_cck) |
448 | tx_flags |= IEEE80211_TX_CTL_NO_CCK_RATE; | 479 | tx_flags |= IEEE80211_TX_CTL_NO_CCK_RATE; |
449 | 480 | ||
450 | sdata = rcu_dereference_protected(local->scan_sdata, | 481 | sdata = rcu_dereference_protected(local->scan_sdata, |
451 | lockdep_is_held(&local->mtx)); | 482 | lockdep_is_held(&local->mtx)); |
452 | 483 | ||
453 | for (i = 0; i < local->scan_req->n_ssids; i++) | 484 | for (i = 0; i < scan_req->n_ssids; i++) |
454 | ieee80211_send_probe_req( | 485 | ieee80211_send_probe_req( |
455 | sdata, NULL, | 486 | sdata, local->scan_addr, NULL, |
456 | local->scan_req->ssids[i].ssid, | 487 | scan_req->ssids[i].ssid, scan_req->ssids[i].ssid_len, |
457 | local->scan_req->ssids[i].ssid_len, | 488 | scan_req->ie, scan_req->ie_len, |
458 | local->scan_req->ie, local->scan_req->ie_len, | 489 | scan_req->rates[band], false, |
459 | local->scan_req->rates[band], false, | ||
460 | tx_flags, local->hw.conf.chandef.chan, true); | 490 | tx_flags, local->hw.conf.chandef.chan, true); |
461 | 491 | ||
462 | /* | 492 | /* |
@@ -480,7 +510,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
480 | 510 | ||
481 | if (!ieee80211_can_scan(local, sdata)) { | 511 | if (!ieee80211_can_scan(local, sdata)) { |
482 | /* wait for the work to finish/time out */ | 512 | /* wait for the work to finish/time out */ |
483 | local->scan_req = req; | 513 | rcu_assign_pointer(local->scan_req, req); |
484 | rcu_assign_pointer(local->scan_sdata, sdata); | 514 | rcu_assign_pointer(local->scan_sdata, sdata); |
485 | return 0; | 515 | return 0; |
486 | } | 516 | } |
@@ -530,9 +560,16 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
530 | */ | 560 | */ |
531 | } | 561 | } |
532 | 562 | ||
533 | local->scan_req = req; | 563 | rcu_assign_pointer(local->scan_req, req); |
534 | rcu_assign_pointer(local->scan_sdata, sdata); | 564 | rcu_assign_pointer(local->scan_sdata, sdata); |
535 | 565 | ||
566 | if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) | ||
567 | get_random_mask_addr(local->scan_addr, | ||
568 | req->mac_addr, | ||
569 | req->mac_addr_mask); | ||
570 | else | ||
571 | memcpy(local->scan_addr, sdata->vif.addr, ETH_ALEN); | ||
572 | |||
536 | if (local->ops->hw_scan) { | 573 | if (local->ops->hw_scan) { |
537 | __set_bit(SCAN_HW_SCANNING, &local->scanning); | 574 | __set_bit(SCAN_HW_SCANNING, &local->scanning); |
538 | } else if ((req->n_channels == 1) && | 575 | } else if ((req->n_channels == 1) && |
@@ -549,7 +586,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
549 | 586 | ||
550 | /* Notify driver scan is starting, keep order of operations | 587 | /* Notify driver scan is starting, keep order of operations |
551 | * same as normal software scan, in case that matters. */ | 588 | * same as normal software scan, in case that matters. */ |
552 | drv_sw_scan_start(local); | 589 | drv_sw_scan_start(local, sdata, local->scan_addr); |
553 | 590 | ||
554 | ieee80211_configure_filter(local); /* accept probe-responses */ | 591 | ieee80211_configure_filter(local); /* accept probe-responses */ |
555 | 592 | ||
@@ -558,7 +595,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
558 | 595 | ||
559 | if ((req->channels[0]->flags & | 596 | if ((req->channels[0]->flags & |
560 | IEEE80211_CHAN_NO_IR) || | 597 | IEEE80211_CHAN_NO_IR) || |
561 | !local->scan_req->n_ssids) { | 598 | !req->n_ssids) { |
562 | next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; | 599 | next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; |
563 | } else { | 600 | } else { |
564 | ieee80211_scan_state_send_probe(local, &next_delay); | 601 | ieee80211_scan_state_send_probe(local, &next_delay); |
@@ -579,8 +616,9 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
579 | if (local->ops->hw_scan) { | 616 | if (local->ops->hw_scan) { |
580 | WARN_ON(!ieee80211_prep_hw_scan(local)); | 617 | WARN_ON(!ieee80211_prep_hw_scan(local)); |
581 | rc = drv_hw_scan(local, sdata, local->hw_scan_req); | 618 | rc = drv_hw_scan(local, sdata, local->hw_scan_req); |
582 | } else | 619 | } else { |
583 | rc = ieee80211_start_sw_scan(local); | 620 | rc = ieee80211_start_sw_scan(local, sdata); |
621 | } | ||
584 | 622 | ||
585 | if (rc) { | 623 | if (rc) { |
586 | kfree(local->hw_scan_req); | 624 | kfree(local->hw_scan_req); |
@@ -617,6 +655,7 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
617 | struct ieee80211_sub_if_data *sdata; | 655 | struct ieee80211_sub_if_data *sdata; |
618 | struct ieee80211_channel *next_chan; | 656 | struct ieee80211_channel *next_chan; |
619 | enum mac80211_scan_state next_scan_state; | 657 | enum mac80211_scan_state next_scan_state; |
658 | struct cfg80211_scan_request *scan_req; | ||
620 | 659 | ||
621 | /* | 660 | /* |
622 | * check if at least one STA interface is associated, | 661 | * check if at least one STA interface is associated, |
@@ -641,7 +680,10 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
641 | } | 680 | } |
642 | mutex_unlock(&local->iflist_mtx); | 681 | mutex_unlock(&local->iflist_mtx); |
643 | 682 | ||
644 | next_chan = local->scan_req->channels[local->scan_channel_idx]; | 683 | scan_req = rcu_dereference_protected(local->scan_req, |
684 | lockdep_is_held(&local->mtx)); | ||
685 | |||
686 | next_chan = scan_req->channels[local->scan_channel_idx]; | ||
645 | 687 | ||
646 | /* | 688 | /* |
647 | * we're currently scanning a different channel, let's | 689 | * we're currently scanning a different channel, let's |
@@ -656,7 +698,7 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
656 | local->leave_oper_channel_time + HZ / 8); | 698 | local->leave_oper_channel_time + HZ / 8); |
657 | 699 | ||
658 | if (associated && !tx_empty) { | 700 | if (associated && !tx_empty) { |
659 | if (local->scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) | 701 | if (scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) |
660 | next_scan_state = SCAN_ABORT; | 702 | next_scan_state = SCAN_ABORT; |
661 | else | 703 | else |
662 | next_scan_state = SCAN_SUSPEND; | 704 | next_scan_state = SCAN_SUSPEND; |
@@ -677,14 +719,18 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, | |||
677 | int skip; | 719 | int skip; |
678 | struct ieee80211_channel *chan; | 720 | struct ieee80211_channel *chan; |
679 | enum nl80211_bss_scan_width oper_scan_width; | 721 | enum nl80211_bss_scan_width oper_scan_width; |
722 | struct cfg80211_scan_request *scan_req; | ||
723 | |||
724 | scan_req = rcu_dereference_protected(local->scan_req, | ||
725 | lockdep_is_held(&local->mtx)); | ||
680 | 726 | ||
681 | skip = 0; | 727 | skip = 0; |
682 | chan = local->scan_req->channels[local->scan_channel_idx]; | 728 | chan = scan_req->channels[local->scan_channel_idx]; |
683 | 729 | ||
684 | local->scan_chandef.chan = chan; | 730 | local->scan_chandef.chan = chan; |
685 | local->scan_chandef.center_freq1 = chan->center_freq; | 731 | local->scan_chandef.center_freq1 = chan->center_freq; |
686 | local->scan_chandef.center_freq2 = 0; | 732 | local->scan_chandef.center_freq2 = 0; |
687 | switch (local->scan_req->scan_width) { | 733 | switch (scan_req->scan_width) { |
688 | case NL80211_BSS_CHAN_WIDTH_5: | 734 | case NL80211_BSS_CHAN_WIDTH_5: |
689 | local->scan_chandef.width = NL80211_CHAN_WIDTH_5; | 735 | local->scan_chandef.width = NL80211_CHAN_WIDTH_5; |
690 | break; | 736 | break; |
@@ -698,7 +744,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, | |||
698 | oper_scan_width = cfg80211_chandef_to_scan_width( | 744 | oper_scan_width = cfg80211_chandef_to_scan_width( |
699 | &local->_oper_chandef); | 745 | &local->_oper_chandef); |
700 | if (chan == local->_oper_chandef.chan && | 746 | if (chan == local->_oper_chandef.chan && |
701 | oper_scan_width == local->scan_req->scan_width) | 747 | oper_scan_width == scan_req->scan_width) |
702 | local->scan_chandef = local->_oper_chandef; | 748 | local->scan_chandef = local->_oper_chandef; |
703 | else | 749 | else |
704 | local->scan_chandef.width = NL80211_CHAN_WIDTH_20_NOHT; | 750 | local->scan_chandef.width = NL80211_CHAN_WIDTH_20_NOHT; |
@@ -727,8 +773,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, | |||
727 | * | 773 | * |
728 | * In any case, it is not necessary for a passive scan. | 774 | * In any case, it is not necessary for a passive scan. |
729 | */ | 775 | */ |
730 | if (chan->flags & IEEE80211_CHAN_NO_IR || | 776 | if (chan->flags & IEEE80211_CHAN_NO_IR || !scan_req->n_ssids) { |
731 | !local->scan_req->n_ssids) { | ||
732 | *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; | 777 | *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; |
733 | local->next_scan_state = SCAN_DECISION; | 778 | local->next_scan_state = SCAN_DECISION; |
734 | return; | 779 | return; |
@@ -777,6 +822,7 @@ void ieee80211_scan_work(struct work_struct *work) | |||
777 | struct ieee80211_local *local = | 822 | struct ieee80211_local *local = |
778 | container_of(work, struct ieee80211_local, scan_work.work); | 823 | container_of(work, struct ieee80211_local, scan_work.work); |
779 | struct ieee80211_sub_if_data *sdata; | 824 | struct ieee80211_sub_if_data *sdata; |
825 | struct cfg80211_scan_request *scan_req; | ||
780 | unsigned long next_delay = 0; | 826 | unsigned long next_delay = 0; |
781 | bool aborted; | 827 | bool aborted; |
782 | 828 | ||
@@ -784,6 +830,8 @@ void ieee80211_scan_work(struct work_struct *work) | |||
784 | 830 | ||
785 | sdata = rcu_dereference_protected(local->scan_sdata, | 831 | sdata = rcu_dereference_protected(local->scan_sdata, |
786 | lockdep_is_held(&local->mtx)); | 832 | lockdep_is_held(&local->mtx)); |
833 | scan_req = rcu_dereference_protected(local->scan_req, | ||
834 | lockdep_is_held(&local->mtx)); | ||
787 | 835 | ||
788 | /* When scanning on-channel, the first-callback means completed. */ | 836 | /* When scanning on-channel, the first-callback means completed. */ |
789 | if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) { | 837 | if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) { |
@@ -796,20 +844,19 @@ void ieee80211_scan_work(struct work_struct *work) | |||
796 | goto out_complete; | 844 | goto out_complete; |
797 | } | 845 | } |
798 | 846 | ||
799 | if (!sdata || !local->scan_req) | 847 | if (!sdata || !scan_req) |
800 | goto out; | 848 | goto out; |
801 | 849 | ||
802 | if (local->scan_req && !local->scanning) { | 850 | if (!local->scanning) { |
803 | struct cfg80211_scan_request *req = local->scan_req; | ||
804 | int rc; | 851 | int rc; |
805 | 852 | ||
806 | local->scan_req = NULL; | 853 | RCU_INIT_POINTER(local->scan_req, NULL); |
807 | RCU_INIT_POINTER(local->scan_sdata, NULL); | 854 | RCU_INIT_POINTER(local->scan_sdata, NULL); |
808 | 855 | ||
809 | rc = __ieee80211_start_scan(sdata, req); | 856 | rc = __ieee80211_start_scan(sdata, scan_req); |
810 | if (rc) { | 857 | if (rc) { |
811 | /* need to complete scan in cfg80211 */ | 858 | /* need to complete scan in cfg80211 */ |
812 | local->scan_req = req; | 859 | rcu_assign_pointer(local->scan_req, scan_req); |
813 | aborted = true; | 860 | aborted = true; |
814 | goto out_complete; | 861 | goto out_complete; |
815 | } else | 862 | } else |
@@ -829,7 +876,7 @@ void ieee80211_scan_work(struct work_struct *work) | |||
829 | switch (local->next_scan_state) { | 876 | switch (local->next_scan_state) { |
830 | case SCAN_DECISION: | 877 | case SCAN_DECISION: |
831 | /* if no more bands/channels left, complete scan */ | 878 | /* if no more bands/channels left, complete scan */ |
832 | if (local->scan_channel_idx >= local->scan_req->n_channels) { | 879 | if (local->scan_channel_idx >= scan_req->n_channels) { |
833 | aborted = false; | 880 | aborted = false; |
834 | goto out_complete; | 881 | goto out_complete; |
835 | } | 882 | } |
@@ -1043,7 +1090,7 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | |||
1043 | ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); | 1090 | ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); |
1044 | if (ret == 0) { | 1091 | if (ret == 0) { |
1045 | rcu_assign_pointer(local->sched_scan_sdata, sdata); | 1092 | rcu_assign_pointer(local->sched_scan_sdata, sdata); |
1046 | local->sched_scan_req = req; | 1093 | rcu_assign_pointer(local->sched_scan_req, req); |
1047 | } | 1094 | } |
1048 | 1095 | ||
1049 | kfree(ie); | 1096 | kfree(ie); |
@@ -1052,7 +1099,7 @@ out: | |||
1052 | if (ret) { | 1099 | if (ret) { |
1053 | /* Clean in case of failure after HW restart or upon resume. */ | 1100 | /* Clean in case of failure after HW restart or upon resume. */ |
1054 | RCU_INIT_POINTER(local->sched_scan_sdata, NULL); | 1101 | RCU_INIT_POINTER(local->sched_scan_sdata, NULL); |
1055 | local->sched_scan_req = NULL; | 1102 | RCU_INIT_POINTER(local->sched_scan_req, NULL); |
1056 | } | 1103 | } |
1057 | 1104 | ||
1058 | return ret; | 1105 | return ret; |
@@ -1090,7 +1137,7 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) | |||
1090 | } | 1137 | } |
1091 | 1138 | ||
1092 | /* We don't want to restart sched scan anymore. */ | 1139 | /* We don't want to restart sched scan anymore. */ |
1093 | local->sched_scan_req = NULL; | 1140 | RCU_INIT_POINTER(local->sched_scan_req, NULL); |
1094 | 1141 | ||
1095 | if (rcu_access_pointer(local->sched_scan_sdata)) { | 1142 | if (rcu_access_pointer(local->sched_scan_sdata)) { |
1096 | ret = drv_sched_scan_stop(local, sdata); | 1143 | ret = drv_sched_scan_stop(local, sdata); |
@@ -1125,7 +1172,7 @@ void ieee80211_sched_scan_end(struct ieee80211_local *local) | |||
1125 | RCU_INIT_POINTER(local->sched_scan_sdata, NULL); | 1172 | RCU_INIT_POINTER(local->sched_scan_sdata, NULL); |
1126 | 1173 | ||
1127 | /* If sched scan was aborted by the driver. */ | 1174 | /* If sched scan was aborted by the driver. */ |
1128 | local->sched_scan_req = NULL; | 1175 | RCU_INIT_POINTER(local->sched_scan_req, NULL); |
1129 | 1176 | ||
1130 | mutex_unlock(&local->mtx); | 1177 | mutex_unlock(&local->mtx); |
1131 | 1178 | ||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index adc25371b171..a42f5b2b024d 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -351,6 +351,9 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
351 | 351 | ||
352 | sta->sta_state = IEEE80211_STA_NONE; | 352 | sta->sta_state = IEEE80211_STA_NONE; |
353 | 353 | ||
354 | /* Mark TID as unreserved */ | ||
355 | sta->reserved_tid = IEEE80211_TID_UNRESERVED; | ||
356 | |||
354 | ktime_get_ts(&uptime); | 357 | ktime_get_ts(&uptime); |
355 | sta->last_connected = uptime.tv_sec; | 358 | sta->last_connected = uptime.tv_sec; |
356 | ewma_init(&sta->avg_signal, 1024, 8); | 359 | ewma_init(&sta->avg_signal, 1024, 8); |
@@ -847,6 +850,15 @@ static int __must_check __sta_info_destroy_part1(struct sta_info *sta) | |||
847 | if (WARN_ON(ret)) | 850 | if (WARN_ON(ret)) |
848 | return ret; | 851 | return ret; |
849 | 852 | ||
853 | /* | ||
854 | * for TDLS peers, make sure to return to the base channel before | ||
855 | * removal. | ||
856 | */ | ||
857 | if (test_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL)) { | ||
858 | drv_tdls_cancel_channel_switch(local, sdata, &sta->sta); | ||
859 | clear_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL); | ||
860 | } | ||
861 | |||
850 | list_del_rcu(&sta->list); | 862 | list_del_rcu(&sta->list); |
851 | 863 | ||
852 | drv_sta_pre_rcu_remove(local, sta->sdata, sta); | 864 | drv_sta_pre_rcu_remove(local, sta->sdata, sta); |
@@ -1249,7 +1261,8 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, | |||
1249 | return; | 1261 | return; |
1250 | } | 1262 | } |
1251 | 1263 | ||
1252 | ieee80211_xmit(sdata, skb, chanctx_conf->def.chan->band); | 1264 | info->band = chanctx_conf->def.chan->band; |
1265 | ieee80211_xmit(sdata, skb); | ||
1253 | rcu_read_unlock(); | 1266 | rcu_read_unlock(); |
1254 | } | 1267 | } |
1255 | 1268 | ||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index bcda2ac7d844..4f052bb2a5ad 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -49,6 +49,9 @@ | |||
49 | * packets. This means the link is enabled. | 49 | * packets. This means the link is enabled. |
50 | * @WLAN_STA_TDLS_INITIATOR: We are the initiator of the TDLS link with this | 50 | * @WLAN_STA_TDLS_INITIATOR: We are the initiator of the TDLS link with this |
51 | * station. | 51 | * station. |
52 | * @WLAN_STA_TDLS_CHAN_SWITCH: This TDLS peer supports TDLS channel-switching | ||
53 | * @WLAN_STA_TDLS_OFF_CHANNEL: The local STA is currently off-channel with this | ||
54 | * TDLS peer | ||
52 | * @WLAN_STA_UAPSD: Station requested unscheduled SP while driver was | 55 | * @WLAN_STA_UAPSD: Station requested unscheduled SP while driver was |
53 | * keeping station in power-save mode, reply when the driver | 56 | * keeping station in power-save mode, reply when the driver |
54 | * unblocks the station. | 57 | * unblocks the station. |
@@ -78,6 +81,8 @@ enum ieee80211_sta_info_flags { | |||
78 | WLAN_STA_TDLS_PEER, | 81 | WLAN_STA_TDLS_PEER, |
79 | WLAN_STA_TDLS_PEER_AUTH, | 82 | WLAN_STA_TDLS_PEER_AUTH, |
80 | WLAN_STA_TDLS_INITIATOR, | 83 | WLAN_STA_TDLS_INITIATOR, |
84 | WLAN_STA_TDLS_CHAN_SWITCH, | ||
85 | WLAN_STA_TDLS_OFF_CHANNEL, | ||
81 | WLAN_STA_UAPSD, | 86 | WLAN_STA_UAPSD, |
82 | WLAN_STA_SP, | 87 | WLAN_STA_SP, |
83 | WLAN_STA_4ADDR_EVENT, | 88 | WLAN_STA_4ADDR_EVENT, |
@@ -249,6 +254,9 @@ struct ieee80211_tx_latency_stat { | |||
249 | u32 bin_count; | 254 | u32 bin_count; |
250 | }; | 255 | }; |
251 | 256 | ||
257 | /* Value to indicate no TID reservation */ | ||
258 | #define IEEE80211_TID_UNRESERVED 0xff | ||
259 | |||
252 | /** | 260 | /** |
253 | * struct sta_info - STA information | 261 | * struct sta_info - STA information |
254 | * | 262 | * |
@@ -337,6 +345,7 @@ struct ieee80211_tx_latency_stat { | |||
337 | * AP only. | 345 | * AP only. |
338 | * @cipher_scheme: optional cipher scheme for this station | 346 | * @cipher_scheme: optional cipher scheme for this station |
339 | * @last_tdls_pkt_time: holds the time in jiffies of last TDLS pkt ACKed | 347 | * @last_tdls_pkt_time: holds the time in jiffies of last TDLS pkt ACKed |
348 | * @reserved_tid: reserved TID (if any, otherwise IEEE80211_TID_UNRESERVED) | ||
340 | */ | 349 | */ |
341 | struct sta_info { | 350 | struct sta_info { |
342 | /* General information, mostly static */ | 351 | /* General information, mostly static */ |
@@ -454,6 +463,8 @@ struct sta_info { | |||
454 | /* TDLS timeout data */ | 463 | /* TDLS timeout data */ |
455 | unsigned long last_tdls_pkt_time; | 464 | unsigned long last_tdls_pkt_time; |
456 | 465 | ||
466 | u8 reserved_tid; | ||
467 | |||
457 | /* keep last! */ | 468 | /* keep last! */ |
458 | struct ieee80211_sta sta; | 469 | struct ieee80211_sta sta; |
459 | }; | 470 | }; |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 9612d89fad56..71de2d3866cc 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -390,6 +390,46 @@ ieee80211_add_tx_radiotap_header(struct ieee80211_local *local, | |||
390 | } | 390 | } |
391 | } | 391 | } |
392 | 392 | ||
393 | /* | ||
394 | * Handles the tx for TDLS teardown frames. | ||
395 | * If the frame wasn't ACKed by the peer - it will be re-sent through the AP | ||
396 | */ | ||
397 | static void ieee80211_tdls_td_tx_handle(struct ieee80211_local *local, | ||
398 | struct ieee80211_sub_if_data *sdata, | ||
399 | struct sk_buff *skb, u32 flags) | ||
400 | { | ||
401 | struct sk_buff *teardown_skb; | ||
402 | struct sk_buff *orig_teardown_skb; | ||
403 | bool is_teardown = false; | ||
404 | |||
405 | /* Get the teardown data we need and free the lock */ | ||
406 | spin_lock(&sdata->u.mgd.teardown_lock); | ||
407 | teardown_skb = sdata->u.mgd.teardown_skb; | ||
408 | orig_teardown_skb = sdata->u.mgd.orig_teardown_skb; | ||
409 | if ((skb == orig_teardown_skb) && teardown_skb) { | ||
410 | sdata->u.mgd.teardown_skb = NULL; | ||
411 | sdata->u.mgd.orig_teardown_skb = NULL; | ||
412 | is_teardown = true; | ||
413 | } | ||
414 | spin_unlock(&sdata->u.mgd.teardown_lock); | ||
415 | |||
416 | if (is_teardown) { | ||
417 | /* This mechanism relies on being able to get ACKs */ | ||
418 | WARN_ON(!(local->hw.flags & | ||
419 | IEEE80211_HW_REPORTS_TX_ACK_STATUS)); | ||
420 | |||
421 | /* Check if peer has ACKed */ | ||
422 | if (flags & IEEE80211_TX_STAT_ACK) { | ||
423 | dev_kfree_skb_any(teardown_skb); | ||
424 | } else { | ||
425 | tdls_dbg(sdata, | ||
426 | "TDLS Resending teardown through AP\n"); | ||
427 | |||
428 | ieee80211_subif_start_xmit(teardown_skb, skb->dev); | ||
429 | } | ||
430 | } | ||
431 | } | ||
432 | |||
393 | static void ieee80211_report_used_skb(struct ieee80211_local *local, | 433 | static void ieee80211_report_used_skb(struct ieee80211_local *local, |
394 | struct sk_buff *skb, bool dropped) | 434 | struct sk_buff *skb, bool dropped) |
395 | { | 435 | { |
@@ -426,8 +466,19 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local, | |||
426 | if (!sdata) { | 466 | if (!sdata) { |
427 | skb->dev = NULL; | 467 | skb->dev = NULL; |
428 | } else if (info->flags & IEEE80211_TX_INTFL_MLME_CONN_TX) { | 468 | } else if (info->flags & IEEE80211_TX_INTFL_MLME_CONN_TX) { |
429 | ieee80211_mgd_conn_tx_status(sdata, hdr->frame_control, | 469 | unsigned int hdr_size = |
430 | acked); | 470 | ieee80211_hdrlen(hdr->frame_control); |
471 | |||
472 | /* Check to see if packet is a TDLS teardown packet */ | ||
473 | if (ieee80211_is_data(hdr->frame_control) && | ||
474 | (ieee80211_get_tdls_action(skb, hdr_size) == | ||
475 | WLAN_TDLS_TEARDOWN)) | ||
476 | ieee80211_tdls_td_tx_handle(local, sdata, skb, | ||
477 | info->flags); | ||
478 | else | ||
479 | ieee80211_mgd_conn_tx_status(sdata, | ||
480 | hdr->frame_control, | ||
481 | acked); | ||
431 | } else if (ieee80211_is_nullfunc(hdr->frame_control) || | 482 | } else if (ieee80211_is_nullfunc(hdr->frame_control) || |
432 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { | 483 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { |
433 | cfg80211_probe_status(sdata->dev, hdr->addr1, | 484 | cfg80211_probe_status(sdata->dev, hdr->addr1, |
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index b4f368e2cb3b..55ddd77b865d 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c | |||
@@ -35,19 +35,101 @@ void ieee80211_tdls_peer_del_work(struct work_struct *wk) | |||
35 | mutex_unlock(&local->mtx); | 35 | mutex_unlock(&local->mtx); |
36 | } | 36 | } |
37 | 37 | ||
38 | static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb) | 38 | static void ieee80211_tdls_add_ext_capab(struct ieee80211_local *local, |
39 | struct sk_buff *skb) | ||
39 | { | 40 | { |
40 | u8 *pos = (void *)skb_put(skb, 7); | 41 | u8 *pos = (void *)skb_put(skb, 7); |
42 | bool chan_switch = local->hw.wiphy->features & | ||
43 | NL80211_FEATURE_TDLS_CHANNEL_SWITCH; | ||
41 | 44 | ||
42 | *pos++ = WLAN_EID_EXT_CAPABILITY; | 45 | *pos++ = WLAN_EID_EXT_CAPABILITY; |
43 | *pos++ = 5; /* len */ | 46 | *pos++ = 5; /* len */ |
44 | *pos++ = 0x0; | 47 | *pos++ = 0x0; |
45 | *pos++ = 0x0; | 48 | *pos++ = 0x0; |
46 | *pos++ = 0x0; | 49 | *pos++ = 0x0; |
47 | *pos++ = 0x0; | 50 | *pos++ = chan_switch ? WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH : 0; |
48 | *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED; | 51 | *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED; |
49 | } | 52 | } |
50 | 53 | ||
54 | static u8 | ||
55 | ieee80211_tdls_add_subband(struct ieee80211_sub_if_data *sdata, | ||
56 | struct sk_buff *skb, u16 start, u16 end, | ||
57 | u16 spacing) | ||
58 | { | ||
59 | u8 subband_cnt = 0, ch_cnt = 0; | ||
60 | struct ieee80211_channel *ch; | ||
61 | struct cfg80211_chan_def chandef; | ||
62 | int i, subband_start; | ||
63 | |||
64 | for (i = start; i <= end; i += spacing) { | ||
65 | if (!ch_cnt) | ||
66 | subband_start = i; | ||
67 | |||
68 | ch = ieee80211_get_channel(sdata->local->hw.wiphy, i); | ||
69 | if (ch) { | ||
70 | /* we will be active on the channel */ | ||
71 | u32 flags = IEEE80211_CHAN_DISABLED | | ||
72 | IEEE80211_CHAN_NO_IR; | ||
73 | cfg80211_chandef_create(&chandef, ch, | ||
74 | NL80211_CHAN_HT20); | ||
75 | if (cfg80211_chandef_usable(sdata->local->hw.wiphy, | ||
76 | &chandef, flags)) { | ||
77 | ch_cnt++; | ||
78 | continue; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | if (ch_cnt) { | ||
83 | u8 *pos = skb_put(skb, 2); | ||
84 | *pos++ = ieee80211_frequency_to_channel(subband_start); | ||
85 | *pos++ = ch_cnt; | ||
86 | |||
87 | subband_cnt++; | ||
88 | ch_cnt = 0; | ||
89 | } | ||
90 | } | ||
91 | |||
92 | return subband_cnt; | ||
93 | } | ||
94 | |||
95 | static void | ||
96 | ieee80211_tdls_add_supp_channels(struct ieee80211_sub_if_data *sdata, | ||
97 | struct sk_buff *skb) | ||
98 | { | ||
99 | /* | ||
100 | * Add possible channels for TDLS. These are channels that are allowed | ||
101 | * to be active. | ||
102 | */ | ||
103 | u8 subband_cnt; | ||
104 | u8 *pos = skb_put(skb, 2); | ||
105 | |||
106 | *pos++ = WLAN_EID_SUPPORTED_CHANNELS; | ||
107 | |||
108 | /* | ||
109 | * 5GHz and 2GHz channels numbers can overlap. Ignore this for now, as | ||
110 | * this doesn't happen in real world scenarios. | ||
111 | */ | ||
112 | |||
113 | /* 2GHz, with 5MHz spacing */ | ||
114 | subband_cnt = ieee80211_tdls_add_subband(sdata, skb, 2412, 2472, 5); | ||
115 | |||
116 | /* 5GHz, with 20MHz spacing */ | ||
117 | subband_cnt += ieee80211_tdls_add_subband(sdata, skb, 5000, 5825, 20); | ||
118 | |||
119 | /* length */ | ||
120 | *pos = 2 * subband_cnt; | ||
121 | } | ||
122 | |||
123 | static void ieee80211_tdls_add_bss_coex_ie(struct sk_buff *skb) | ||
124 | { | ||
125 | u8 *pos = (void *)skb_put(skb, 3); | ||
126 | |||
127 | *pos++ = WLAN_EID_BSS_COEX_2040; | ||
128 | *pos++ = 1; /* len */ | ||
129 | |||
130 | *pos++ = WLAN_BSS_COEX_INFORMATION_REQUEST; | ||
131 | } | ||
132 | |||
51 | static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata, | 133 | static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata, |
52 | u16 status_code) | 134 | u16 status_code) |
53 | { | 135 | { |
@@ -190,6 +272,7 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, | |||
190 | 272 | ||
191 | ieee80211_add_srates_ie(sdata, skb, false, band); | 273 | ieee80211_add_srates_ie(sdata, skb, false, band); |
192 | ieee80211_add_ext_srates_ie(sdata, skb, false, band); | 274 | ieee80211_add_ext_srates_ie(sdata, skb, false, band); |
275 | ieee80211_tdls_add_supp_channels(sdata, skb); | ||
193 | 276 | ||
194 | /* add any custom IEs that go before Extended Capabilities */ | 277 | /* add any custom IEs that go before Extended Capabilities */ |
195 | if (extra_ies_len) { | 278 | if (extra_ies_len) { |
@@ -209,7 +292,7 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, | |||
209 | offset = noffset; | 292 | offset = noffset; |
210 | } | 293 | } |
211 | 294 | ||
212 | ieee80211_tdls_add_ext_capab(skb); | 295 | ieee80211_tdls_add_ext_capab(local, skb); |
213 | 296 | ||
214 | /* add the QoS element if we support it */ | 297 | /* add the QoS element if we support it */ |
215 | if (local->hw.queues >= IEEE80211_NUM_ACS && | 298 | if (local->hw.queues >= IEEE80211_NUM_ACS && |
@@ -271,6 +354,10 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, | |||
271 | 354 | ||
272 | rcu_read_unlock(); | 355 | rcu_read_unlock(); |
273 | 356 | ||
357 | if (ht_cap.ht_supported && | ||
358 | (ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
359 | ieee80211_tdls_add_bss_coex_ie(skb); | ||
360 | |||
274 | /* add any remaining IEs */ | 361 | /* add any remaining IEs */ |
275 | if (extra_ies_len) { | 362 | if (extra_ies_len) { |
276 | noffset = extra_ies_len; | 363 | noffset = extra_ies_len; |
@@ -362,11 +449,68 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, | |||
362 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | 449 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); |
363 | } | 450 | } |
364 | 451 | ||
452 | static void | ||
453 | ieee80211_tdls_add_chan_switch_req_ies(struct ieee80211_sub_if_data *sdata, | ||
454 | struct sk_buff *skb, const u8 *peer, | ||
455 | bool initiator, const u8 *extra_ies, | ||
456 | size_t extra_ies_len, u8 oper_class, | ||
457 | struct cfg80211_chan_def *chandef) | ||
458 | { | ||
459 | struct ieee80211_tdls_data *tf; | ||
460 | size_t offset = 0, noffset; | ||
461 | u8 *pos; | ||
462 | |||
463 | if (WARN_ON_ONCE(!chandef)) | ||
464 | return; | ||
465 | |||
466 | tf = (void *)skb->data; | ||
467 | tf->u.chan_switch_req.target_channel = | ||
468 | ieee80211_frequency_to_channel(chandef->chan->center_freq); | ||
469 | tf->u.chan_switch_req.oper_class = oper_class; | ||
470 | |||
471 | if (extra_ies_len) { | ||
472 | static const u8 before_lnkie[] = { | ||
473 | WLAN_EID_SECONDARY_CHANNEL_OFFSET, | ||
474 | }; | ||
475 | noffset = ieee80211_ie_split(extra_ies, extra_ies_len, | ||
476 | before_lnkie, | ||
477 | ARRAY_SIZE(before_lnkie), | ||
478 | offset); | ||
479 | pos = skb_put(skb, noffset - offset); | ||
480 | memcpy(pos, extra_ies + offset, noffset - offset); | ||
481 | offset = noffset; | ||
482 | } | ||
483 | |||
484 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | ||
485 | |||
486 | /* add any remaining IEs */ | ||
487 | if (extra_ies_len) { | ||
488 | noffset = extra_ies_len; | ||
489 | pos = skb_put(skb, noffset - offset); | ||
490 | memcpy(pos, extra_ies + offset, noffset - offset); | ||
491 | } | ||
492 | } | ||
493 | |||
494 | static void | ||
495 | ieee80211_tdls_add_chan_switch_resp_ies(struct ieee80211_sub_if_data *sdata, | ||
496 | struct sk_buff *skb, const u8 *peer, | ||
497 | u16 status_code, bool initiator, | ||
498 | const u8 *extra_ies, | ||
499 | size_t extra_ies_len) | ||
500 | { | ||
501 | if (status_code == 0) | ||
502 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | ||
503 | |||
504 | if (extra_ies_len) | ||
505 | memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len); | ||
506 | } | ||
507 | |||
365 | static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, | 508 | static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, |
366 | struct sk_buff *skb, const u8 *peer, | 509 | struct sk_buff *skb, const u8 *peer, |
367 | u8 action_code, u16 status_code, | 510 | u8 action_code, u16 status_code, |
368 | bool initiator, const u8 *extra_ies, | 511 | bool initiator, const u8 *extra_ies, |
369 | size_t extra_ies_len) | 512 | size_t extra_ies_len, u8 oper_class, |
513 | struct cfg80211_chan_def *chandef) | ||
370 | { | 514 | { |
371 | switch (action_code) { | 515 | switch (action_code) { |
372 | case WLAN_TDLS_SETUP_REQUEST: | 516 | case WLAN_TDLS_SETUP_REQUEST: |
@@ -393,6 +537,18 @@ static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, | |||
393 | if (status_code == 0 || action_code == WLAN_TDLS_TEARDOWN) | 537 | if (status_code == 0 || action_code == WLAN_TDLS_TEARDOWN) |
394 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | 538 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); |
395 | break; | 539 | break; |
540 | case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: | ||
541 | ieee80211_tdls_add_chan_switch_req_ies(sdata, skb, peer, | ||
542 | initiator, extra_ies, | ||
543 | extra_ies_len, | ||
544 | oper_class, chandef); | ||
545 | break; | ||
546 | case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: | ||
547 | ieee80211_tdls_add_chan_switch_resp_ies(sdata, skb, peer, | ||
548 | status_code, | ||
549 | initiator, extra_ies, | ||
550 | extra_ies_len); | ||
551 | break; | ||
396 | } | 552 | } |
397 | 553 | ||
398 | } | 554 | } |
@@ -459,6 +615,19 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
459 | skb_put(skb, sizeof(tf->u.discover_req)); | 615 | skb_put(skb, sizeof(tf->u.discover_req)); |
460 | tf->u.discover_req.dialog_token = dialog_token; | 616 | tf->u.discover_req.dialog_token = dialog_token; |
461 | break; | 617 | break; |
618 | case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: | ||
619 | tf->category = WLAN_CATEGORY_TDLS; | ||
620 | tf->action_code = WLAN_TDLS_CHANNEL_SWITCH_REQUEST; | ||
621 | |||
622 | skb_put(skb, sizeof(tf->u.chan_switch_req)); | ||
623 | break; | ||
624 | case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: | ||
625 | tf->category = WLAN_CATEGORY_TDLS; | ||
626 | tf->action_code = WLAN_TDLS_CHANNEL_SWITCH_RESPONSE; | ||
627 | |||
628 | skb_put(skb, sizeof(tf->u.chan_switch_resp)); | ||
629 | tf->u.chan_switch_resp.status_code = cpu_to_le16(status_code); | ||
630 | break; | ||
462 | default: | 631 | default: |
463 | return -EINVAL; | 632 | return -EINVAL; |
464 | } | 633 | } |
@@ -502,32 +671,33 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, | |||
502 | return 0; | 671 | return 0; |
503 | } | 672 | } |
504 | 673 | ||
505 | static int | 674 | static struct sk_buff * |
506 | ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | 675 | ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata, |
507 | const u8 *peer, u8 action_code, | 676 | const u8 *peer, u8 action_code, |
508 | u8 dialog_token, u16 status_code, | 677 | u8 dialog_token, u16 status_code, |
509 | u32 peer_capability, bool initiator, | 678 | bool initiator, const u8 *extra_ies, |
510 | const u8 *extra_ies, size_t extra_ies_len) | 679 | size_t extra_ies_len, u8 oper_class, |
680 | struct cfg80211_chan_def *chandef) | ||
511 | { | 681 | { |
512 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
513 | struct ieee80211_local *local = sdata->local; | 682 | struct ieee80211_local *local = sdata->local; |
514 | struct sk_buff *skb = NULL; | 683 | struct sk_buff *skb; |
515 | bool send_direct; | ||
516 | struct sta_info *sta; | ||
517 | int ret; | 684 | int ret; |
518 | 685 | ||
519 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 686 | skb = netdev_alloc_skb(sdata->dev, |
520 | max(sizeof(struct ieee80211_mgmt), | 687 | local->hw.extra_tx_headroom + |
521 | sizeof(struct ieee80211_tdls_data)) + | 688 | max(sizeof(struct ieee80211_mgmt), |
522 | 50 + /* supported rates */ | 689 | sizeof(struct ieee80211_tdls_data)) + |
523 | 7 + /* ext capab */ | 690 | 50 + /* supported rates */ |
524 | 26 + /* max(WMM-info, WMM-param) */ | 691 | 7 + /* ext capab */ |
525 | 2 + max(sizeof(struct ieee80211_ht_cap), | 692 | 26 + /* max(WMM-info, WMM-param) */ |
526 | sizeof(struct ieee80211_ht_operation)) + | 693 | 2 + max(sizeof(struct ieee80211_ht_cap), |
527 | extra_ies_len + | 694 | sizeof(struct ieee80211_ht_operation)) + |
528 | sizeof(struct ieee80211_tdls_lnkie)); | 695 | 50 + /* supported channels */ |
696 | 3 + /* 40/20 BSS coex */ | ||
697 | extra_ies_len + | ||
698 | sizeof(struct ieee80211_tdls_lnkie)); | ||
529 | if (!skb) | 699 | if (!skb) |
530 | return -ENOMEM; | 700 | return NULL; |
531 | 701 | ||
532 | skb_reserve(skb, local->hw.extra_tx_headroom); | 702 | skb_reserve(skb, local->hw.extra_tx_headroom); |
533 | 703 | ||
@@ -537,16 +707,18 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
537 | case WLAN_TDLS_SETUP_CONFIRM: | 707 | case WLAN_TDLS_SETUP_CONFIRM: |
538 | case WLAN_TDLS_TEARDOWN: | 708 | case WLAN_TDLS_TEARDOWN: |
539 | case WLAN_TDLS_DISCOVERY_REQUEST: | 709 | case WLAN_TDLS_DISCOVERY_REQUEST: |
540 | ret = ieee80211_prep_tdls_encap_data(wiphy, dev, peer, | 710 | case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: |
711 | case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: | ||
712 | ret = ieee80211_prep_tdls_encap_data(local->hw.wiphy, | ||
713 | sdata->dev, peer, | ||
541 | action_code, dialog_token, | 714 | action_code, dialog_token, |
542 | status_code, skb); | 715 | status_code, skb); |
543 | send_direct = false; | ||
544 | break; | 716 | break; |
545 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | 717 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: |
546 | ret = ieee80211_prep_tdls_direct(wiphy, dev, peer, action_code, | 718 | ret = ieee80211_prep_tdls_direct(local->hw.wiphy, sdata->dev, |
719 | peer, action_code, | ||
547 | dialog_token, status_code, | 720 | dialog_token, status_code, |
548 | skb); | 721 | skb); |
549 | send_direct = true; | ||
550 | break; | 722 | break; |
551 | default: | 723 | default: |
552 | ret = -ENOTSUPP; | 724 | ret = -ENOTSUPP; |
@@ -556,6 +728,30 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
556 | if (ret < 0) | 728 | if (ret < 0) |
557 | goto fail; | 729 | goto fail; |
558 | 730 | ||
731 | ieee80211_tdls_add_ies(sdata, skb, peer, action_code, status_code, | ||
732 | initiator, extra_ies, extra_ies_len, oper_class, | ||
733 | chandef); | ||
734 | return skb; | ||
735 | |||
736 | fail: | ||
737 | dev_kfree_skb(skb); | ||
738 | return NULL; | ||
739 | } | ||
740 | |||
741 | static int | ||
742 | ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | ||
743 | const u8 *peer, u8 action_code, u8 dialog_token, | ||
744 | u16 status_code, u32 peer_capability, | ||
745 | bool initiator, const u8 *extra_ies, | ||
746 | size_t extra_ies_len, u8 oper_class, | ||
747 | struct cfg80211_chan_def *chandef) | ||
748 | { | ||
749 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
750 | struct sk_buff *skb = NULL; | ||
751 | struct sta_info *sta; | ||
752 | u32 flags = 0; | ||
753 | int ret = 0; | ||
754 | |||
559 | rcu_read_lock(); | 755 | rcu_read_lock(); |
560 | sta = sta_info_get(sdata, peer); | 756 | sta = sta_info_get(sdata, peer); |
561 | 757 | ||
@@ -586,6 +782,8 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
586 | initiator = false; | 782 | initiator = false; |
587 | break; | 783 | break; |
588 | case WLAN_TDLS_TEARDOWN: | 784 | case WLAN_TDLS_TEARDOWN: |
785 | case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: | ||
786 | case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: | ||
589 | /* any value is ok */ | 787 | /* any value is ok */ |
590 | break; | 788 | break; |
591 | default: | 789 | default: |
@@ -600,9 +798,17 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
600 | if (ret < 0) | 798 | if (ret < 0) |
601 | goto fail; | 799 | goto fail; |
602 | 800 | ||
603 | ieee80211_tdls_add_ies(sdata, skb, peer, action_code, status_code, | 801 | skb = ieee80211_tdls_build_mgmt_packet_data(sdata, peer, action_code, |
604 | initiator, extra_ies, extra_ies_len); | 802 | dialog_token, status_code, |
605 | if (send_direct) { | 803 | initiator, extra_ies, |
804 | extra_ies_len, oper_class, | ||
805 | chandef); | ||
806 | if (!skb) { | ||
807 | ret = -EINVAL; | ||
808 | goto fail; | ||
809 | } | ||
810 | |||
811 | if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) { | ||
606 | ieee80211_tx_skb(sdata, skb); | 812 | ieee80211_tx_skb(sdata, skb); |
607 | return 0; | 813 | return 0; |
608 | } | 814 | } |
@@ -623,9 +829,44 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
623 | break; | 829 | break; |
624 | } | 830 | } |
625 | 831 | ||
832 | /* | ||
833 | * Set the WLAN_TDLS_TEARDOWN flag to indicate a teardown in progress. | ||
834 | * Later, if no ACK is returned from peer, we will re-send the teardown | ||
835 | * packet through the AP. | ||
836 | */ | ||
837 | if ((action_code == WLAN_TDLS_TEARDOWN) && | ||
838 | (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) { | ||
839 | struct sta_info *sta = NULL; | ||
840 | bool try_resend; /* Should we keep skb for possible resend */ | ||
841 | |||
842 | /* If not sending directly to peer - no point in keeping skb */ | ||
843 | rcu_read_lock(); | ||
844 | sta = sta_info_get(sdata, peer); | ||
845 | try_resend = sta && test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); | ||
846 | rcu_read_unlock(); | ||
847 | |||
848 | spin_lock_bh(&sdata->u.mgd.teardown_lock); | ||
849 | if (try_resend && !sdata->u.mgd.teardown_skb) { | ||
850 | /* Mark it as requiring TX status callback */ | ||
851 | flags |= IEEE80211_TX_CTL_REQ_TX_STATUS | | ||
852 | IEEE80211_TX_INTFL_MLME_CONN_TX; | ||
853 | |||
854 | /* | ||
855 | * skb is copied since mac80211 will later set | ||
856 | * properties that might not be the same as the AP, | ||
857 | * such as encryption, QoS, addresses, etc. | ||
858 | * | ||
859 | * No problem if skb_copy() fails, so no need to check. | ||
860 | */ | ||
861 | sdata->u.mgd.teardown_skb = skb_copy(skb, GFP_ATOMIC); | ||
862 | sdata->u.mgd.orig_teardown_skb = skb; | ||
863 | } | ||
864 | spin_unlock_bh(&sdata->u.mgd.teardown_lock); | ||
865 | } | ||
866 | |||
626 | /* disable bottom halves when entering the Tx path */ | 867 | /* disable bottom halves when entering the Tx path */ |
627 | local_bh_disable(); | 868 | local_bh_disable(); |
628 | ret = ieee80211_subif_start_xmit(skb, dev); | 869 | __ieee80211_subif_start_xmit(skb, dev, flags); |
629 | local_bh_enable(); | 870 | local_bh_enable(); |
630 | 871 | ||
631 | return ret; | 872 | return ret; |
@@ -676,7 +917,8 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, | |||
676 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, | 917 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, |
677 | dialog_token, status_code, | 918 | dialog_token, status_code, |
678 | peer_capability, initiator, | 919 | peer_capability, initiator, |
679 | extra_ies, extra_ies_len); | 920 | extra_ies, extra_ies_len, 0, |
921 | NULL); | ||
680 | if (ret < 0) | 922 | if (ret < 0) |
681 | goto exit; | 923 | goto exit; |
682 | 924 | ||
@@ -715,7 +957,8 @@ ieee80211_tdls_mgmt_teardown(struct wiphy *wiphy, struct net_device *dev, | |||
715 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, | 957 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, |
716 | dialog_token, status_code, | 958 | dialog_token, status_code, |
717 | peer_capability, initiator, | 959 | peer_capability, initiator, |
718 | extra_ies, extra_ies_len); | 960 | extra_ies, extra_ies_len, 0, |
961 | NULL); | ||
719 | if (ret < 0) | 962 | if (ret < 0) |
720 | sdata_err(sdata, "Failed sending TDLS teardown packet %d\n", | 963 | sdata_err(sdata, "Failed sending TDLS teardown packet %d\n", |
721 | ret); | 964 | ret); |
@@ -785,7 +1028,7 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | |||
785 | status_code, | 1028 | status_code, |
786 | peer_capability, | 1029 | peer_capability, |
787 | initiator, extra_ies, | 1030 | initiator, extra_ies, |
788 | extra_ies_len); | 1031 | extra_ies_len, 0, NULL); |
789 | break; | 1032 | break; |
790 | default: | 1033 | default: |
791 | ret = -EOPNOTSUPP; | 1034 | ret = -EOPNOTSUPP; |
@@ -888,3 +1131,480 @@ void ieee80211_tdls_oper_request(struct ieee80211_vif *vif, const u8 *peer, | |||
888 | cfg80211_tdls_oper_request(sdata->dev, peer, oper, reason_code, gfp); | 1131 | cfg80211_tdls_oper_request(sdata->dev, peer, oper, reason_code, gfp); |
889 | } | 1132 | } |
890 | EXPORT_SYMBOL(ieee80211_tdls_oper_request); | 1133 | EXPORT_SYMBOL(ieee80211_tdls_oper_request); |
1134 | |||
1135 | static void | ||
1136 | iee80211_tdls_add_ch_switch_timing(u8 *buf, u16 switch_time, u16 switch_timeout) | ||
1137 | { | ||
1138 | struct ieee80211_ch_switch_timing *ch_sw; | ||
1139 | |||
1140 | *buf++ = WLAN_EID_CHAN_SWITCH_TIMING; | ||
1141 | *buf++ = sizeof(struct ieee80211_ch_switch_timing); | ||
1142 | |||
1143 | ch_sw = (void *)buf; | ||
1144 | ch_sw->switch_time = cpu_to_le16(switch_time); | ||
1145 | ch_sw->switch_timeout = cpu_to_le16(switch_timeout); | ||
1146 | } | ||
1147 | |||
1148 | /* find switch timing IE in SKB ready for Tx */ | ||
1149 | static const u8 *ieee80211_tdls_find_sw_timing_ie(struct sk_buff *skb) | ||
1150 | { | ||
1151 | struct ieee80211_tdls_data *tf; | ||
1152 | const u8 *ie_start; | ||
1153 | |||
1154 | /* | ||
1155 | * Get the offset for the new location of the switch timing IE. | ||
1156 | * The SKB network header will now point to the "payload_type" | ||
1157 | * element of the TDLS data frame struct. | ||
1158 | */ | ||
1159 | tf = container_of(skb->data + skb_network_offset(skb), | ||
1160 | struct ieee80211_tdls_data, payload_type); | ||
1161 | ie_start = tf->u.chan_switch_req.variable; | ||
1162 | return cfg80211_find_ie(WLAN_EID_CHAN_SWITCH_TIMING, ie_start, | ||
1163 | skb->len - (ie_start - skb->data)); | ||
1164 | } | ||
1165 | |||
1166 | static struct sk_buff * | ||
1167 | ieee80211_tdls_ch_sw_tmpl_get(struct sta_info *sta, u8 oper_class, | ||
1168 | struct cfg80211_chan_def *chandef, | ||
1169 | u32 *ch_sw_tm_ie_offset) | ||
1170 | { | ||
1171 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
1172 | u8 extra_ies[2 + sizeof(struct ieee80211_sec_chan_offs_ie) + | ||
1173 | 2 + sizeof(struct ieee80211_ch_switch_timing)]; | ||
1174 | int extra_ies_len = 2 + sizeof(struct ieee80211_ch_switch_timing); | ||
1175 | u8 *pos = extra_ies; | ||
1176 | struct sk_buff *skb; | ||
1177 | |||
1178 | /* | ||
1179 | * if chandef points to a wide channel add a Secondary-Channel | ||
1180 | * Offset information element | ||
1181 | */ | ||
1182 | if (chandef->width == NL80211_CHAN_WIDTH_40) { | ||
1183 | struct ieee80211_sec_chan_offs_ie *sec_chan_ie; | ||
1184 | bool ht40plus; | ||
1185 | |||
1186 | *pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; | ||
1187 | *pos++ = sizeof(*sec_chan_ie); | ||
1188 | sec_chan_ie = (void *)pos; | ||
1189 | |||
1190 | ht40plus = cfg80211_get_chandef_type(chandef) == | ||
1191 | NL80211_CHAN_HT40PLUS; | ||
1192 | sec_chan_ie->sec_chan_offs = ht40plus ? | ||
1193 | IEEE80211_HT_PARAM_CHA_SEC_ABOVE : | ||
1194 | IEEE80211_HT_PARAM_CHA_SEC_BELOW; | ||
1195 | pos += sizeof(*sec_chan_ie); | ||
1196 | |||
1197 | extra_ies_len += 2 + sizeof(struct ieee80211_sec_chan_offs_ie); | ||
1198 | } | ||
1199 | |||
1200 | /* just set the values to 0, this is a template */ | ||
1201 | iee80211_tdls_add_ch_switch_timing(pos, 0, 0); | ||
1202 | |||
1203 | skb = ieee80211_tdls_build_mgmt_packet_data(sdata, sta->sta.addr, | ||
1204 | WLAN_TDLS_CHANNEL_SWITCH_REQUEST, | ||
1205 | 0, 0, !sta->sta.tdls_initiator, | ||
1206 | extra_ies, extra_ies_len, | ||
1207 | oper_class, chandef); | ||
1208 | if (!skb) | ||
1209 | return NULL; | ||
1210 | |||
1211 | skb = ieee80211_build_data_template(sdata, skb, 0); | ||
1212 | if (IS_ERR(skb)) { | ||
1213 | tdls_dbg(sdata, "Failed building TDLS channel switch frame\n"); | ||
1214 | return NULL; | ||
1215 | } | ||
1216 | |||
1217 | if (ch_sw_tm_ie_offset) { | ||
1218 | const u8 *tm_ie = ieee80211_tdls_find_sw_timing_ie(skb); | ||
1219 | |||
1220 | if (!tm_ie) { | ||
1221 | tdls_dbg(sdata, "No switch timing IE in TDLS switch\n"); | ||
1222 | dev_kfree_skb_any(skb); | ||
1223 | return NULL; | ||
1224 | } | ||
1225 | |||
1226 | *ch_sw_tm_ie_offset = tm_ie - skb->data; | ||
1227 | } | ||
1228 | |||
1229 | tdls_dbg(sdata, | ||
1230 | "TDLS channel switch request template for %pM ch %d width %d\n", | ||
1231 | sta->sta.addr, chandef->chan->center_freq, chandef->width); | ||
1232 | return skb; | ||
1233 | } | ||
1234 | |||
1235 | int | ||
1236 | ieee80211_tdls_channel_switch(struct wiphy *wiphy, struct net_device *dev, | ||
1237 | const u8 *addr, u8 oper_class, | ||
1238 | struct cfg80211_chan_def *chandef) | ||
1239 | { | ||
1240 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1241 | struct ieee80211_local *local = sdata->local; | ||
1242 | struct sta_info *sta; | ||
1243 | struct sk_buff *skb = NULL; | ||
1244 | u32 ch_sw_tm_ie; | ||
1245 | int ret; | ||
1246 | |||
1247 | mutex_lock(&local->sta_mtx); | ||
1248 | sta = sta_info_get(sdata, addr); | ||
1249 | if (!sta) { | ||
1250 | tdls_dbg(sdata, | ||
1251 | "Invalid TDLS peer %pM for channel switch request\n", | ||
1252 | addr); | ||
1253 | ret = -ENOENT; | ||
1254 | goto out; | ||
1255 | } | ||
1256 | |||
1257 | if (!test_sta_flag(sta, WLAN_STA_TDLS_CHAN_SWITCH)) { | ||
1258 | tdls_dbg(sdata, "TDLS channel switch unsupported by %pM\n", | ||
1259 | addr); | ||
1260 | ret = -ENOTSUPP; | ||
1261 | goto out; | ||
1262 | } | ||
1263 | |||
1264 | skb = ieee80211_tdls_ch_sw_tmpl_get(sta, oper_class, chandef, | ||
1265 | &ch_sw_tm_ie); | ||
1266 | if (!skb) { | ||
1267 | ret = -ENOENT; | ||
1268 | goto out; | ||
1269 | } | ||
1270 | |||
1271 | ret = drv_tdls_channel_switch(local, sdata, &sta->sta, oper_class, | ||
1272 | chandef, skb, ch_sw_tm_ie); | ||
1273 | if (!ret) | ||
1274 | set_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL); | ||
1275 | |||
1276 | out: | ||
1277 | mutex_unlock(&local->sta_mtx); | ||
1278 | dev_kfree_skb_any(skb); | ||
1279 | return ret; | ||
1280 | } | ||
1281 | |||
1282 | void | ||
1283 | ieee80211_tdls_cancel_channel_switch(struct wiphy *wiphy, | ||
1284 | struct net_device *dev, | ||
1285 | const u8 *addr) | ||
1286 | { | ||
1287 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1288 | struct ieee80211_local *local = sdata->local; | ||
1289 | struct sta_info *sta; | ||
1290 | |||
1291 | mutex_lock(&local->sta_mtx); | ||
1292 | sta = sta_info_get(sdata, addr); | ||
1293 | if (!sta) { | ||
1294 | tdls_dbg(sdata, | ||
1295 | "Invalid TDLS peer %pM for channel switch cancel\n", | ||
1296 | addr); | ||
1297 | goto out; | ||
1298 | } | ||
1299 | |||
1300 | if (!test_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL)) { | ||
1301 | tdls_dbg(sdata, "TDLS channel switch not initiated by %pM\n", | ||
1302 | addr); | ||
1303 | goto out; | ||
1304 | } | ||
1305 | |||
1306 | drv_tdls_cancel_channel_switch(local, sdata, &sta->sta); | ||
1307 | clear_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL); | ||
1308 | |||
1309 | out: | ||
1310 | mutex_unlock(&local->sta_mtx); | ||
1311 | } | ||
1312 | |||
1313 | static struct sk_buff * | ||
1314 | ieee80211_tdls_ch_sw_resp_tmpl_get(struct sta_info *sta, | ||
1315 | u32 *ch_sw_tm_ie_offset) | ||
1316 | { | ||
1317 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
1318 | struct sk_buff *skb; | ||
1319 | u8 extra_ies[2 + sizeof(struct ieee80211_ch_switch_timing)]; | ||
1320 | |||
1321 | /* initial timing are always zero in the template */ | ||
1322 | iee80211_tdls_add_ch_switch_timing(extra_ies, 0, 0); | ||
1323 | |||
1324 | skb = ieee80211_tdls_build_mgmt_packet_data(sdata, sta->sta.addr, | ||
1325 | WLAN_TDLS_CHANNEL_SWITCH_RESPONSE, | ||
1326 | 0, 0, !sta->sta.tdls_initiator, | ||
1327 | extra_ies, sizeof(extra_ies), 0, NULL); | ||
1328 | if (!skb) | ||
1329 | return NULL; | ||
1330 | |||
1331 | skb = ieee80211_build_data_template(sdata, skb, 0); | ||
1332 | if (IS_ERR(skb)) { | ||
1333 | tdls_dbg(sdata, | ||
1334 | "Failed building TDLS channel switch resp frame\n"); | ||
1335 | return NULL; | ||
1336 | } | ||
1337 | |||
1338 | if (ch_sw_tm_ie_offset) { | ||
1339 | const u8 *tm_ie = ieee80211_tdls_find_sw_timing_ie(skb); | ||
1340 | |||
1341 | if (!tm_ie) { | ||
1342 | tdls_dbg(sdata, | ||
1343 | "No switch timing IE in TDLS switch resp\n"); | ||
1344 | dev_kfree_skb_any(skb); | ||
1345 | return NULL; | ||
1346 | } | ||
1347 | |||
1348 | *ch_sw_tm_ie_offset = tm_ie - skb->data; | ||
1349 | } | ||
1350 | |||
1351 | tdls_dbg(sdata, "TDLS get channel switch response template for %pM\n", | ||
1352 | sta->sta.addr); | ||
1353 | return skb; | ||
1354 | } | ||
1355 | |||
1356 | static int | ||
1357 | ieee80211_process_tdls_channel_switch_resp(struct ieee80211_sub_if_data *sdata, | ||
1358 | struct sk_buff *skb) | ||
1359 | { | ||
1360 | struct ieee80211_local *local = sdata->local; | ||
1361 | struct ieee802_11_elems elems; | ||
1362 | struct sta_info *sta; | ||
1363 | struct ieee80211_tdls_data *tf = (void *)skb->data; | ||
1364 | bool local_initiator; | ||
1365 | struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); | ||
1366 | int baselen = offsetof(typeof(*tf), u.chan_switch_resp.variable); | ||
1367 | struct ieee80211_tdls_ch_sw_params params = {}; | ||
1368 | int ret; | ||
1369 | |||
1370 | params.action_code = WLAN_TDLS_CHANNEL_SWITCH_RESPONSE; | ||
1371 | params.timestamp = rx_status->device_timestamp; | ||
1372 | |||
1373 | if (skb->len < baselen) { | ||
1374 | tdls_dbg(sdata, "TDLS channel switch resp too short: %d\n", | ||
1375 | skb->len); | ||
1376 | return -EINVAL; | ||
1377 | } | ||
1378 | |||
1379 | mutex_lock(&local->sta_mtx); | ||
1380 | sta = sta_info_get(sdata, tf->sa); | ||
1381 | if (!sta || !test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) { | ||
1382 | tdls_dbg(sdata, "TDLS chan switch from non-peer sta %pM\n", | ||
1383 | tf->sa); | ||
1384 | ret = -EINVAL; | ||
1385 | goto out; | ||
1386 | } | ||
1387 | |||
1388 | params.sta = &sta->sta; | ||
1389 | params.status = le16_to_cpu(tf->u.chan_switch_resp.status_code); | ||
1390 | if (params.status != 0) { | ||
1391 | ret = 0; | ||
1392 | goto call_drv; | ||
1393 | } | ||
1394 | |||
1395 | ieee802_11_parse_elems(tf->u.chan_switch_resp.variable, | ||
1396 | skb->len - baselen, false, &elems); | ||
1397 | if (elems.parse_error) { | ||
1398 | tdls_dbg(sdata, "Invalid IEs in TDLS channel switch resp\n"); | ||
1399 | ret = -EINVAL; | ||
1400 | goto out; | ||
1401 | } | ||
1402 | |||
1403 | if (!elems.ch_sw_timing || !elems.lnk_id) { | ||
1404 | tdls_dbg(sdata, "TDLS channel switch resp - missing IEs\n"); | ||
1405 | ret = -EINVAL; | ||
1406 | goto out; | ||
1407 | } | ||
1408 | |||
1409 | /* validate the initiator is set correctly */ | ||
1410 | local_initiator = | ||
1411 | !memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); | ||
1412 | if (local_initiator == sta->sta.tdls_initiator) { | ||
1413 | tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n"); | ||
1414 | ret = -EINVAL; | ||
1415 | goto out; | ||
1416 | } | ||
1417 | |||
1418 | params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time); | ||
1419 | params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout); | ||
1420 | |||
1421 | params.tmpl_skb = | ||
1422 | ieee80211_tdls_ch_sw_resp_tmpl_get(sta, ¶ms.ch_sw_tm_ie); | ||
1423 | if (!params.tmpl_skb) { | ||
1424 | ret = -ENOENT; | ||
1425 | goto out; | ||
1426 | } | ||
1427 | |||
1428 | call_drv: | ||
1429 | drv_tdls_recv_channel_switch(sdata->local, sdata, ¶ms); | ||
1430 | |||
1431 | tdls_dbg(sdata, | ||
1432 | "TDLS channel switch response received from %pM status %d\n", | ||
1433 | tf->sa, params.status); | ||
1434 | |||
1435 | out: | ||
1436 | mutex_unlock(&local->sta_mtx); | ||
1437 | dev_kfree_skb_any(params.tmpl_skb); | ||
1438 | return ret; | ||
1439 | } | ||
1440 | |||
1441 | static int | ||
1442 | ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata, | ||
1443 | struct sk_buff *skb) | ||
1444 | { | ||
1445 | struct ieee80211_local *local = sdata->local; | ||
1446 | struct ieee802_11_elems elems; | ||
1447 | struct cfg80211_chan_def chandef; | ||
1448 | struct ieee80211_channel *chan; | ||
1449 | enum nl80211_channel_type chan_type; | ||
1450 | int freq; | ||
1451 | u8 target_channel, oper_class; | ||
1452 | bool local_initiator; | ||
1453 | struct sta_info *sta; | ||
1454 | enum ieee80211_band band; | ||
1455 | struct ieee80211_tdls_data *tf = (void *)skb->data; | ||
1456 | struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); | ||
1457 | int baselen = offsetof(typeof(*tf), u.chan_switch_req.variable); | ||
1458 | struct ieee80211_tdls_ch_sw_params params = {}; | ||
1459 | int ret = 0; | ||
1460 | |||
1461 | params.action_code = WLAN_TDLS_CHANNEL_SWITCH_REQUEST; | ||
1462 | params.timestamp = rx_status->device_timestamp; | ||
1463 | |||
1464 | if (skb->len < baselen) { | ||
1465 | tdls_dbg(sdata, "TDLS channel switch req too short: %d\n", | ||
1466 | skb->len); | ||
1467 | return -EINVAL; | ||
1468 | } | ||
1469 | |||
1470 | target_channel = tf->u.chan_switch_req.target_channel; | ||
1471 | oper_class = tf->u.chan_switch_req.oper_class; | ||
1472 | |||
1473 | /* | ||
1474 | * We can't easily infer the channel band. The operating class is | ||
1475 | * ambiguous - there are multiple tables (US/Europe/JP/Global). The | ||
1476 | * solution here is to treat channels with number >14 as 5GHz ones, | ||
1477 | * and specifically check for the (oper_class, channel) combinations | ||
1478 | * where this doesn't hold. These are thankfully unique according to | ||
1479 | * IEEE802.11-2012. | ||
1480 | * We consider only the 2GHz and 5GHz bands and 20MHz+ channels as | ||
1481 | * valid here. | ||
1482 | */ | ||
1483 | if ((oper_class == 112 || oper_class == 2 || oper_class == 3 || | ||
1484 | oper_class == 4 || oper_class == 5 || oper_class == 6) && | ||
1485 | target_channel < 14) | ||
1486 | band = IEEE80211_BAND_5GHZ; | ||
1487 | else | ||
1488 | band = target_channel < 14 ? IEEE80211_BAND_2GHZ : | ||
1489 | IEEE80211_BAND_5GHZ; | ||
1490 | |||
1491 | freq = ieee80211_channel_to_frequency(target_channel, band); | ||
1492 | if (freq == 0) { | ||
1493 | tdls_dbg(sdata, "Invalid channel in TDLS chan switch: %d\n", | ||
1494 | target_channel); | ||
1495 | return -EINVAL; | ||
1496 | } | ||
1497 | |||
1498 | chan = ieee80211_get_channel(sdata->local->hw.wiphy, freq); | ||
1499 | if (!chan) { | ||
1500 | tdls_dbg(sdata, | ||
1501 | "Unsupported channel for TDLS chan switch: %d\n", | ||
1502 | target_channel); | ||
1503 | return -EINVAL; | ||
1504 | } | ||
1505 | |||
1506 | ieee802_11_parse_elems(tf->u.chan_switch_req.variable, | ||
1507 | skb->len - baselen, false, &elems); | ||
1508 | if (elems.parse_error) { | ||
1509 | tdls_dbg(sdata, "Invalid IEs in TDLS channel switch req\n"); | ||
1510 | return -EINVAL; | ||
1511 | } | ||
1512 | |||
1513 | if (!elems.ch_sw_timing || !elems.lnk_id) { | ||
1514 | tdls_dbg(sdata, "TDLS channel switch req - missing IEs\n"); | ||
1515 | return -EINVAL; | ||
1516 | } | ||
1517 | |||
1518 | mutex_lock(&local->sta_mtx); | ||
1519 | sta = sta_info_get(sdata, tf->sa); | ||
1520 | if (!sta || !test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) { | ||
1521 | tdls_dbg(sdata, "TDLS chan switch from non-peer sta %pM\n", | ||
1522 | tf->sa); | ||
1523 | ret = -EINVAL; | ||
1524 | goto out; | ||
1525 | } | ||
1526 | |||
1527 | params.sta = &sta->sta; | ||
1528 | |||
1529 | /* validate the initiator is set correctly */ | ||
1530 | local_initiator = | ||
1531 | !memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); | ||
1532 | if (local_initiator == sta->sta.tdls_initiator) { | ||
1533 | tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n"); | ||
1534 | ret = -EINVAL; | ||
1535 | goto out; | ||
1536 | } | ||
1537 | |||
1538 | if (!sta->sta.ht_cap.ht_supported) { | ||
1539 | chan_type = NL80211_CHAN_NO_HT; | ||
1540 | } else if (!elems.sec_chan_offs) { | ||
1541 | chan_type = NL80211_CHAN_HT20; | ||
1542 | } else { | ||
1543 | switch (elems.sec_chan_offs->sec_chan_offs) { | ||
1544 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
1545 | chan_type = NL80211_CHAN_HT40PLUS; | ||
1546 | break; | ||
1547 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
1548 | chan_type = NL80211_CHAN_HT40MINUS; | ||
1549 | break; | ||
1550 | default: | ||
1551 | chan_type = NL80211_CHAN_HT20; | ||
1552 | break; | ||
1553 | } | ||
1554 | } | ||
1555 | |||
1556 | cfg80211_chandef_create(&chandef, chan, chan_type); | ||
1557 | params.chandef = &chandef; | ||
1558 | |||
1559 | params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time); | ||
1560 | params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout); | ||
1561 | |||
1562 | params.tmpl_skb = | ||
1563 | ieee80211_tdls_ch_sw_resp_tmpl_get(sta, | ||
1564 | ¶ms.ch_sw_tm_ie); | ||
1565 | if (!params.tmpl_skb) { | ||
1566 | ret = -ENOENT; | ||
1567 | goto out; | ||
1568 | } | ||
1569 | |||
1570 | drv_tdls_recv_channel_switch(sdata->local, sdata, ¶ms); | ||
1571 | |||
1572 | tdls_dbg(sdata, | ||
1573 | "TDLS ch switch request received from %pM ch %d width %d\n", | ||
1574 | tf->sa, params.chandef->chan->center_freq, | ||
1575 | params.chandef->width); | ||
1576 | out: | ||
1577 | mutex_unlock(&local->sta_mtx); | ||
1578 | dev_kfree_skb_any(params.tmpl_skb); | ||
1579 | return ret; | ||
1580 | } | ||
1581 | |||
1582 | void ieee80211_process_tdls_channel_switch(struct ieee80211_sub_if_data *sdata, | ||
1583 | struct sk_buff *skb) | ||
1584 | { | ||
1585 | struct ieee80211_tdls_data *tf = (void *)skb->data; | ||
1586 | struct wiphy *wiphy = sdata->local->hw.wiphy; | ||
1587 | |||
1588 | /* make sure the driver supports it */ | ||
1589 | if (!(wiphy->features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH)) | ||
1590 | return; | ||
1591 | |||
1592 | /* we want to access the entire packet */ | ||
1593 | if (skb_linearize(skb)) | ||
1594 | return; | ||
1595 | /* | ||
1596 | * The packet/size was already validated by mac80211 Rx path, only look | ||
1597 | * at the action type. | ||
1598 | */ | ||
1599 | switch (tf->action_code) { | ||
1600 | case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: | ||
1601 | ieee80211_process_tdls_channel_switch_req(sdata, skb); | ||
1602 | break; | ||
1603 | case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: | ||
1604 | ieee80211_process_tdls_channel_switch_resp(sdata, skb); | ||
1605 | break; | ||
1606 | default: | ||
1607 | WARN_ON_ONCE(1); | ||
1608 | return; | ||
1609 | } | ||
1610 | } | ||
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 809a4983eb4a..85ccfbe863db 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #define STA_ENTRY __array(char, sta_addr, ETH_ALEN) | 17 | #define STA_ENTRY __array(char, sta_addr, ETH_ALEN) |
18 | #define STA_ASSIGN (sta ? memcpy(__entry->sta_addr, sta->addr, ETH_ALEN) : memset(__entry->sta_addr, 0, ETH_ALEN)) | 18 | #define STA_ASSIGN (sta ? memcpy(__entry->sta_addr, sta->addr, ETH_ALEN) : memset(__entry->sta_addr, 0, ETH_ALEN)) |
19 | #define STA_NAMED_ASSIGN(s) memcpy(__entry->sta_addr, (s)->addr, ETH_ALEN) | ||
19 | #define STA_PR_FMT " sta:%pM" | 20 | #define STA_PR_FMT " sta:%pM" |
20 | #define STA_PR_ARG __entry->sta_addr | 21 | #define STA_PR_ARG __entry->sta_addr |
21 | 22 | ||
@@ -595,14 +596,33 @@ DEFINE_EVENT(local_sdata_evt, drv_sched_scan_stop, | |||
595 | TP_ARGS(local, sdata) | 596 | TP_ARGS(local, sdata) |
596 | ); | 597 | ); |
597 | 598 | ||
598 | DEFINE_EVENT(local_only_evt, drv_sw_scan_start, | 599 | TRACE_EVENT(drv_sw_scan_start, |
599 | TP_PROTO(struct ieee80211_local *local), | 600 | TP_PROTO(struct ieee80211_local *local, |
600 | TP_ARGS(local) | 601 | struct ieee80211_sub_if_data *sdata, |
602 | const u8 *mac_addr), | ||
603 | |||
604 | TP_ARGS(local, sdata, mac_addr), | ||
605 | |||
606 | TP_STRUCT__entry( | ||
607 | LOCAL_ENTRY | ||
608 | VIF_ENTRY | ||
609 | __array(char, mac_addr, ETH_ALEN) | ||
610 | ), | ||
611 | |||
612 | TP_fast_assign( | ||
613 | LOCAL_ASSIGN; | ||
614 | VIF_ASSIGN; | ||
615 | memcpy(__entry->mac_addr, mac_addr, ETH_ALEN); | ||
616 | ), | ||
617 | |||
618 | TP_printk(LOCAL_PR_FMT ", " VIF_PR_FMT ", addr:%pM", | ||
619 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->mac_addr) | ||
601 | ); | 620 | ); |
602 | 621 | ||
603 | DEFINE_EVENT(local_only_evt, drv_sw_scan_complete, | 622 | DEFINE_EVENT(local_sdata_evt, drv_sw_scan_complete, |
604 | TP_PROTO(struct ieee80211_local *local), | 623 | TP_PROTO(struct ieee80211_local *local, |
605 | TP_ARGS(local) | 624 | struct ieee80211_sub_if_data *sdata), |
625 | TP_ARGS(local, sdata) | ||
606 | ); | 626 | ); |
607 | 627 | ||
608 | TRACE_EVENT(drv_get_stats, | 628 | TRACE_EVENT(drv_get_stats, |
@@ -826,6 +846,13 @@ DEFINE_EVENT(sta_event, drv_sta_pre_rcu_remove, | |||
826 | TP_ARGS(local, sdata, sta) | 846 | TP_ARGS(local, sdata, sta) |
827 | ); | 847 | ); |
828 | 848 | ||
849 | DEFINE_EVENT(sta_event, drv_sta_rate_tbl_update, | ||
850 | TP_PROTO(struct ieee80211_local *local, | ||
851 | struct ieee80211_sub_if_data *sdata, | ||
852 | struct ieee80211_sta *sta), | ||
853 | TP_ARGS(local, sdata, sta) | ||
854 | ); | ||
855 | |||
829 | TRACE_EVENT(drv_conf_tx, | 856 | TRACE_EVENT(drv_conf_tx, |
830 | TP_PROTO(struct ieee80211_local *local, | 857 | TP_PROTO(struct ieee80211_local *local, |
831 | struct ieee80211_sub_if_data *sdata, | 858 | struct ieee80211_sub_if_data *sdata, |
@@ -2140,6 +2167,7 @@ TRACE_EVENT(drv_pre_channel_switch, | |||
2140 | VIF_ENTRY | 2167 | VIF_ENTRY |
2141 | CHANDEF_ENTRY | 2168 | CHANDEF_ENTRY |
2142 | __field(u64, timestamp) | 2169 | __field(u64, timestamp) |
2170 | __field(u32, device_timestamp) | ||
2143 | __field(bool, block_tx) | 2171 | __field(bool, block_tx) |
2144 | __field(u8, count) | 2172 | __field(u8, count) |
2145 | ), | 2173 | ), |
@@ -2149,6 +2177,7 @@ TRACE_EVENT(drv_pre_channel_switch, | |||
2149 | VIF_ASSIGN; | 2177 | VIF_ASSIGN; |
2150 | CHANDEF_ASSIGN(&ch_switch->chandef) | 2178 | CHANDEF_ASSIGN(&ch_switch->chandef) |
2151 | __entry->timestamp = ch_switch->timestamp; | 2179 | __entry->timestamp = ch_switch->timestamp; |
2180 | __entry->device_timestamp = ch_switch->device_timestamp; | ||
2152 | __entry->block_tx = ch_switch->block_tx; | 2181 | __entry->block_tx = ch_switch->block_tx; |
2153 | __entry->count = ch_switch->count; | 2182 | __entry->count = ch_switch->count; |
2154 | ), | 2183 | ), |
@@ -2194,6 +2223,107 @@ TRACE_EVENT(drv_get_txpower, | |||
2194 | ) | 2223 | ) |
2195 | ); | 2224 | ); |
2196 | 2225 | ||
2226 | TRACE_EVENT(drv_tdls_channel_switch, | ||
2227 | TP_PROTO(struct ieee80211_local *local, | ||
2228 | struct ieee80211_sub_if_data *sdata, | ||
2229 | struct ieee80211_sta *sta, u8 oper_class, | ||
2230 | struct cfg80211_chan_def *chandef), | ||
2231 | |||
2232 | TP_ARGS(local, sdata, sta, oper_class, chandef), | ||
2233 | |||
2234 | TP_STRUCT__entry( | ||
2235 | LOCAL_ENTRY | ||
2236 | VIF_ENTRY | ||
2237 | STA_ENTRY | ||
2238 | __field(u8, oper_class) | ||
2239 | CHANDEF_ENTRY | ||
2240 | ), | ||
2241 | |||
2242 | TP_fast_assign( | ||
2243 | LOCAL_ASSIGN; | ||
2244 | VIF_ASSIGN; | ||
2245 | STA_ASSIGN; | ||
2246 | __entry->oper_class = oper_class; | ||
2247 | CHANDEF_ASSIGN(chandef) | ||
2248 | ), | ||
2249 | |||
2250 | TP_printk( | ||
2251 | LOCAL_PR_FMT VIF_PR_FMT " tdls channel switch to" | ||
2252 | CHANDEF_PR_FMT " oper_class:%d " STA_PR_FMT, | ||
2253 | LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->oper_class, | ||
2254 | STA_PR_ARG | ||
2255 | ) | ||
2256 | ); | ||
2257 | |||
2258 | TRACE_EVENT(drv_tdls_cancel_channel_switch, | ||
2259 | TP_PROTO(struct ieee80211_local *local, | ||
2260 | struct ieee80211_sub_if_data *sdata, | ||
2261 | struct ieee80211_sta *sta), | ||
2262 | |||
2263 | TP_ARGS(local, sdata, sta), | ||
2264 | |||
2265 | TP_STRUCT__entry( | ||
2266 | LOCAL_ENTRY | ||
2267 | VIF_ENTRY | ||
2268 | STA_ENTRY | ||
2269 | ), | ||
2270 | |||
2271 | TP_fast_assign( | ||
2272 | LOCAL_ASSIGN; | ||
2273 | VIF_ASSIGN; | ||
2274 | STA_ASSIGN; | ||
2275 | ), | ||
2276 | |||
2277 | TP_printk( | ||
2278 | LOCAL_PR_FMT VIF_PR_FMT | ||
2279 | " tdls cancel channel switch with " STA_PR_FMT, | ||
2280 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG | ||
2281 | ) | ||
2282 | ); | ||
2283 | |||
2284 | TRACE_EVENT(drv_tdls_recv_channel_switch, | ||
2285 | TP_PROTO(struct ieee80211_local *local, | ||
2286 | struct ieee80211_sub_if_data *sdata, | ||
2287 | struct ieee80211_tdls_ch_sw_params *params), | ||
2288 | |||
2289 | TP_ARGS(local, sdata, params), | ||
2290 | |||
2291 | TP_STRUCT__entry( | ||
2292 | LOCAL_ENTRY | ||
2293 | VIF_ENTRY | ||
2294 | __field(u8, action_code) | ||
2295 | STA_ENTRY | ||
2296 | CHANDEF_ENTRY | ||
2297 | __field(u32, status) | ||
2298 | __field(bool, peer_initiator) | ||
2299 | __field(u32, timestamp) | ||
2300 | __field(u16, switch_time) | ||
2301 | __field(u16, switch_timeout) | ||
2302 | ), | ||
2303 | |||
2304 | TP_fast_assign( | ||
2305 | LOCAL_ASSIGN; | ||
2306 | VIF_ASSIGN; | ||
2307 | STA_NAMED_ASSIGN(params->sta); | ||
2308 | CHANDEF_ASSIGN(params->chandef) | ||
2309 | __entry->peer_initiator = params->sta->tdls_initiator; | ||
2310 | __entry->action_code = params->action_code; | ||
2311 | __entry->status = params->status; | ||
2312 | __entry->timestamp = params->timestamp; | ||
2313 | __entry->switch_time = params->switch_time; | ||
2314 | __entry->switch_timeout = params->switch_timeout; | ||
2315 | ), | ||
2316 | |||
2317 | TP_printk( | ||
2318 | LOCAL_PR_FMT VIF_PR_FMT " received tdls channel switch packet" | ||
2319 | " action:%d status:%d time:%d switch time:%d switch" | ||
2320 | " timeout:%d initiator: %d chan:" CHANDEF_PR_FMT STA_PR_FMT, | ||
2321 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->action_code, __entry->status, | ||
2322 | __entry->timestamp, __entry->switch_time, | ||
2323 | __entry->switch_timeout, __entry->peer_initiator, | ||
2324 | CHANDEF_PR_ARG, STA_PR_ARG | ||
2325 | ) | ||
2326 | ); | ||
2197 | 2327 | ||
2198 | #ifdef CONFIG_MAC80211_MESSAGE_TRACING | 2328 | #ifdef CONFIG_MAC80211_MESSAGE_TRACING |
2199 | #undef TRACE_SYSTEM | 2329 | #undef TRACE_SYSTEM |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 3ffd91f295a6..66ddbbeccd20 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1426,8 +1426,7 @@ EXPORT_SYMBOL(ieee80211_tx_prepare_skb); | |||
1426 | * Returns false if the frame couldn't be transmitted but was queued instead. | 1426 | * Returns false if the frame couldn't be transmitted but was queued instead. |
1427 | */ | 1427 | */ |
1428 | static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | 1428 | static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, |
1429 | struct sk_buff *skb, bool txpending, | 1429 | struct sk_buff *skb, bool txpending) |
1430 | enum ieee80211_band band) | ||
1431 | { | 1430 | { |
1432 | struct ieee80211_local *local = sdata->local; | 1431 | struct ieee80211_local *local = sdata->local; |
1433 | struct ieee80211_tx_data tx; | 1432 | struct ieee80211_tx_data tx; |
@@ -1452,8 +1451,6 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | |||
1452 | return true; | 1451 | return true; |
1453 | } | 1452 | } |
1454 | 1453 | ||
1455 | info->band = band; | ||
1456 | |||
1457 | /* set up hw_queue value early */ | 1454 | /* set up hw_queue value early */ |
1458 | if (!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || | 1455 | if (!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || |
1459 | !(local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)) | 1456 | !(local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)) |
@@ -1501,8 +1498,7 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata, | |||
1501 | return 0; | 1498 | return 0; |
1502 | } | 1499 | } |
1503 | 1500 | ||
1504 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | 1501 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
1505 | enum ieee80211_band band) | ||
1506 | { | 1502 | { |
1507 | struct ieee80211_local *local = sdata->local; | 1503 | struct ieee80211_local *local = sdata->local; |
1508 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1504 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
@@ -1537,7 +1533,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | |||
1537 | } | 1533 | } |
1538 | 1534 | ||
1539 | ieee80211_set_qos_hdr(sdata, skb); | 1535 | ieee80211_set_qos_hdr(sdata, skb); |
1540 | ieee80211_tx(sdata, skb, false, band); | 1536 | ieee80211_tx(sdata, skb, false); |
1541 | } | 1537 | } |
1542 | 1538 | ||
1543 | static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb) | 1539 | static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb) |
@@ -1757,7 +1753,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
1757 | sdata->vif.type)) | 1753 | sdata->vif.type)) |
1758 | goto fail_rcu; | 1754 | goto fail_rcu; |
1759 | 1755 | ||
1760 | ieee80211_xmit(sdata, skb, chandef->chan->band); | 1756 | info->band = chandef->chan->band; |
1757 | ieee80211_xmit(sdata, skb); | ||
1761 | rcu_read_unlock(); | 1758 | rcu_read_unlock(); |
1762 | 1759 | ||
1763 | return NETDEV_TX_OK; | 1760 | return NETDEV_TX_OK; |
@@ -1787,23 +1784,26 @@ static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local, | |||
1787 | } | 1784 | } |
1788 | 1785 | ||
1789 | /** | 1786 | /** |
1790 | * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type | 1787 | * ieee80211_build_hdr - build 802.11 header in the given frame |
1791 | * subinterfaces (wlan#, WDS, and VLAN interfaces) | 1788 | * @sdata: virtual interface to build the header for |
1792 | * @skb: packet to be sent | 1789 | * @skb: the skb to build the header in |
1793 | * @dev: incoming interface | 1790 | * @info_flags: skb flags to set |
1791 | * | ||
1792 | * This function takes the skb with 802.3 header and reformats the header to | ||
1793 | * the appropriate IEEE 802.11 header based on which interface the packet is | ||
1794 | * being transmitted on. | ||
1794 | * | 1795 | * |
1795 | * Returns: NETDEV_TX_OK both on success and on failure. On failure skb will | 1796 | * Note that this function also takes care of the TX status request and |
1796 | * be freed. | 1797 | * potential unsharing of the SKB - this needs to be interleaved with the |
1798 | * header building. | ||
1797 | * | 1799 | * |
1798 | * This function takes in an Ethernet header and encapsulates it with suitable | 1800 | * The function requires the read-side RCU lock held |
1799 | * IEEE 802.11 header based on which interface the packet is coming in. The | 1801 | * |
1800 | * encapsulated packet will then be passed to master interface, wlan#.11, for | 1802 | * Returns: the (possibly reallocated) skb or an ERR_PTR() code |
1801 | * transmission (through low-level driver). | ||
1802 | */ | 1803 | */ |
1803 | netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | 1804 | static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, |
1804 | struct net_device *dev) | 1805 | struct sk_buff *skb, u32 info_flags) |
1805 | { | 1806 | { |
1806 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1807 | struct ieee80211_local *local = sdata->local; | 1807 | struct ieee80211_local *local = sdata->local; |
1808 | struct ieee80211_tx_info *info; | 1808 | struct ieee80211_tx_info *info; |
1809 | int head_need; | 1809 | int head_need; |
@@ -1819,25 +1819,17 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1819 | bool wme_sta = false, authorized = false, tdls_auth = false; | 1819 | bool wme_sta = false, authorized = false, tdls_auth = false; |
1820 | bool tdls_peer = false, tdls_setup_frame = false; | 1820 | bool tdls_peer = false, tdls_setup_frame = false; |
1821 | bool multicast; | 1821 | bool multicast; |
1822 | u32 info_flags = 0; | ||
1823 | u16 info_id = 0; | 1822 | u16 info_id = 0; |
1824 | struct ieee80211_chanctx_conf *chanctx_conf; | 1823 | struct ieee80211_chanctx_conf *chanctx_conf; |
1825 | struct ieee80211_sub_if_data *ap_sdata; | 1824 | struct ieee80211_sub_if_data *ap_sdata; |
1826 | enum ieee80211_band band; | 1825 | enum ieee80211_band band; |
1827 | 1826 | int ret; | |
1828 | if (unlikely(skb->len < ETH_HLEN)) | ||
1829 | goto fail; | ||
1830 | 1827 | ||
1831 | /* convert Ethernet header to proper 802.11 header (based on | 1828 | /* convert Ethernet header to proper 802.11 header (based on |
1832 | * operation mode) */ | 1829 | * operation mode) */ |
1833 | ethertype = (skb->data[12] << 8) | skb->data[13]; | 1830 | ethertype = (skb->data[12] << 8) | skb->data[13]; |
1834 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); | 1831 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); |
1835 | 1832 | ||
1836 | rcu_read_lock(); | ||
1837 | |||
1838 | /* Measure frame arrival for Tx latency statistics calculation */ | ||
1839 | ieee80211_tx_latency_start_msrmnt(local, skb); | ||
1840 | |||
1841 | switch (sdata->vif.type) { | 1833 | switch (sdata->vif.type) { |
1842 | case NL80211_IFTYPE_AP_VLAN: | 1834 | case NL80211_IFTYPE_AP_VLAN: |
1843 | sta = rcu_dereference(sdata->u.vlan.sta); | 1835 | sta = rcu_dereference(sdata->u.vlan.sta); |
@@ -1855,8 +1847,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1855 | ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, | 1847 | ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, |
1856 | u.ap); | 1848 | u.ap); |
1857 | chanctx_conf = rcu_dereference(ap_sdata->vif.chanctx_conf); | 1849 | chanctx_conf = rcu_dereference(ap_sdata->vif.chanctx_conf); |
1858 | if (!chanctx_conf) | 1850 | if (!chanctx_conf) { |
1859 | goto fail_rcu; | 1851 | ret = -ENOTCONN; |
1852 | goto free; | ||
1853 | } | ||
1860 | band = chanctx_conf->def.chan->band; | 1854 | band = chanctx_conf->def.chan->band; |
1861 | if (sta) | 1855 | if (sta) |
1862 | break; | 1856 | break; |
@@ -1864,8 +1858,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1864 | case NL80211_IFTYPE_AP: | 1858 | case NL80211_IFTYPE_AP: |
1865 | if (sdata->vif.type == NL80211_IFTYPE_AP) | 1859 | if (sdata->vif.type == NL80211_IFTYPE_AP) |
1866 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 1860 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
1867 | if (!chanctx_conf) | 1861 | if (!chanctx_conf) { |
1868 | goto fail_rcu; | 1862 | ret = -ENOTCONN; |
1863 | goto free; | ||
1864 | } | ||
1869 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); | 1865 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); |
1870 | /* DA BSSID SA */ | 1866 | /* DA BSSID SA */ |
1871 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 1867 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
@@ -1952,8 +1948,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1952 | 1948 | ||
1953 | } | 1949 | } |
1954 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 1950 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
1955 | if (!chanctx_conf) | 1951 | if (!chanctx_conf) { |
1956 | goto fail_rcu; | 1952 | ret = -ENOTCONN; |
1953 | goto free; | ||
1954 | } | ||
1957 | band = chanctx_conf->def.chan->band; | 1955 | band = chanctx_conf->def.chan->band; |
1958 | break; | 1956 | break; |
1959 | #endif | 1957 | #endif |
@@ -1983,8 +1981,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1983 | * of a link teardown after a TDLS sta is removed due to being | 1981 | * of a link teardown after a TDLS sta is removed due to being |
1984 | * unreachable. | 1982 | * unreachable. |
1985 | */ | 1983 | */ |
1986 | if (tdls_peer && !tdls_auth && !tdls_setup_frame) | 1984 | if (tdls_peer && !tdls_auth && !tdls_setup_frame) { |
1987 | goto fail_rcu; | 1985 | ret = -EINVAL; |
1986 | goto free; | ||
1987 | } | ||
1988 | 1988 | ||
1989 | /* send direct packets to authorized TDLS peers */ | 1989 | /* send direct packets to authorized TDLS peers */ |
1990 | if (tdls_peer && tdls_auth) { | 1990 | if (tdls_peer && tdls_auth) { |
@@ -2012,8 +2012,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2012 | hdrlen = 24; | 2012 | hdrlen = 24; |
2013 | } | 2013 | } |
2014 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 2014 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
2015 | if (!chanctx_conf) | 2015 | if (!chanctx_conf) { |
2016 | goto fail_rcu; | 2016 | ret = -ENOTCONN; |
2017 | goto free; | ||
2018 | } | ||
2017 | band = chanctx_conf->def.chan->band; | 2019 | band = chanctx_conf->def.chan->band; |
2018 | break; | 2020 | break; |
2019 | case NL80211_IFTYPE_OCB: | 2021 | case NL80211_IFTYPE_OCB: |
@@ -2023,8 +2025,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2023 | eth_broadcast_addr(hdr.addr3); | 2025 | eth_broadcast_addr(hdr.addr3); |
2024 | hdrlen = 24; | 2026 | hdrlen = 24; |
2025 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 2027 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
2026 | if (!chanctx_conf) | 2028 | if (!chanctx_conf) { |
2027 | goto fail_rcu; | 2029 | ret = -ENOTCONN; |
2030 | goto free; | ||
2031 | } | ||
2028 | band = chanctx_conf->def.chan->band; | 2032 | band = chanctx_conf->def.chan->band; |
2029 | break; | 2033 | break; |
2030 | case NL80211_IFTYPE_ADHOC: | 2034 | case NL80211_IFTYPE_ADHOC: |
@@ -2034,12 +2038,15 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2034 | memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN); | 2038 | memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN); |
2035 | hdrlen = 24; | 2039 | hdrlen = 24; |
2036 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 2040 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
2037 | if (!chanctx_conf) | 2041 | if (!chanctx_conf) { |
2038 | goto fail_rcu; | 2042 | ret = -ENOTCONN; |
2043 | goto free; | ||
2044 | } | ||
2039 | band = chanctx_conf->def.chan->band; | 2045 | band = chanctx_conf->def.chan->band; |
2040 | break; | 2046 | break; |
2041 | default: | 2047 | default: |
2042 | goto fail_rcu; | 2048 | ret = -EINVAL; |
2049 | goto free; | ||
2043 | } | 2050 | } |
2044 | 2051 | ||
2045 | /* | 2052 | /* |
@@ -2077,12 +2084,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2077 | !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) { | 2084 | !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) { |
2078 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 2085 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
2079 | net_info_ratelimited("%s: dropped frame to %pM (unauthorized port)\n", | 2086 | net_info_ratelimited("%s: dropped frame to %pM (unauthorized port)\n", |
2080 | dev->name, hdr.addr1); | 2087 | sdata->name, hdr.addr1); |
2081 | #endif | 2088 | #endif |
2082 | 2089 | ||
2083 | I802_DEBUG_INC(local->tx_handlers_drop_unauth_port); | 2090 | I802_DEBUG_INC(local->tx_handlers_drop_unauth_port); |
2084 | 2091 | ||
2085 | goto fail_rcu; | 2092 | ret = -EPERM; |
2093 | goto free; | ||
2086 | } | 2094 | } |
2087 | 2095 | ||
2088 | if (unlikely(!multicast && skb->sk && | 2096 | if (unlikely(!multicast && skb->sk && |
@@ -2119,8 +2127,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2119 | skb = skb_clone(skb, GFP_ATOMIC); | 2127 | skb = skb_clone(skb, GFP_ATOMIC); |
2120 | kfree_skb(tmp_skb); | 2128 | kfree_skb(tmp_skb); |
2121 | 2129 | ||
2122 | if (!skb) | 2130 | if (!skb) { |
2123 | goto fail_rcu; | 2131 | ret = -ENOMEM; |
2132 | goto free; | ||
2133 | } | ||
2124 | } | 2134 | } |
2125 | 2135 | ||
2126 | hdr.frame_control = fc; | 2136 | hdr.frame_control = fc; |
@@ -2169,7 +2179,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2169 | if (ieee80211_skb_resize(sdata, skb, head_need, true)) { | 2179 | if (ieee80211_skb_resize(sdata, skb, head_need, true)) { |
2170 | ieee80211_free_txskb(&local->hw, skb); | 2180 | ieee80211_free_txskb(&local->hw, skb); |
2171 | skb = NULL; | 2181 | skb = NULL; |
2172 | goto fail_rcu; | 2182 | return ERR_PTR(-ENOMEM); |
2173 | } | 2183 | } |
2174 | } | 2184 | } |
2175 | 2185 | ||
@@ -2203,9 +2213,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2203 | nh_pos += hdrlen; | 2213 | nh_pos += hdrlen; |
2204 | h_pos += hdrlen; | 2214 | h_pos += hdrlen; |
2205 | 2215 | ||
2206 | dev->stats.tx_packets++; | ||
2207 | dev->stats.tx_bytes += skb->len; | ||
2208 | |||
2209 | /* Update skb pointers to various headers since this modified frame | 2216 | /* Update skb pointers to various headers since this modified frame |
2210 | * is going to go through Linux networking code that may potentially | 2217 | * is going to go through Linux networking code that may potentially |
2211 | * need things like pointer to IP header. */ | 2218 | * need things like pointer to IP header. */ |
@@ -2216,23 +2223,90 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2216 | info = IEEE80211_SKB_CB(skb); | 2223 | info = IEEE80211_SKB_CB(skb); |
2217 | memset(info, 0, sizeof(*info)); | 2224 | memset(info, 0, sizeof(*info)); |
2218 | 2225 | ||
2219 | dev->trans_start = jiffies; | ||
2220 | |||
2221 | info->flags = info_flags; | 2226 | info->flags = info_flags; |
2222 | info->ack_frame_id = info_id; | 2227 | info->ack_frame_id = info_id; |
2228 | info->band = band; | ||
2223 | 2229 | ||
2224 | ieee80211_xmit(sdata, skb, band); | 2230 | return skb; |
2225 | rcu_read_unlock(); | 2231 | free: |
2232 | kfree_skb(skb); | ||
2233 | return ERR_PTR(ret); | ||
2234 | } | ||
2226 | 2235 | ||
2227 | return NETDEV_TX_OK; | 2236 | void __ieee80211_subif_start_xmit(struct sk_buff *skb, |
2237 | struct net_device *dev, | ||
2238 | u32 info_flags) | ||
2239 | { | ||
2240 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2241 | struct ieee80211_local *local = sdata->local; | ||
2242 | |||
2243 | if (unlikely(skb->len < ETH_HLEN)) { | ||
2244 | kfree_skb(skb); | ||
2245 | return; | ||
2246 | } | ||
2247 | |||
2248 | rcu_read_lock(); | ||
2249 | |||
2250 | /* Measure frame arrival for Tx latency statistics calculation */ | ||
2251 | ieee80211_tx_latency_start_msrmnt(local, skb); | ||
2252 | |||
2253 | skb = ieee80211_build_hdr(sdata, skb, info_flags); | ||
2254 | if (IS_ERR(skb)) | ||
2255 | goto out; | ||
2256 | |||
2257 | dev->stats.tx_packets++; | ||
2258 | dev->stats.tx_bytes += skb->len; | ||
2259 | dev->trans_start = jiffies; | ||
2228 | 2260 | ||
2229 | fail_rcu: | 2261 | ieee80211_xmit(sdata, skb); |
2262 | out: | ||
2230 | rcu_read_unlock(); | 2263 | rcu_read_unlock(); |
2231 | fail: | 2264 | } |
2232 | dev_kfree_skb(skb); | 2265 | |
2266 | /** | ||
2267 | * ieee80211_subif_start_xmit - netif start_xmit function for 802.3 vifs | ||
2268 | * @skb: packet to be sent | ||
2269 | * @dev: incoming interface | ||
2270 | * | ||
2271 | * On failure skb will be freed. | ||
2272 | */ | ||
2273 | netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | ||
2274 | struct net_device *dev) | ||
2275 | { | ||
2276 | __ieee80211_subif_start_xmit(skb, dev, 0); | ||
2233 | return NETDEV_TX_OK; | 2277 | return NETDEV_TX_OK; |
2234 | } | 2278 | } |
2235 | 2279 | ||
2280 | struct sk_buff * | ||
2281 | ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata, | ||
2282 | struct sk_buff *skb, u32 info_flags) | ||
2283 | { | ||
2284 | struct ieee80211_hdr *hdr; | ||
2285 | struct ieee80211_tx_data tx = { | ||
2286 | .local = sdata->local, | ||
2287 | .sdata = sdata, | ||
2288 | }; | ||
2289 | |||
2290 | rcu_read_lock(); | ||
2291 | |||
2292 | skb = ieee80211_build_hdr(sdata, skb, info_flags); | ||
2293 | if (IS_ERR(skb)) | ||
2294 | goto out; | ||
2295 | |||
2296 | hdr = (void *)skb->data; | ||
2297 | tx.sta = sta_info_get(sdata, hdr->addr1); | ||
2298 | tx.skb = skb; | ||
2299 | |||
2300 | if (ieee80211_tx_h_select_key(&tx) != TX_CONTINUE) { | ||
2301 | rcu_read_unlock(); | ||
2302 | kfree_skb(skb); | ||
2303 | return ERR_PTR(-EINVAL); | ||
2304 | } | ||
2305 | |||
2306 | out: | ||
2307 | rcu_read_unlock(); | ||
2308 | return skb; | ||
2309 | } | ||
2236 | 2310 | ||
2237 | /* | 2311 | /* |
2238 | * ieee80211_clear_tx_pending may not be called in a context where | 2312 | * ieee80211_clear_tx_pending may not be called in a context where |
@@ -2272,8 +2346,8 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, | |||
2272 | dev_kfree_skb(skb); | 2346 | dev_kfree_skb(skb); |
2273 | return true; | 2347 | return true; |
2274 | } | 2348 | } |
2275 | result = ieee80211_tx(sdata, skb, true, | 2349 | info->band = chanctx_conf->def.chan->band; |
2276 | chanctx_conf->def.chan->band); | 2350 | result = ieee80211_tx(sdata, skb, true); |
2277 | } else { | 2351 | } else { |
2278 | struct sk_buff_head skbs; | 2352 | struct sk_buff_head skbs; |
2279 | 2353 | ||
@@ -2887,19 +2961,16 @@ struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, | |||
2887 | EXPORT_SYMBOL(ieee80211_nullfunc_get); | 2961 | EXPORT_SYMBOL(ieee80211_nullfunc_get); |
2888 | 2962 | ||
2889 | struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, | 2963 | struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, |
2890 | struct ieee80211_vif *vif, | 2964 | const u8 *src_addr, |
2891 | const u8 *ssid, size_t ssid_len, | 2965 | const u8 *ssid, size_t ssid_len, |
2892 | size_t tailroom) | 2966 | size_t tailroom) |
2893 | { | 2967 | { |
2894 | struct ieee80211_sub_if_data *sdata; | 2968 | struct ieee80211_local *local = hw_to_local(hw); |
2895 | struct ieee80211_local *local; | ||
2896 | struct ieee80211_hdr_3addr *hdr; | 2969 | struct ieee80211_hdr_3addr *hdr; |
2897 | struct sk_buff *skb; | 2970 | struct sk_buff *skb; |
2898 | size_t ie_ssid_len; | 2971 | size_t ie_ssid_len; |
2899 | u8 *pos; | 2972 | u8 *pos; |
2900 | 2973 | ||
2901 | sdata = vif_to_sdata(vif); | ||
2902 | local = sdata->local; | ||
2903 | ie_ssid_len = 2 + ssid_len; | 2974 | ie_ssid_len = 2 + ssid_len; |
2904 | 2975 | ||
2905 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) + | 2976 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) + |
@@ -2914,7 +2985,7 @@ struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, | |||
2914 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 2985 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
2915 | IEEE80211_STYPE_PROBE_REQ); | 2986 | IEEE80211_STYPE_PROBE_REQ); |
2916 | eth_broadcast_addr(hdr->addr1); | 2987 | eth_broadcast_addr(hdr->addr1); |
2917 | memcpy(hdr->addr2, vif->addr, ETH_ALEN); | 2988 | memcpy(hdr->addr2, src_addr, ETH_ALEN); |
2918 | eth_broadcast_addr(hdr->addr3); | 2989 | eth_broadcast_addr(hdr->addr3); |
2919 | 2990 | ||
2920 | pos = skb_put(skb, ie_ssid_len); | 2991 | pos = skb_put(skb, ie_ssid_len); |
@@ -3033,6 +3104,97 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
3033 | } | 3104 | } |
3034 | EXPORT_SYMBOL(ieee80211_get_buffered_bc); | 3105 | EXPORT_SYMBOL(ieee80211_get_buffered_bc); |
3035 | 3106 | ||
3107 | int ieee80211_reserve_tid(struct ieee80211_sta *pubsta, u8 tid) | ||
3108 | { | ||
3109 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | ||
3110 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
3111 | struct ieee80211_local *local = sdata->local; | ||
3112 | int ret; | ||
3113 | u32 queues; | ||
3114 | |||
3115 | lockdep_assert_held(&local->sta_mtx); | ||
3116 | |||
3117 | /* only some cases are supported right now */ | ||
3118 | switch (sdata->vif.type) { | ||
3119 | case NL80211_IFTYPE_STATION: | ||
3120 | case NL80211_IFTYPE_AP: | ||
3121 | case NL80211_IFTYPE_AP_VLAN: | ||
3122 | break; | ||
3123 | default: | ||
3124 | WARN_ON(1); | ||
3125 | return -EINVAL; | ||
3126 | } | ||
3127 | |||
3128 | if (WARN_ON(tid >= IEEE80211_NUM_UPS)) | ||
3129 | return -EINVAL; | ||
3130 | |||
3131 | if (sta->reserved_tid == tid) { | ||
3132 | ret = 0; | ||
3133 | goto out; | ||
3134 | } | ||
3135 | |||
3136 | if (sta->reserved_tid != IEEE80211_TID_UNRESERVED) { | ||
3137 | sdata_err(sdata, "TID reservation already active\n"); | ||
3138 | ret = -EALREADY; | ||
3139 | goto out; | ||
3140 | } | ||
3141 | |||
3142 | ieee80211_stop_vif_queues(sdata->local, sdata, | ||
3143 | IEEE80211_QUEUE_STOP_REASON_RESERVE_TID); | ||
3144 | |||
3145 | synchronize_net(); | ||
3146 | |||
3147 | /* Tear down BA sessions so we stop aggregating on this TID */ | ||
3148 | if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) { | ||
3149 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); | ||
3150 | __ieee80211_stop_tx_ba_session(sta, tid, | ||
3151 | AGG_STOP_LOCAL_REQUEST); | ||
3152 | } | ||
3153 | |||
3154 | queues = BIT(sdata->vif.hw_queue[ieee802_1d_to_ac[tid]]); | ||
3155 | __ieee80211_flush_queues(local, sdata, queues); | ||
3156 | |||
3157 | sta->reserved_tid = tid; | ||
3158 | |||
3159 | ieee80211_wake_vif_queues(local, sdata, | ||
3160 | IEEE80211_QUEUE_STOP_REASON_RESERVE_TID); | ||
3161 | |||
3162 | if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) | ||
3163 | clear_sta_flag(sta, WLAN_STA_BLOCK_BA); | ||
3164 | |||
3165 | ret = 0; | ||
3166 | out: | ||
3167 | return ret; | ||
3168 | } | ||
3169 | EXPORT_SYMBOL(ieee80211_reserve_tid); | ||
3170 | |||
3171 | void ieee80211_unreserve_tid(struct ieee80211_sta *pubsta, u8 tid) | ||
3172 | { | ||
3173 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | ||
3174 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
3175 | |||
3176 | lockdep_assert_held(&sdata->local->sta_mtx); | ||
3177 | |||
3178 | /* only some cases are supported right now */ | ||
3179 | switch (sdata->vif.type) { | ||
3180 | case NL80211_IFTYPE_STATION: | ||
3181 | case NL80211_IFTYPE_AP: | ||
3182 | case NL80211_IFTYPE_AP_VLAN: | ||
3183 | break; | ||
3184 | default: | ||
3185 | WARN_ON(1); | ||
3186 | return; | ||
3187 | } | ||
3188 | |||
3189 | if (tid != sta->reserved_tid) { | ||
3190 | sdata_err(sdata, "TID to unreserve (%d) isn't reserved\n", tid); | ||
3191 | return; | ||
3192 | } | ||
3193 | |||
3194 | sta->reserved_tid = IEEE80211_TID_UNRESERVED; | ||
3195 | } | ||
3196 | EXPORT_SYMBOL(ieee80211_unreserve_tid); | ||
3197 | |||
3036 | void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, | 3198 | void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, |
3037 | struct sk_buff *skb, int tid, | 3199 | struct sk_buff *skb, int tid, |
3038 | enum ieee80211_band band) | 3200 | enum ieee80211_band band) |
@@ -3054,6 +3216,7 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, | |||
3054 | * requirements are that we do not come into tx with bhs on. | 3216 | * requirements are that we do not come into tx with bhs on. |
3055 | */ | 3217 | */ |
3056 | local_bh_disable(); | 3218 | local_bh_disable(); |
3057 | ieee80211_xmit(sdata, skb, band); | 3219 | IEEE80211_SKB_CB(skb)->band = band; |
3220 | ieee80211_xmit(sdata, skb); | ||
3058 | local_bh_enable(); | 3221 | local_bh_enable(); |
3059 | } | 3222 | } |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index f9319a5dca64..bb9664cb8831 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -576,15 +576,19 @@ ieee80211_get_vif_queues(struct ieee80211_local *local, | |||
576 | return queues; | 576 | return queues; |
577 | } | 577 | } |
578 | 578 | ||
579 | void ieee80211_flush_queues(struct ieee80211_local *local, | 579 | void __ieee80211_flush_queues(struct ieee80211_local *local, |
580 | struct ieee80211_sub_if_data *sdata) | 580 | struct ieee80211_sub_if_data *sdata, |
581 | unsigned int queues) | ||
581 | { | 582 | { |
582 | unsigned int queues; | ||
583 | |||
584 | if (!local->ops->flush) | 583 | if (!local->ops->flush) |
585 | return; | 584 | return; |
586 | 585 | ||
587 | queues = ieee80211_get_vif_queues(local, sdata); | 586 | /* |
587 | * If no queue was set, or if the HW doesn't support | ||
588 | * IEEE80211_HW_QUEUE_CONTROL - flush all queues | ||
589 | */ | ||
590 | if (!queues || !(local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)) | ||
591 | queues = ieee80211_get_vif_queues(local, sdata); | ||
588 | 592 | ||
589 | ieee80211_stop_queues_by_reason(&local->hw, queues, | 593 | ieee80211_stop_queues_by_reason(&local->hw, queues, |
590 | IEEE80211_QUEUE_STOP_REASON_FLUSH, | 594 | IEEE80211_QUEUE_STOP_REASON_FLUSH, |
@@ -597,6 +601,12 @@ void ieee80211_flush_queues(struct ieee80211_local *local, | |||
597 | false); | 601 | false); |
598 | } | 602 | } |
599 | 603 | ||
604 | void ieee80211_flush_queues(struct ieee80211_local *local, | ||
605 | struct ieee80211_sub_if_data *sdata) | ||
606 | { | ||
607 | __ieee80211_flush_queues(local, sdata, 0); | ||
608 | } | ||
609 | |||
600 | void ieee80211_stop_vif_queues(struct ieee80211_local *local, | 610 | void ieee80211_stop_vif_queues(struct ieee80211_local *local, |
601 | struct ieee80211_sub_if_data *sdata, | 611 | struct ieee80211_sub_if_data *sdata, |
602 | enum queue_stop_reason reason) | 612 | enum queue_stop_reason reason) |
@@ -831,6 +841,9 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | |||
831 | case WLAN_EID_SECONDARY_CHANNEL_OFFSET: | 841 | case WLAN_EID_SECONDARY_CHANNEL_OFFSET: |
832 | case WLAN_EID_WIDE_BW_CHANNEL_SWITCH: | 842 | case WLAN_EID_WIDE_BW_CHANNEL_SWITCH: |
833 | case WLAN_EID_CHAN_SWITCH_PARAM: | 843 | case WLAN_EID_CHAN_SWITCH_PARAM: |
844 | case WLAN_EID_EXT_CAPABILITY: | ||
845 | case WLAN_EID_CHAN_SWITCH_TIMING: | ||
846 | case WLAN_EID_LINK_ID: | ||
834 | /* | 847 | /* |
835 | * not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible | 848 | * not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible |
836 | * that if the content gets bigger it might be needed more than once | 849 | * that if the content gets bigger it might be needed more than once |
@@ -850,6 +863,24 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | |||
850 | elem_parse_failed = false; | 863 | elem_parse_failed = false; |
851 | 864 | ||
852 | switch (id) { | 865 | switch (id) { |
866 | case WLAN_EID_LINK_ID: | ||
867 | if (elen + 2 != sizeof(struct ieee80211_tdls_lnkie)) { | ||
868 | elem_parse_failed = true; | ||
869 | break; | ||
870 | } | ||
871 | elems->lnk_id = (void *)(pos - 2); | ||
872 | break; | ||
873 | case WLAN_EID_CHAN_SWITCH_TIMING: | ||
874 | if (elen != sizeof(struct ieee80211_ch_switch_timing)) { | ||
875 | elem_parse_failed = true; | ||
876 | break; | ||
877 | } | ||
878 | elems->ch_sw_timing = (void *)pos; | ||
879 | break; | ||
880 | case WLAN_EID_EXT_CAPABILITY: | ||
881 | elems->ext_capab = pos; | ||
882 | elems->ext_capab_len = elen; | ||
883 | break; | ||
853 | case WLAN_EID_SSID: | 884 | case WLAN_EID_SSID: |
854 | elems->ssid = pos; | 885 | elems->ssid = pos; |
855 | elems->ssid_len = elen; | 886 | elems->ssid_len = elen; |
@@ -1492,7 +1523,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1492 | }; | 1523 | }; |
1493 | 1524 | ||
1494 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | 1525 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, |
1495 | u8 *dst, u32 ratemask, | 1526 | const u8 *src, const u8 *dst, |
1527 | u32 ratemask, | ||
1496 | struct ieee80211_channel *chan, | 1528 | struct ieee80211_channel *chan, |
1497 | const u8 *ssid, size_t ssid_len, | 1529 | const u8 *ssid, size_t ssid_len, |
1498 | const u8 *ie, size_t ie_len, | 1530 | const u8 *ie, size_t ie_len, |
@@ -1517,8 +1549,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1517 | else | 1549 | else |
1518 | chandef.chan = chan; | 1550 | chandef.chan = chan; |
1519 | 1551 | ||
1520 | skb = ieee80211_probereq_get(&local->hw, &sdata->vif, | 1552 | skb = ieee80211_probereq_get(&local->hw, src, ssid, ssid_len, |
1521 | ssid, ssid_len, 100 + ie_len); | 1553 | 100 + ie_len); |
1522 | if (!skb) | 1554 | if (!skb) |
1523 | return NULL; | 1555 | return NULL; |
1524 | 1556 | ||
@@ -1540,7 +1572,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1540 | return skb; | 1572 | return skb; |
1541 | } | 1573 | } |
1542 | 1574 | ||
1543 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 1575 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, |
1576 | const u8 *src, const u8 *dst, | ||
1544 | const u8 *ssid, size_t ssid_len, | 1577 | const u8 *ssid, size_t ssid_len, |
1545 | const u8 *ie, size_t ie_len, | 1578 | const u8 *ie, size_t ie_len, |
1546 | u32 ratemask, bool directed, u32 tx_flags, | 1579 | u32 ratemask, bool directed, u32 tx_flags, |
@@ -1548,7 +1581,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
1548 | { | 1581 | { |
1549 | struct sk_buff *skb; | 1582 | struct sk_buff *skb; |
1550 | 1583 | ||
1551 | skb = ieee80211_build_probe_req(sdata, dst, ratemask, channel, | 1584 | skb = ieee80211_build_probe_req(sdata, src, dst, ratemask, channel, |
1552 | ssid, ssid_len, | 1585 | ssid, ssid_len, |
1553 | ie, ie_len, directed); | 1586 | ie, ie_len, directed); |
1554 | if (skb) { | 1587 | if (skb) { |
@@ -1690,6 +1723,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1690 | int res, i; | 1723 | int res, i; |
1691 | bool reconfig_due_to_wowlan = false; | 1724 | bool reconfig_due_to_wowlan = false; |
1692 | struct ieee80211_sub_if_data *sched_scan_sdata; | 1725 | struct ieee80211_sub_if_data *sched_scan_sdata; |
1726 | struct cfg80211_sched_scan_request *sched_scan_req; | ||
1693 | bool sched_scan_stopped = false; | 1727 | bool sched_scan_stopped = false; |
1694 | 1728 | ||
1695 | #ifdef CONFIG_PM | 1729 | #ifdef CONFIG_PM |
@@ -1980,13 +2014,15 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1980 | mutex_lock(&local->mtx); | 2014 | mutex_lock(&local->mtx); |
1981 | sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata, | 2015 | sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata, |
1982 | lockdep_is_held(&local->mtx)); | 2016 | lockdep_is_held(&local->mtx)); |
1983 | if (sched_scan_sdata && local->sched_scan_req) | 2017 | sched_scan_req = rcu_dereference_protected(local->sched_scan_req, |
2018 | lockdep_is_held(&local->mtx)); | ||
2019 | if (sched_scan_sdata && sched_scan_req) | ||
1984 | /* | 2020 | /* |
1985 | * Sched scan stopped, but we don't want to report it. Instead, | 2021 | * Sched scan stopped, but we don't want to report it. Instead, |
1986 | * we're trying to reschedule. | 2022 | * we're trying to reschedule. |
1987 | */ | 2023 | */ |
1988 | if (__ieee80211_request_sched_scan_start(sched_scan_sdata, | 2024 | if (__ieee80211_request_sched_scan_start(sched_scan_sdata, |
1989 | local->sched_scan_req)) | 2025 | sched_scan_req)) |
1990 | sched_scan_stopped = true; | 2026 | sched_scan_stopped = true; |
1991 | mutex_unlock(&local->mtx); | 2027 | mutex_unlock(&local->mtx); |
1992 | 2028 | ||
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index 671ce0d27a80..bc9e8fc48785 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c | |||
@@ -287,6 +287,8 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta) | |||
287 | /* fall through */ | 287 | /* fall through */ |
288 | case NL80211_CHAN_WIDTH_20_NOHT: | 288 | case NL80211_CHAN_WIDTH_20_NOHT: |
289 | case NL80211_CHAN_WIDTH_20: | 289 | case NL80211_CHAN_WIDTH_20: |
290 | bw = IEEE80211_STA_RX_BW_20; | ||
291 | break; | ||
290 | case NL80211_CHAN_WIDTH_40: | 292 | case NL80211_CHAN_WIDTH_40: |
291 | bw = sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? | 293 | bw = sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? |
292 | IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; | 294 | IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; |
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index fdf52db95b33..9eb0aee9105b 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
@@ -53,6 +53,36 @@ static int wme_downgrade_ac(struct sk_buff *skb) | |||
53 | } | 53 | } |
54 | } | 54 | } |
55 | 55 | ||
56 | /** | ||
57 | * ieee80211_fix_reserved_tid - return the TID to use if this one is reserved | ||
58 | * @tid: the assumed-reserved TID | ||
59 | * | ||
60 | * Returns: the alternative TID to use, or 0 on error | ||
61 | */ | ||
62 | static inline u8 ieee80211_fix_reserved_tid(u8 tid) | ||
63 | { | ||
64 | switch (tid) { | ||
65 | case 0: | ||
66 | return 3; | ||
67 | case 1: | ||
68 | return 2; | ||
69 | case 2: | ||
70 | return 1; | ||
71 | case 3: | ||
72 | return 0; | ||
73 | case 4: | ||
74 | return 5; | ||
75 | case 5: | ||
76 | return 4; | ||
77 | case 6: | ||
78 | return 7; | ||
79 | case 7: | ||
80 | return 6; | ||
81 | } | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
56 | static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, | 86 | static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, |
57 | struct sta_info *sta, struct sk_buff *skb) | 87 | struct sta_info *sta, struct sk_buff *skb) |
58 | { | 88 | { |
@@ -77,6 +107,10 @@ static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, | |||
77 | } | 107 | } |
78 | } | 108 | } |
79 | 109 | ||
110 | /* Check to see if this is a reserved TID */ | ||
111 | if (sta && sta->reserved_tid == skb->priority) | ||
112 | skb->priority = ieee80211_fix_reserved_tid(skb->priority); | ||
113 | |||
80 | /* look up which queue to use for frames with this 1d tag */ | 114 | /* look up which queue to use for frames with this 1d tag */ |
81 | return ieee802_1d_to_ac[skb->priority]; | 115 | return ieee802_1d_to_ac[skb->priority]; |
82 | } | 116 | } |
@@ -143,6 +177,11 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
143 | break; | 177 | break; |
144 | #endif | 178 | #endif |
145 | case NL80211_IFTYPE_STATION: | 179 | case NL80211_IFTYPE_STATION: |
180 | /* might be a TDLS station */ | ||
181 | sta = sta_info_get(sdata, skb->data); | ||
182 | if (sta) | ||
183 | qos = sta->sta.wme; | ||
184 | |||
146 | ra = sdata->u.mgd.bssid; | 185 | ra = sdata->u.mgd.bssid; |
147 | break; | 186 | break; |
148 | case NL80211_IFTYPE_ADHOC: | 187 | case NL80211_IFTYPE_ADHOC: |
diff --git a/net/wireless/core.c b/net/wireless/core.c index a4d27927aba2..4c2e501203d1 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -541,6 +541,10 @@ int wiphy_register(struct wiphy *wiphy) | |||
541 | !wiphy->wowlan->tcp)) | 541 | !wiphy->wowlan->tcp)) |
542 | return -EINVAL; | 542 | return -EINVAL; |
543 | #endif | 543 | #endif |
544 | if (WARN_ON((wiphy->features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH) && | ||
545 | (!rdev->ops->tdls_channel_switch || | ||
546 | !rdev->ops->tdls_cancel_channel_switch))) | ||
547 | return -EINVAL; | ||
544 | 548 | ||
545 | if (WARN_ON(wiphy->coalesce && | 549 | if (WARN_ON(wiphy->coalesce && |
546 | (!wiphy->coalesce->n_rules || | 550 | (!wiphy->coalesce->n_rules || |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 61ee664cf2bd..faa5b1609aae 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -111,6 +111,7 @@ cfg80211_rdev_free_wowlan(struct cfg80211_registered_device *rdev) | |||
111 | rdev->wiphy.wowlan_config->tcp->sock) | 111 | rdev->wiphy.wowlan_config->tcp->sock) |
112 | sock_release(rdev->wiphy.wowlan_config->tcp->sock); | 112 | sock_release(rdev->wiphy.wowlan_config->tcp->sock); |
113 | kfree(rdev->wiphy.wowlan_config->tcp); | 113 | kfree(rdev->wiphy.wowlan_config->tcp); |
114 | kfree(rdev->wiphy.wowlan_config->nd_config); | ||
114 | kfree(rdev->wiphy.wowlan_config); | 115 | kfree(rdev->wiphy.wowlan_config); |
115 | #endif | 116 | #endif |
116 | } | 117 | } |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1a31736914e5..6e4177701d86 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -209,7 +209,7 @@ cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info) | |||
209 | } | 209 | } |
210 | 210 | ||
211 | /* policy for the attributes */ | 211 | /* policy for the attributes */ |
212 | static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | 212 | static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { |
213 | [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, | 213 | [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, |
214 | [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, | 214 | [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, |
215 | .len = 20-1 }, | 215 | .len = 20-1 }, |
@@ -388,13 +388,14 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
388 | [NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN }, | 388 | [NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN }, |
389 | [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 }, | 389 | [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 }, |
390 | [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 }, | 390 | [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 }, |
391 | [NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG }, | 391 | [NL80211_ATTR_SOCKET_OWNER] = { .type = NLA_FLAG }, |
392 | [NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY }, | 392 | [NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY }, |
393 | [NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG }, | 393 | [NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG }, |
394 | [NL80211_ATTR_TSID] = { .type = NLA_U8 }, | 394 | [NL80211_ATTR_TSID] = { .type = NLA_U8 }, |
395 | [NL80211_ATTR_USER_PRIO] = { .type = NLA_U8 }, | 395 | [NL80211_ATTR_USER_PRIO] = { .type = NLA_U8 }, |
396 | [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 }, | 396 | [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 }, |
397 | [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 }, | 397 | [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 }, |
398 | [NL80211_ATTR_MAC_MASK] = { .len = ETH_ALEN }, | ||
398 | }; | 399 | }; |
399 | 400 | ||
400 | /* policy for the key attributes */ | 401 | /* policy for the key attributes */ |
@@ -428,6 +429,7 @@ nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = { | |||
428 | [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG }, | 429 | [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG }, |
429 | [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG }, | 430 | [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG }, |
430 | [NL80211_WOWLAN_TRIG_TCP_CONNECTION] = { .type = NLA_NESTED }, | 431 | [NL80211_WOWLAN_TRIG_TCP_CONNECTION] = { .type = NLA_NESTED }, |
432 | [NL80211_WOWLAN_TRIG_NET_DETECT] = { .type = NLA_NESTED }, | ||
431 | }; | 433 | }; |
432 | 434 | ||
433 | static const struct nla_policy | 435 | static const struct nla_policy |
@@ -1088,6 +1090,8 @@ static int nl80211_send_wowlan(struct sk_buff *msg, | |||
1088 | if (large && nl80211_send_wowlan_tcp_caps(rdev, msg)) | 1090 | if (large && nl80211_send_wowlan_tcp_caps(rdev, msg)) |
1089 | return -ENOBUFS; | 1091 | return -ENOBUFS; |
1090 | 1092 | ||
1093 | /* TODO: send wowlan net detect */ | ||
1094 | |||
1091 | nla_nest_end(msg, nl_wowlan); | 1095 | nla_nest_end(msg, nl_wowlan); |
1092 | 1096 | ||
1093 | return 0; | 1097 | return 0; |
@@ -2341,12 +2345,16 @@ static int nl80211_send_chandef(struct sk_buff *msg, | |||
2341 | 2345 | ||
2342 | static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags, | 2346 | static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags, |
2343 | struct cfg80211_registered_device *rdev, | 2347 | struct cfg80211_registered_device *rdev, |
2344 | struct wireless_dev *wdev) | 2348 | struct wireless_dev *wdev, bool removal) |
2345 | { | 2349 | { |
2346 | struct net_device *dev = wdev->netdev; | 2350 | struct net_device *dev = wdev->netdev; |
2351 | u8 cmd = NL80211_CMD_NEW_INTERFACE; | ||
2347 | void *hdr; | 2352 | void *hdr; |
2348 | 2353 | ||
2349 | hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_INTERFACE); | 2354 | if (removal) |
2355 | cmd = NL80211_CMD_DEL_INTERFACE; | ||
2356 | |||
2357 | hdr = nl80211hdr_put(msg, portid, seq, flags, cmd); | ||
2350 | if (!hdr) | 2358 | if (!hdr) |
2351 | return -1; | 2359 | return -1; |
2352 | 2360 | ||
@@ -2413,7 +2421,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
2413 | } | 2421 | } |
2414 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid, | 2422 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid, |
2415 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 2423 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
2416 | rdev, wdev) < 0) { | 2424 | rdev, wdev, false) < 0) { |
2417 | goto out; | 2425 | goto out; |
2418 | } | 2426 | } |
2419 | if_idx++; | 2427 | if_idx++; |
@@ -2441,7 +2449,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) | |||
2441 | return -ENOMEM; | 2449 | return -ENOMEM; |
2442 | 2450 | ||
2443 | if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0, | 2451 | if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0, |
2444 | rdev, wdev) < 0) { | 2452 | rdev, wdev, false) < 0) { |
2445 | nlmsg_free(msg); | 2453 | nlmsg_free(msg); |
2446 | return -ENOBUFS; | 2454 | return -ENOBUFS; |
2447 | } | 2455 | } |
@@ -2587,7 +2595,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
2587 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2595 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2588 | struct vif_params params; | 2596 | struct vif_params params; |
2589 | struct wireless_dev *wdev; | 2597 | struct wireless_dev *wdev; |
2590 | struct sk_buff *msg; | 2598 | struct sk_buff *msg, *event; |
2591 | int err; | 2599 | int err; |
2592 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; | 2600 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; |
2593 | u32 flags; | 2601 | u32 flags; |
@@ -2641,12 +2649,15 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
2641 | wdev = rdev_add_virtual_intf(rdev, | 2649 | wdev = rdev_add_virtual_intf(rdev, |
2642 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), | 2650 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
2643 | type, err ? NULL : &flags, ¶ms); | 2651 | type, err ? NULL : &flags, ¶ms); |
2644 | if (IS_ERR(wdev)) { | 2652 | if (WARN_ON(!wdev)) { |
2653 | nlmsg_free(msg); | ||
2654 | return -EPROTO; | ||
2655 | } else if (IS_ERR(wdev)) { | ||
2645 | nlmsg_free(msg); | 2656 | nlmsg_free(msg); |
2646 | return PTR_ERR(wdev); | 2657 | return PTR_ERR(wdev); |
2647 | } | 2658 | } |
2648 | 2659 | ||
2649 | if (info->attrs[NL80211_ATTR_IFACE_SOCKET_OWNER]) | 2660 | if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) |
2650 | wdev->owner_nlportid = info->snd_portid; | 2661 | wdev->owner_nlportid = info->snd_portid; |
2651 | 2662 | ||
2652 | switch (type) { | 2663 | switch (type) { |
@@ -2682,11 +2693,25 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
2682 | } | 2693 | } |
2683 | 2694 | ||
2684 | if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0, | 2695 | if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0, |
2685 | rdev, wdev) < 0) { | 2696 | rdev, wdev, false) < 0) { |
2686 | nlmsg_free(msg); | 2697 | nlmsg_free(msg); |
2687 | return -ENOBUFS; | 2698 | return -ENOBUFS; |
2688 | } | 2699 | } |
2689 | 2700 | ||
2701 | event = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
2702 | if (event) { | ||
2703 | if (nl80211_send_iface(event, 0, 0, 0, | ||
2704 | rdev, wdev, false) < 0) { | ||
2705 | nlmsg_free(event); | ||
2706 | goto out; | ||
2707 | } | ||
2708 | |||
2709 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), | ||
2710 | event, 0, NL80211_MCGRP_CONFIG, | ||
2711 | GFP_KERNEL); | ||
2712 | } | ||
2713 | |||
2714 | out: | ||
2690 | return genlmsg_reply(msg, info); | 2715 | return genlmsg_reply(msg, info); |
2691 | } | 2716 | } |
2692 | 2717 | ||
@@ -2694,10 +2719,18 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | |||
2694 | { | 2719 | { |
2695 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2720 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2696 | struct wireless_dev *wdev = info->user_ptr[1]; | 2721 | struct wireless_dev *wdev = info->user_ptr[1]; |
2722 | struct sk_buff *msg; | ||
2723 | int status; | ||
2697 | 2724 | ||
2698 | if (!rdev->ops->del_virtual_intf) | 2725 | if (!rdev->ops->del_virtual_intf) |
2699 | return -EOPNOTSUPP; | 2726 | return -EOPNOTSUPP; |
2700 | 2727 | ||
2728 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
2729 | if (msg && nl80211_send_iface(msg, 0, 0, 0, rdev, wdev, true) < 0) { | ||
2730 | nlmsg_free(msg); | ||
2731 | msg = NULL; | ||
2732 | } | ||
2733 | |||
2701 | /* | 2734 | /* |
2702 | * If we remove a wireless device without a netdev then clear | 2735 | * If we remove a wireless device without a netdev then clear |
2703 | * user_ptr[1] so that nl80211_post_doit won't dereference it | 2736 | * user_ptr[1] so that nl80211_post_doit won't dereference it |
@@ -2708,7 +2741,15 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | |||
2708 | if (!wdev->netdev) | 2741 | if (!wdev->netdev) |
2709 | info->user_ptr[1] = NULL; | 2742 | info->user_ptr[1] = NULL; |
2710 | 2743 | ||
2711 | return rdev_del_virtual_intf(rdev, wdev); | 2744 | status = rdev_del_virtual_intf(rdev, wdev); |
2745 | if (status >= 0 && msg) | ||
2746 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), | ||
2747 | msg, 0, NL80211_MCGRP_CONFIG, | ||
2748 | GFP_KERNEL); | ||
2749 | else | ||
2750 | nlmsg_free(msg); | ||
2751 | |||
2752 | return status; | ||
2712 | } | 2753 | } |
2713 | 2754 | ||
2714 | static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info) | 2755 | static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info) |
@@ -4453,7 +4494,7 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq, | |||
4453 | void *hdr; | 4494 | void *hdr; |
4454 | struct nlattr *pinfoattr; | 4495 | struct nlattr *pinfoattr; |
4455 | 4496 | ||
4456 | hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_STATION); | 4497 | hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_MPATH); |
4457 | if (!hdr) | 4498 | if (!hdr) |
4458 | return -1; | 4499 | return -1; |
4459 | 4500 | ||
@@ -5478,6 +5519,43 @@ static int validate_scan_freqs(struct nlattr *freqs) | |||
5478 | return n_channels; | 5519 | return n_channels; |
5479 | } | 5520 | } |
5480 | 5521 | ||
5522 | static int nl80211_parse_random_mac(struct nlattr **attrs, | ||
5523 | u8 *mac_addr, u8 *mac_addr_mask) | ||
5524 | { | ||
5525 | int i; | ||
5526 | |||
5527 | if (!attrs[NL80211_ATTR_MAC] && !attrs[NL80211_ATTR_MAC_MASK]) { | ||
5528 | memset(mac_addr, 0, ETH_ALEN); | ||
5529 | memset(mac_addr_mask, 0, ETH_ALEN); | ||
5530 | mac_addr[0] = 0x2; | ||
5531 | mac_addr_mask[0] = 0x3; | ||
5532 | |||
5533 | return 0; | ||
5534 | } | ||
5535 | |||
5536 | /* need both or none */ | ||
5537 | if (!attrs[NL80211_ATTR_MAC] || !attrs[NL80211_ATTR_MAC_MASK]) | ||
5538 | return -EINVAL; | ||
5539 | |||
5540 | memcpy(mac_addr, nla_data(attrs[NL80211_ATTR_MAC]), ETH_ALEN); | ||
5541 | memcpy(mac_addr_mask, nla_data(attrs[NL80211_ATTR_MAC_MASK]), ETH_ALEN); | ||
5542 | |||
5543 | /* don't allow or configure an mcast address */ | ||
5544 | if (!is_multicast_ether_addr(mac_addr_mask) || | ||
5545 | is_multicast_ether_addr(mac_addr)) | ||
5546 | return -EINVAL; | ||
5547 | |||
5548 | /* | ||
5549 | * allow users to pass a MAC address that has bits set outside | ||
5550 | * of the mask, but don't bother drivers with having to deal | ||
5551 | * with such bits | ||
5552 | */ | ||
5553 | for (i = 0; i < ETH_ALEN; i++) | ||
5554 | mac_addr[i] &= mac_addr_mask[i]; | ||
5555 | |||
5556 | return 0; | ||
5557 | } | ||
5558 | |||
5481 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | 5559 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) |
5482 | { | 5560 | { |
5483 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 5561 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -5655,6 +5733,25 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
5655 | err = -EOPNOTSUPP; | 5733 | err = -EOPNOTSUPP; |
5656 | goto out_free; | 5734 | goto out_free; |
5657 | } | 5735 | } |
5736 | |||
5737 | if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { | ||
5738 | if (!(wiphy->features & | ||
5739 | NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR)) { | ||
5740 | err = -EOPNOTSUPP; | ||
5741 | goto out_free; | ||
5742 | } | ||
5743 | |||
5744 | if (wdev->current_bss) { | ||
5745 | err = -EOPNOTSUPP; | ||
5746 | goto out_free; | ||
5747 | } | ||
5748 | |||
5749 | err = nl80211_parse_random_mac(info->attrs, | ||
5750 | request->mac_addr, | ||
5751 | request->mac_addr_mask); | ||
5752 | if (err) | ||
5753 | goto out_free; | ||
5754 | } | ||
5658 | } | 5755 | } |
5659 | 5756 | ||
5660 | request->no_cck = | 5757 | request->no_cck = |
@@ -5681,14 +5778,12 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
5681 | return err; | 5778 | return err; |
5682 | } | 5779 | } |
5683 | 5780 | ||
5684 | static int nl80211_start_sched_scan(struct sk_buff *skb, | 5781 | static struct cfg80211_sched_scan_request * |
5685 | struct genl_info *info) | 5782 | nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev, |
5783 | struct nlattr **attrs) | ||
5686 | { | 5784 | { |
5687 | struct cfg80211_sched_scan_request *request; | 5785 | struct cfg80211_sched_scan_request *request; |
5688 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
5689 | struct net_device *dev = info->user_ptr[1]; | ||
5690 | struct nlattr *attr; | 5786 | struct nlattr *attr; |
5691 | struct wiphy *wiphy; | ||
5692 | int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i; | 5787 | int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i; |
5693 | u32 interval; | 5788 | u32 interval; |
5694 | enum ieee80211_band band; | 5789 | enum ieee80211_band band; |
@@ -5696,38 +5791,32 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5696 | struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1]; | 5791 | struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1]; |
5697 | s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF; | 5792 | s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF; |
5698 | 5793 | ||
5699 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || | 5794 | if (!is_valid_ie_attr(attrs[NL80211_ATTR_IE])) |
5700 | !rdev->ops->sched_scan_start) | 5795 | return ERR_PTR(-EINVAL); |
5701 | return -EOPNOTSUPP; | ||
5702 | |||
5703 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
5704 | return -EINVAL; | ||
5705 | 5796 | ||
5706 | if (!info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]) | 5797 | if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]) |
5707 | return -EINVAL; | 5798 | return ERR_PTR(-EINVAL); |
5708 | 5799 | ||
5709 | interval = nla_get_u32(info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]); | 5800 | interval = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]); |
5710 | if (interval == 0) | 5801 | if (interval == 0) |
5711 | return -EINVAL; | 5802 | return ERR_PTR(-EINVAL); |
5712 | |||
5713 | wiphy = &rdev->wiphy; | ||
5714 | 5803 | ||
5715 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { | 5804 | if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { |
5716 | n_channels = validate_scan_freqs( | 5805 | n_channels = validate_scan_freqs( |
5717 | info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); | 5806 | attrs[NL80211_ATTR_SCAN_FREQUENCIES]); |
5718 | if (!n_channels) | 5807 | if (!n_channels) |
5719 | return -EINVAL; | 5808 | return ERR_PTR(-EINVAL); |
5720 | } else { | 5809 | } else { |
5721 | n_channels = ieee80211_get_num_supported_channels(wiphy); | 5810 | n_channels = ieee80211_get_num_supported_channels(wiphy); |
5722 | } | 5811 | } |
5723 | 5812 | ||
5724 | if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) | 5813 | if (attrs[NL80211_ATTR_SCAN_SSIDS]) |
5725 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], | 5814 | nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS], |
5726 | tmp) | 5815 | tmp) |
5727 | n_ssids++; | 5816 | n_ssids++; |
5728 | 5817 | ||
5729 | if (n_ssids > wiphy->max_sched_scan_ssids) | 5818 | if (n_ssids > wiphy->max_sched_scan_ssids) |
5730 | return -EINVAL; | 5819 | return ERR_PTR(-EINVAL); |
5731 | 5820 | ||
5732 | /* | 5821 | /* |
5733 | * First, count the number of 'real' matchsets. Due to an issue with | 5822 | * First, count the number of 'real' matchsets. Due to an issue with |
@@ -5738,9 +5827,9 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5738 | * older userspace that treated a matchset with only the RSSI as the | 5827 | * older userspace that treated a matchset with only the RSSI as the |
5739 | * global RSSI for all other matchsets - if there are other matchsets. | 5828 | * global RSSI for all other matchsets - if there are other matchsets. |
5740 | */ | 5829 | */ |
5741 | if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) { | 5830 | if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) { |
5742 | nla_for_each_nested(attr, | 5831 | nla_for_each_nested(attr, |
5743 | info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], | 5832 | attrs[NL80211_ATTR_SCHED_SCAN_MATCH], |
5744 | tmp) { | 5833 | tmp) { |
5745 | struct nlattr *rssi; | 5834 | struct nlattr *rssi; |
5746 | 5835 | ||
@@ -5748,7 +5837,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5748 | nla_data(attr), nla_len(attr), | 5837 | nla_data(attr), nla_len(attr), |
5749 | nl80211_match_policy); | 5838 | nl80211_match_policy); |
5750 | if (err) | 5839 | if (err) |
5751 | return err; | 5840 | return ERR_PTR(err); |
5752 | /* add other standalone attributes here */ | 5841 | /* add other standalone attributes here */ |
5753 | if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]) { | 5842 | if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]) { |
5754 | n_match_sets++; | 5843 | n_match_sets++; |
@@ -5765,30 +5854,23 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5765 | n_match_sets = 1; | 5854 | n_match_sets = 1; |
5766 | 5855 | ||
5767 | if (n_match_sets > wiphy->max_match_sets) | 5856 | if (n_match_sets > wiphy->max_match_sets) |
5768 | return -EINVAL; | 5857 | return ERR_PTR(-EINVAL); |
5769 | 5858 | ||
5770 | if (info->attrs[NL80211_ATTR_IE]) | 5859 | if (attrs[NL80211_ATTR_IE]) |
5771 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 5860 | ie_len = nla_len(attrs[NL80211_ATTR_IE]); |
5772 | else | 5861 | else |
5773 | ie_len = 0; | 5862 | ie_len = 0; |
5774 | 5863 | ||
5775 | if (ie_len > wiphy->max_sched_scan_ie_len) | 5864 | if (ie_len > wiphy->max_sched_scan_ie_len) |
5776 | return -EINVAL; | 5865 | return ERR_PTR(-EINVAL); |
5777 | |||
5778 | if (rdev->sched_scan_req) { | ||
5779 | err = -EINPROGRESS; | ||
5780 | goto out; | ||
5781 | } | ||
5782 | 5866 | ||
5783 | request = kzalloc(sizeof(*request) | 5867 | request = kzalloc(sizeof(*request) |
5784 | + sizeof(*request->ssids) * n_ssids | 5868 | + sizeof(*request->ssids) * n_ssids |
5785 | + sizeof(*request->match_sets) * n_match_sets | 5869 | + sizeof(*request->match_sets) * n_match_sets |
5786 | + sizeof(*request->channels) * n_channels | 5870 | + sizeof(*request->channels) * n_channels |
5787 | + ie_len, GFP_KERNEL); | 5871 | + ie_len, GFP_KERNEL); |
5788 | if (!request) { | 5872 | if (!request) |
5789 | err = -ENOMEM; | 5873 | return ERR_PTR(-ENOMEM); |
5790 | goto out; | ||
5791 | } | ||
5792 | 5874 | ||
5793 | if (n_ssids) | 5875 | if (n_ssids) |
5794 | request->ssids = (void *)&request->channels[n_channels]; | 5876 | request->ssids = (void *)&request->channels[n_channels]; |
@@ -5813,10 +5895,10 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5813 | request->n_match_sets = n_match_sets; | 5895 | request->n_match_sets = n_match_sets; |
5814 | 5896 | ||
5815 | i = 0; | 5897 | i = 0; |
5816 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { | 5898 | if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { |
5817 | /* user specified, bail out if channel not found */ | 5899 | /* user specified, bail out if channel not found */ |
5818 | nla_for_each_nested(attr, | 5900 | nla_for_each_nested(attr, |
5819 | info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], | 5901 | attrs[NL80211_ATTR_SCAN_FREQUENCIES], |
5820 | tmp) { | 5902 | tmp) { |
5821 | struct ieee80211_channel *chan; | 5903 | struct ieee80211_channel *chan; |
5822 | 5904 | ||
@@ -5862,8 +5944,8 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5862 | request->n_channels = i; | 5944 | request->n_channels = i; |
5863 | 5945 | ||
5864 | i = 0; | 5946 | i = 0; |
5865 | if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) { | 5947 | if (attrs[NL80211_ATTR_SCAN_SSIDS]) { |
5866 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], | 5948 | nla_for_each_nested(attr, attrs[NL80211_ATTR_SCAN_SSIDS], |
5867 | tmp) { | 5949 | tmp) { |
5868 | if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) { | 5950 | if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) { |
5869 | err = -EINVAL; | 5951 | err = -EINVAL; |
@@ -5877,9 +5959,9 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5877 | } | 5959 | } |
5878 | 5960 | ||
5879 | i = 0; | 5961 | i = 0; |
5880 | if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) { | 5962 | if (attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) { |
5881 | nla_for_each_nested(attr, | 5963 | nla_for_each_nested(attr, |
5882 | info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], | 5964 | attrs[NL80211_ATTR_SCHED_SCAN_MATCH], |
5883 | tmp) { | 5965 | tmp) { |
5884 | struct nlattr *ssid, *rssi; | 5966 | struct nlattr *ssid, *rssi; |
5885 | 5967 | ||
@@ -5934,36 +6016,88 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5934 | if (ie_len) { | 6016 | if (ie_len) { |
5935 | request->ie_len = ie_len; | 6017 | request->ie_len = ie_len; |
5936 | memcpy((void *)request->ie, | 6018 | memcpy((void *)request->ie, |
5937 | nla_data(info->attrs[NL80211_ATTR_IE]), | 6019 | nla_data(attrs[NL80211_ATTR_IE]), |
5938 | request->ie_len); | 6020 | request->ie_len); |
5939 | } | 6021 | } |
5940 | 6022 | ||
5941 | if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) { | 6023 | if (attrs[NL80211_ATTR_SCAN_FLAGS]) { |
5942 | request->flags = nla_get_u32( | 6024 | request->flags = nla_get_u32( |
5943 | info->attrs[NL80211_ATTR_SCAN_FLAGS]); | 6025 | attrs[NL80211_ATTR_SCAN_FLAGS]); |
5944 | if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && | 6026 | if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && |
5945 | !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { | 6027 | !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { |
5946 | err = -EOPNOTSUPP; | 6028 | err = -EOPNOTSUPP; |
5947 | goto out_free; | 6029 | goto out_free; |
5948 | } | 6030 | } |
6031 | |||
6032 | if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { | ||
6033 | u32 flg = NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR; | ||
6034 | |||
6035 | if (!wdev) /* must be net-detect */ | ||
6036 | flg = NL80211_FEATURE_ND_RANDOM_MAC_ADDR; | ||
6037 | |||
6038 | if (!(wiphy->features & flg)) { | ||
6039 | err = -EOPNOTSUPP; | ||
6040 | goto out_free; | ||
6041 | } | ||
6042 | |||
6043 | if (wdev && wdev->current_bss) { | ||
6044 | err = -EOPNOTSUPP; | ||
6045 | goto out_free; | ||
6046 | } | ||
6047 | |||
6048 | err = nl80211_parse_random_mac(attrs, request->mac_addr, | ||
6049 | request->mac_addr_mask); | ||
6050 | if (err) | ||
6051 | goto out_free; | ||
6052 | } | ||
5949 | } | 6053 | } |
5950 | 6054 | ||
5951 | request->dev = dev; | ||
5952 | request->wiphy = &rdev->wiphy; | ||
5953 | request->interval = interval; | 6055 | request->interval = interval; |
5954 | request->scan_start = jiffies; | 6056 | request->scan_start = jiffies; |
5955 | 6057 | ||
5956 | err = rdev_sched_scan_start(rdev, dev, request); | 6058 | return request; |
5957 | if (!err) { | ||
5958 | rdev->sched_scan_req = request; | ||
5959 | nl80211_send_sched_scan(rdev, dev, | ||
5960 | NL80211_CMD_START_SCHED_SCAN); | ||
5961 | goto out; | ||
5962 | } | ||
5963 | 6059 | ||
5964 | out_free: | 6060 | out_free: |
5965 | kfree(request); | 6061 | kfree(request); |
5966 | out: | 6062 | return ERR_PTR(err); |
6063 | } | ||
6064 | |||
6065 | static int nl80211_start_sched_scan(struct sk_buff *skb, | ||
6066 | struct genl_info *info) | ||
6067 | { | ||
6068 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
6069 | struct net_device *dev = info->user_ptr[1]; | ||
6070 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
6071 | int err; | ||
6072 | |||
6073 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || | ||
6074 | !rdev->ops->sched_scan_start) | ||
6075 | return -EOPNOTSUPP; | ||
6076 | |||
6077 | if (rdev->sched_scan_req) | ||
6078 | return -EINPROGRESS; | ||
6079 | |||
6080 | rdev->sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev, | ||
6081 | info->attrs); | ||
6082 | err = PTR_ERR_OR_ZERO(rdev->sched_scan_req); | ||
6083 | if (err) | ||
6084 | goto out_err; | ||
6085 | |||
6086 | err = rdev_sched_scan_start(rdev, dev, rdev->sched_scan_req); | ||
6087 | if (err) | ||
6088 | goto out_free; | ||
6089 | |||
6090 | rdev->sched_scan_req->dev = dev; | ||
6091 | rdev->sched_scan_req->wiphy = &rdev->wiphy; | ||
6092 | |||
6093 | nl80211_send_sched_scan(rdev, dev, | ||
6094 | NL80211_CMD_START_SCHED_SCAN); | ||
6095 | return 0; | ||
6096 | |||
6097 | out_free: | ||
6098 | kfree(rdev->sched_scan_req); | ||
6099 | out_err: | ||
6100 | rdev->sched_scan_req = NULL; | ||
5967 | return err; | 6101 | return err; |
5968 | } | 6102 | } |
5969 | 6103 | ||
@@ -8681,6 +8815,39 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev, | |||
8681 | return 0; | 8815 | return 0; |
8682 | } | 8816 | } |
8683 | 8817 | ||
8818 | static int nl80211_parse_wowlan_nd(struct cfg80211_registered_device *rdev, | ||
8819 | const struct wiphy_wowlan_support *wowlan, | ||
8820 | struct nlattr *attr, | ||
8821 | struct cfg80211_wowlan *trig) | ||
8822 | { | ||
8823 | struct nlattr **tb; | ||
8824 | int err; | ||
8825 | |||
8826 | tb = kzalloc(NUM_NL80211_ATTR * sizeof(*tb), GFP_KERNEL); | ||
8827 | if (!tb) | ||
8828 | return -ENOMEM; | ||
8829 | |||
8830 | if (!(wowlan->flags & WIPHY_WOWLAN_NET_DETECT)) { | ||
8831 | err = -EOPNOTSUPP; | ||
8832 | goto out; | ||
8833 | } | ||
8834 | |||
8835 | err = nla_parse(tb, NL80211_ATTR_MAX, | ||
8836 | nla_data(attr), nla_len(attr), | ||
8837 | nl80211_policy); | ||
8838 | if (err) | ||
8839 | goto out; | ||
8840 | |||
8841 | trig->nd_config = nl80211_parse_sched_scan(&rdev->wiphy, NULL, tb); | ||
8842 | err = PTR_ERR_OR_ZERO(trig->nd_config); | ||
8843 | if (err) | ||
8844 | trig->nd_config = NULL; | ||
8845 | |||
8846 | out: | ||
8847 | kfree(tb); | ||
8848 | return err; | ||
8849 | } | ||
8850 | |||
8684 | static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | 8851 | static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) |
8685 | { | 8852 | { |
8686 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 8853 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -8826,6 +8993,14 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
8826 | goto error; | 8993 | goto error; |
8827 | } | 8994 | } |
8828 | 8995 | ||
8996 | if (tb[NL80211_WOWLAN_TRIG_NET_DETECT]) { | ||
8997 | err = nl80211_parse_wowlan_nd( | ||
8998 | rdev, wowlan, tb[NL80211_WOWLAN_TRIG_NET_DETECT], | ||
8999 | &new_triggers); | ||
9000 | if (err) | ||
9001 | goto error; | ||
9002 | } | ||
9003 | |||
8829 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL); | 9004 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL); |
8830 | if (!ntrig) { | 9005 | if (!ntrig) { |
8831 | err = -ENOMEM; | 9006 | err = -ENOMEM; |
@@ -9658,6 +9833,98 @@ static int nl80211_del_tx_ts(struct sk_buff *skb, struct genl_info *info) | |||
9658 | return err; | 9833 | return err; |
9659 | } | 9834 | } |
9660 | 9835 | ||
9836 | static int nl80211_tdls_channel_switch(struct sk_buff *skb, | ||
9837 | struct genl_info *info) | ||
9838 | { | ||
9839 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
9840 | struct net_device *dev = info->user_ptr[1]; | ||
9841 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
9842 | struct cfg80211_chan_def chandef = {}; | ||
9843 | const u8 *addr; | ||
9844 | u8 oper_class; | ||
9845 | int err; | ||
9846 | |||
9847 | if (!rdev->ops->tdls_channel_switch || | ||
9848 | !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH)) | ||
9849 | return -EOPNOTSUPP; | ||
9850 | |||
9851 | switch (dev->ieee80211_ptr->iftype) { | ||
9852 | case NL80211_IFTYPE_STATION: | ||
9853 | case NL80211_IFTYPE_P2P_CLIENT: | ||
9854 | break; | ||
9855 | default: | ||
9856 | return -EOPNOTSUPP; | ||
9857 | } | ||
9858 | |||
9859 | if (!info->attrs[NL80211_ATTR_MAC] || | ||
9860 | !info->attrs[NL80211_ATTR_OPER_CLASS]) | ||
9861 | return -EINVAL; | ||
9862 | |||
9863 | err = nl80211_parse_chandef(rdev, info, &chandef); | ||
9864 | if (err) | ||
9865 | return err; | ||
9866 | |||
9867 | /* | ||
9868 | * Don't allow wide channels on the 2.4Ghz band, as per IEEE802.11-2012 | ||
9869 | * section 10.22.6.2.1. Disallow 5/10Mhz channels as well for now, the | ||
9870 | * specification is not defined for them. | ||
9871 | */ | ||
9872 | if (chandef.chan->band == IEEE80211_BAND_2GHZ && | ||
9873 | chandef.width != NL80211_CHAN_WIDTH_20_NOHT && | ||
9874 | chandef.width != NL80211_CHAN_WIDTH_20) | ||
9875 | return -EINVAL; | ||
9876 | |||
9877 | /* we will be active on the TDLS link */ | ||
9878 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, wdev->iftype)) | ||
9879 | return -EINVAL; | ||
9880 | |||
9881 | /* don't allow switching to DFS channels */ | ||
9882 | if (cfg80211_chandef_dfs_required(wdev->wiphy, &chandef, wdev->iftype)) | ||
9883 | return -EINVAL; | ||
9884 | |||
9885 | addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
9886 | oper_class = nla_get_u8(info->attrs[NL80211_ATTR_OPER_CLASS]); | ||
9887 | |||
9888 | wdev_lock(wdev); | ||
9889 | err = rdev_tdls_channel_switch(rdev, dev, addr, oper_class, &chandef); | ||
9890 | wdev_unlock(wdev); | ||
9891 | |||
9892 | return err; | ||
9893 | } | ||
9894 | |||
9895 | static int nl80211_tdls_cancel_channel_switch(struct sk_buff *skb, | ||
9896 | struct genl_info *info) | ||
9897 | { | ||
9898 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
9899 | struct net_device *dev = info->user_ptr[1]; | ||
9900 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
9901 | const u8 *addr; | ||
9902 | |||
9903 | if (!rdev->ops->tdls_channel_switch || | ||
9904 | !rdev->ops->tdls_cancel_channel_switch || | ||
9905 | !(rdev->wiphy.features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH)) | ||
9906 | return -EOPNOTSUPP; | ||
9907 | |||
9908 | switch (dev->ieee80211_ptr->iftype) { | ||
9909 | case NL80211_IFTYPE_STATION: | ||
9910 | case NL80211_IFTYPE_P2P_CLIENT: | ||
9911 | break; | ||
9912 | default: | ||
9913 | return -EOPNOTSUPP; | ||
9914 | } | ||
9915 | |||
9916 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
9917 | return -EINVAL; | ||
9918 | |||
9919 | addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
9920 | |||
9921 | wdev_lock(wdev); | ||
9922 | rdev_tdls_cancel_channel_switch(rdev, dev, addr); | ||
9923 | wdev_unlock(wdev); | ||
9924 | |||
9925 | return 0; | ||
9926 | } | ||
9927 | |||
9661 | #define NL80211_FLAG_NEED_WIPHY 0x01 | 9928 | #define NL80211_FLAG_NEED_WIPHY 0x01 |
9662 | #define NL80211_FLAG_NEED_NETDEV 0x02 | 9929 | #define NL80211_FLAG_NEED_NETDEV 0x02 |
9663 | #define NL80211_FLAG_NEED_RTNL 0x04 | 9930 | #define NL80211_FLAG_NEED_RTNL 0x04 |
@@ -10456,6 +10723,22 @@ static const struct genl_ops nl80211_ops[] = { | |||
10456 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 10723 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
10457 | NL80211_FLAG_NEED_RTNL, | 10724 | NL80211_FLAG_NEED_RTNL, |
10458 | }, | 10725 | }, |
10726 | { | ||
10727 | .cmd = NL80211_CMD_TDLS_CHANNEL_SWITCH, | ||
10728 | .doit = nl80211_tdls_channel_switch, | ||
10729 | .policy = nl80211_policy, | ||
10730 | .flags = GENL_ADMIN_PERM, | ||
10731 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
10732 | NL80211_FLAG_NEED_RTNL, | ||
10733 | }, | ||
10734 | { | ||
10735 | .cmd = NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH, | ||
10736 | .doit = nl80211_tdls_cancel_channel_switch, | ||
10737 | .policy = nl80211_policy, | ||
10738 | .flags = GENL_ADMIN_PERM, | ||
10739 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
10740 | NL80211_FLAG_NEED_RTNL, | ||
10741 | }, | ||
10459 | }; | 10742 | }; |
10460 | 10743 | ||
10461 | /* notification functions */ | 10744 | /* notification functions */ |
@@ -11653,7 +11936,9 @@ EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); | |||
11653 | static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | 11936 | static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, |
11654 | struct net_device *netdev, | 11937 | struct net_device *netdev, |
11655 | struct cfg80211_chan_def *chandef, | 11938 | struct cfg80211_chan_def *chandef, |
11656 | gfp_t gfp) | 11939 | gfp_t gfp, |
11940 | enum nl80211_commands notif, | ||
11941 | u8 count) | ||
11657 | { | 11942 | { |
11658 | struct sk_buff *msg; | 11943 | struct sk_buff *msg; |
11659 | void *hdr; | 11944 | void *hdr; |
@@ -11662,7 +11947,7 @@ static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | |||
11662 | if (!msg) | 11947 | if (!msg) |
11663 | return; | 11948 | return; |
11664 | 11949 | ||
11665 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CH_SWITCH_NOTIFY); | 11950 | hdr = nl80211hdr_put(msg, 0, 0, 0, notif); |
11666 | if (!hdr) { | 11951 | if (!hdr) { |
11667 | nlmsg_free(msg); | 11952 | nlmsg_free(msg); |
11668 | return; | 11953 | return; |
@@ -11674,6 +11959,10 @@ static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | |||
11674 | if (nl80211_send_chandef(msg, chandef)) | 11959 | if (nl80211_send_chandef(msg, chandef)) |
11675 | goto nla_put_failure; | 11960 | goto nla_put_failure; |
11676 | 11961 | ||
11962 | if ((notif == NL80211_CMD_CH_SWITCH_STARTED_NOTIFY) && | ||
11963 | (nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT, count))) | ||
11964 | goto nla_put_failure; | ||
11965 | |||
11677 | genlmsg_end(msg, hdr); | 11966 | genlmsg_end(msg, hdr); |
11678 | 11967 | ||
11679 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, | 11968 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, |
@@ -11696,18 +11985,28 @@ void cfg80211_ch_switch_notify(struct net_device *dev, | |||
11696 | 11985 | ||
11697 | trace_cfg80211_ch_switch_notify(dev, chandef); | 11986 | trace_cfg80211_ch_switch_notify(dev, chandef); |
11698 | 11987 | ||
11699 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | ||
11700 | wdev->iftype != NL80211_IFTYPE_P2P_GO && | ||
11701 | wdev->iftype != NL80211_IFTYPE_ADHOC && | ||
11702 | wdev->iftype != NL80211_IFTYPE_MESH_POINT)) | ||
11703 | return; | ||
11704 | |||
11705 | wdev->chandef = *chandef; | 11988 | wdev->chandef = *chandef; |
11706 | wdev->preset_chandef = *chandef; | 11989 | wdev->preset_chandef = *chandef; |
11707 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); | 11990 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL, |
11991 | NL80211_CMD_CH_SWITCH_NOTIFY, 0); | ||
11708 | } | 11992 | } |
11709 | EXPORT_SYMBOL(cfg80211_ch_switch_notify); | 11993 | EXPORT_SYMBOL(cfg80211_ch_switch_notify); |
11710 | 11994 | ||
11995 | void cfg80211_ch_switch_started_notify(struct net_device *dev, | ||
11996 | struct cfg80211_chan_def *chandef, | ||
11997 | u8 count) | ||
11998 | { | ||
11999 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
12000 | struct wiphy *wiphy = wdev->wiphy; | ||
12001 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | ||
12002 | |||
12003 | trace_cfg80211_ch_switch_started_notify(dev, chandef); | ||
12004 | |||
12005 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL, | ||
12006 | NL80211_CMD_CH_SWITCH_STARTED_NOTIFY, count); | ||
12007 | } | ||
12008 | EXPORT_SYMBOL(cfg80211_ch_switch_started_notify); | ||
12009 | |||
11711 | void cfg80211_cqm_txe_notify(struct net_device *dev, | 12010 | void cfg80211_cqm_txe_notify(struct net_device *dev, |
11712 | const u8 *peer, u32 num_packets, | 12011 | const u8 *peer, u32 num_packets, |
11713 | u32 rate, u32 intvl, gfp_t gfp) | 12012 | u32 rate, u32 intvl, gfp_t gfp) |
@@ -11944,6 +12243,67 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy, | |||
11944 | EXPORT_SYMBOL(cfg80211_report_obss_beacon); | 12243 | EXPORT_SYMBOL(cfg80211_report_obss_beacon); |
11945 | 12244 | ||
11946 | #ifdef CONFIG_PM | 12245 | #ifdef CONFIG_PM |
12246 | static int cfg80211_net_detect_results(struct sk_buff *msg, | ||
12247 | struct cfg80211_wowlan_wakeup *wakeup) | ||
12248 | { | ||
12249 | struct cfg80211_wowlan_nd_info *nd = wakeup->net_detect; | ||
12250 | struct nlattr *nl_results, *nl_match, *nl_freqs; | ||
12251 | int i, j; | ||
12252 | |||
12253 | nl_results = nla_nest_start( | ||
12254 | msg, NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS); | ||
12255 | if (!nl_results) | ||
12256 | return -EMSGSIZE; | ||
12257 | |||
12258 | for (i = 0; i < nd->n_matches; i++) { | ||
12259 | struct cfg80211_wowlan_nd_match *match = nd->matches[i]; | ||
12260 | |||
12261 | nl_match = nla_nest_start(msg, i); | ||
12262 | if (!nl_match) | ||
12263 | break; | ||
12264 | |||
12265 | /* The SSID attribute is optional in nl80211, but for | ||
12266 | * simplicity reasons it's always present in the | ||
12267 | * cfg80211 structure. If a driver can't pass the | ||
12268 | * SSID, that needs to be changed. A zero length SSID | ||
12269 | * is still a valid SSID (wildcard), so it cannot be | ||
12270 | * used for this purpose. | ||
12271 | */ | ||
12272 | if (nla_put(msg, NL80211_ATTR_SSID, match->ssid.ssid_len, | ||
12273 | match->ssid.ssid)) { | ||
12274 | nla_nest_cancel(msg, nl_match); | ||
12275 | goto out; | ||
12276 | } | ||
12277 | |||
12278 | if (match->n_channels) { | ||
12279 | nl_freqs = nla_nest_start( | ||
12280 | msg, NL80211_ATTR_SCAN_FREQUENCIES); | ||
12281 | if (!nl_freqs) { | ||
12282 | nla_nest_cancel(msg, nl_match); | ||
12283 | goto out; | ||
12284 | } | ||
12285 | |||
12286 | for (j = 0; j < match->n_channels; j++) { | ||
12287 | if (nla_put_u32(msg, | ||
12288 | NL80211_ATTR_WIPHY_FREQ, | ||
12289 | match->channels[j])) { | ||
12290 | nla_nest_cancel(msg, nl_freqs); | ||
12291 | nla_nest_cancel(msg, nl_match); | ||
12292 | goto out; | ||
12293 | } | ||
12294 | } | ||
12295 | |||
12296 | nla_nest_end(msg, nl_freqs); | ||
12297 | } | ||
12298 | |||
12299 | nla_nest_end(msg, nl_match); | ||
12300 | } | ||
12301 | |||
12302 | out: | ||
12303 | nla_nest_end(msg, nl_results); | ||
12304 | return 0; | ||
12305 | } | ||
12306 | |||
11947 | void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, | 12307 | void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, |
11948 | struct cfg80211_wowlan_wakeup *wakeup, | 12308 | struct cfg80211_wowlan_wakeup *wakeup, |
11949 | gfp_t gfp) | 12309 | gfp_t gfp) |
@@ -12038,6 +12398,10 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, | |||
12038 | goto free_msg; | 12398 | goto free_msg; |
12039 | } | 12399 | } |
12040 | 12400 | ||
12401 | if (wakeup->net_detect && | ||
12402 | cfg80211_net_detect_results(msg, wakeup)) | ||
12403 | goto free_msg; | ||
12404 | |||
12041 | nla_nest_end(msg, reasons); | 12405 | nla_nest_end(msg, reasons); |
12042 | } | 12406 | } |
12043 | 12407 | ||
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 1b3864cd50ca..35cfb7134bdb 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h | |||
@@ -993,4 +993,28 @@ rdev_del_tx_ts(struct cfg80211_registered_device *rdev, | |||
993 | return ret; | 993 | return ret; |
994 | } | 994 | } |
995 | 995 | ||
996 | static inline int | ||
997 | rdev_tdls_channel_switch(struct cfg80211_registered_device *rdev, | ||
998 | struct net_device *dev, const u8 *addr, | ||
999 | u8 oper_class, struct cfg80211_chan_def *chandef) | ||
1000 | { | ||
1001 | int ret; | ||
1002 | |||
1003 | trace_rdev_tdls_channel_switch(&rdev->wiphy, dev, addr, oper_class, | ||
1004 | chandef); | ||
1005 | ret = rdev->ops->tdls_channel_switch(&rdev->wiphy, dev, addr, | ||
1006 | oper_class, chandef); | ||
1007 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
1008 | return ret; | ||
1009 | } | ||
1010 | |||
1011 | static inline void | ||
1012 | rdev_tdls_cancel_channel_switch(struct cfg80211_registered_device *rdev, | ||
1013 | struct net_device *dev, const u8 *addr) | ||
1014 | { | ||
1015 | trace_rdev_tdls_cancel_channel_switch(&rdev->wiphy, dev, addr); | ||
1016 | rdev->ops->tdls_cancel_channel_switch(&rdev->wiphy, dev, addr); | ||
1017 | trace_rdev_return_void(&rdev->wiphy); | ||
1018 | } | ||
1019 | |||
996 | #endif /* __CFG80211_RDEV_OPS */ | 1020 | #endif /* __CFG80211_RDEV_OPS */ |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index b725a31a4751..32d8310b0f85 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -573,8 +573,9 @@ static const struct ieee80211_regdomain *reg_get_regdomain(struct wiphy *wiphy) | |||
573 | return get_cfg80211_regdom(); | 573 | return get_cfg80211_regdom(); |
574 | } | 574 | } |
575 | 575 | ||
576 | unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, | 576 | static unsigned int |
577 | const struct ieee80211_reg_rule *rule) | 577 | reg_get_max_bandwidth_from_range(const struct ieee80211_regdomain *rd, |
578 | const struct ieee80211_reg_rule *rule) | ||
578 | { | 579 | { |
579 | const struct ieee80211_freq_range *freq_range = &rule->freq_range; | 580 | const struct ieee80211_freq_range *freq_range = &rule->freq_range; |
580 | const struct ieee80211_freq_range *freq_range_tmp; | 581 | const struct ieee80211_freq_range *freq_range_tmp; |
@@ -622,6 +623,27 @@ unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, | |||
622 | return end_freq - start_freq; | 623 | return end_freq - start_freq; |
623 | } | 624 | } |
624 | 625 | ||
626 | unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, | ||
627 | const struct ieee80211_reg_rule *rule) | ||
628 | { | ||
629 | unsigned int bw = reg_get_max_bandwidth_from_range(rd, rule); | ||
630 | |||
631 | if (rule->flags & NL80211_RRF_NO_160MHZ) | ||
632 | bw = min_t(unsigned int, bw, MHZ_TO_KHZ(80)); | ||
633 | if (rule->flags & NL80211_RRF_NO_80MHZ) | ||
634 | bw = min_t(unsigned int, bw, MHZ_TO_KHZ(40)); | ||
635 | |||
636 | /* | ||
637 | * HT40+/HT40- limits are handled per-channel. Only limit BW if both | ||
638 | * are not allowed. | ||
639 | */ | ||
640 | if (rule->flags & NL80211_RRF_NO_HT40MINUS && | ||
641 | rule->flags & NL80211_RRF_NO_HT40PLUS) | ||
642 | bw = min_t(unsigned int, bw, MHZ_TO_KHZ(20)); | ||
643 | |||
644 | return bw; | ||
645 | } | ||
646 | |||
625 | /* Sanity check on a regulatory rule */ | 647 | /* Sanity check on a regulatory rule */ |
626 | static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule) | 648 | static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule) |
627 | { | 649 | { |
@@ -946,6 +968,16 @@ static u32 map_regdom_flags(u32 rd_flags) | |||
946 | channel_flags |= IEEE80211_CHAN_NO_OFDM; | 968 | channel_flags |= IEEE80211_CHAN_NO_OFDM; |
947 | if (rd_flags & NL80211_RRF_NO_OUTDOOR) | 969 | if (rd_flags & NL80211_RRF_NO_OUTDOOR) |
948 | channel_flags |= IEEE80211_CHAN_INDOOR_ONLY; | 970 | channel_flags |= IEEE80211_CHAN_INDOOR_ONLY; |
971 | if (rd_flags & NL80211_RRF_GO_CONCURRENT) | ||
972 | channel_flags |= IEEE80211_CHAN_GO_CONCURRENT; | ||
973 | if (rd_flags & NL80211_RRF_NO_HT40MINUS) | ||
974 | channel_flags |= IEEE80211_CHAN_NO_HT40MINUS; | ||
975 | if (rd_flags & NL80211_RRF_NO_HT40PLUS) | ||
976 | channel_flags |= IEEE80211_CHAN_NO_HT40PLUS; | ||
977 | if (rd_flags & NL80211_RRF_NO_80MHZ) | ||
978 | channel_flags |= IEEE80211_CHAN_NO_80MHZ; | ||
979 | if (rd_flags & NL80211_RRF_NO_160MHZ) | ||
980 | channel_flags |= IEEE80211_CHAN_NO_160MHZ; | ||
949 | return channel_flags; | 981 | return channel_flags; |
950 | } | 982 | } |
951 | 983 | ||
@@ -1565,10 +1597,23 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1565 | if (max_bandwidth_khz < MHZ_TO_KHZ(160)) | 1597 | if (max_bandwidth_khz < MHZ_TO_KHZ(160)) |
1566 | bw_flags |= IEEE80211_CHAN_NO_160MHZ; | 1598 | bw_flags |= IEEE80211_CHAN_NO_160MHZ; |
1567 | 1599 | ||
1600 | chan->dfs_state_entered = jiffies; | ||
1601 | chan->dfs_state = NL80211_DFS_USABLE; | ||
1602 | |||
1603 | chan->beacon_found = false; | ||
1568 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; | 1604 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; |
1569 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); | 1605 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); |
1570 | chan->max_reg_power = chan->max_power = | 1606 | chan->max_reg_power = chan->max_power = |
1571 | (int) MBM_TO_DBM(power_rule->max_eirp); | 1607 | (int) MBM_TO_DBM(power_rule->max_eirp); |
1608 | |||
1609 | if (chan->flags & IEEE80211_CHAN_RADAR) { | ||
1610 | if (reg_rule->dfs_cac_ms) | ||
1611 | chan->dfs_cac_ms = reg_rule->dfs_cac_ms; | ||
1612 | else | ||
1613 | chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; | ||
1614 | } | ||
1615 | |||
1616 | chan->max_power = chan->max_reg_power; | ||
1572 | } | 1617 | } |
1573 | 1618 | ||
1574 | static void handle_band_custom(struct wiphy *wiphy, | 1619 | static void handle_band_custom(struct wiphy *wiphy, |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 277a85df910e..ad38910f7036 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -2032,6 +2032,48 @@ TRACE_EVENT(rdev_del_tx_ts, | |||
2032 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->tsid) | 2032 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->tsid) |
2033 | ); | 2033 | ); |
2034 | 2034 | ||
2035 | TRACE_EVENT(rdev_tdls_channel_switch, | ||
2036 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | ||
2037 | const u8 *addr, u8 oper_class, | ||
2038 | struct cfg80211_chan_def *chandef), | ||
2039 | TP_ARGS(wiphy, netdev, addr, oper_class, chandef), | ||
2040 | TP_STRUCT__entry( | ||
2041 | WIPHY_ENTRY | ||
2042 | NETDEV_ENTRY | ||
2043 | MAC_ENTRY(addr) | ||
2044 | __field(u8, oper_class) | ||
2045 | CHAN_DEF_ENTRY | ||
2046 | ), | ||
2047 | TP_fast_assign( | ||
2048 | WIPHY_ASSIGN; | ||
2049 | NETDEV_ASSIGN; | ||
2050 | MAC_ASSIGN(addr, addr); | ||
2051 | CHAN_DEF_ASSIGN(chandef); | ||
2052 | ), | ||
2053 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT | ||
2054 | " oper class %d, " CHAN_DEF_PR_FMT, | ||
2055 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(addr), | ||
2056 | __entry->oper_class, CHAN_DEF_PR_ARG) | ||
2057 | ); | ||
2058 | |||
2059 | TRACE_EVENT(rdev_tdls_cancel_channel_switch, | ||
2060 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | ||
2061 | const u8 *addr), | ||
2062 | TP_ARGS(wiphy, netdev, addr), | ||
2063 | TP_STRUCT__entry( | ||
2064 | WIPHY_ENTRY | ||
2065 | NETDEV_ENTRY | ||
2066 | MAC_ENTRY(addr) | ||
2067 | ), | ||
2068 | TP_fast_assign( | ||
2069 | WIPHY_ASSIGN; | ||
2070 | NETDEV_ASSIGN; | ||
2071 | MAC_ASSIGN(addr, addr); | ||
2072 | ), | ||
2073 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT, | ||
2074 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(addr)) | ||
2075 | ); | ||
2076 | |||
2035 | /************************************************************* | 2077 | /************************************************************* |
2036 | * cfg80211 exported functions traces * | 2078 | * cfg80211 exported functions traces * |
2037 | *************************************************************/ | 2079 | *************************************************************/ |
@@ -2355,6 +2397,22 @@ TRACE_EVENT(cfg80211_ch_switch_notify, | |||
2355 | NETDEV_PR_ARG, CHAN_DEF_PR_ARG) | 2397 | NETDEV_PR_ARG, CHAN_DEF_PR_ARG) |
2356 | ); | 2398 | ); |
2357 | 2399 | ||
2400 | TRACE_EVENT(cfg80211_ch_switch_started_notify, | ||
2401 | TP_PROTO(struct net_device *netdev, | ||
2402 | struct cfg80211_chan_def *chandef), | ||
2403 | TP_ARGS(netdev, chandef), | ||
2404 | TP_STRUCT__entry( | ||
2405 | NETDEV_ENTRY | ||
2406 | CHAN_DEF_ENTRY | ||
2407 | ), | ||
2408 | TP_fast_assign( | ||
2409 | NETDEV_ASSIGN; | ||
2410 | CHAN_DEF_ASSIGN(chandef); | ||
2411 | ), | ||
2412 | TP_printk(NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT, | ||
2413 | NETDEV_PR_ARG, CHAN_DEF_PR_ARG) | ||
2414 | ); | ||
2415 | |||
2358 | TRACE_EVENT(cfg80211_radar_event, | 2416 | TRACE_EVENT(cfg80211_radar_event, |
2359 | TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), | 2417 | TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), |
2360 | TP_ARGS(wiphy, chandef), | 2418 | TP_ARGS(wiphy, chandef), |