mirror of
https://github.com/torvalds/linux.git
synced 2026-06-03 12:03:54 +02:00
Quite a number of fixes still:
- mt76 (hadn't sent any fixes so far)
- RCU
- scanning
- decapsulation offload
- interface combinations
- rt2x00: build fix (bad function pointer prototype)
- cfg80211: prevent A-MSDU flipping attacks in mesh
- zd1211rw: prevent race ending with NULL ptr deref
- cfg80211/mac80211: more S1G fixes
- mwifiex: avoid WARN on certain RX frames
- mac80211:
- avoid stack data leak in WARN cases
- fix non-transmitted BSSID search
(on certain multi-BSSID APs)
- always initialize key list so driver
iteration won't crash
- fix monitor interface in device restart
- fix __free() annotation usage
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEpeA8sTs3M8SN2hR410qiO8sPaAAFAmhvr/IACgkQ10qiO8sP
aAB6axAAkDobxlyAB2SwqM9Es5JQcK/iAmQg3mdAsYxFGMRMz5nzzBszCfqAoAX/
2PQvODLfd14Bbfc5svWtWmUz/Fie0Agk6GavOr9zMtIPLJL6/Q7lInjhbZ4zCNiD
zxM2HjUzZMkomKHBfniiUPLd9WBQwrBKjvV5ub/f+w5ExCV+xILoP5+Mm42cPTCU
in96FKqe2j0TSXrrPBnmKwMlS93s2NRmzKdyO5U94q8kCZXbQ93mosLKqjH8dpW5
UGvcu1tY0gWqLR434UcBeCKEQhWsrgVq6YgmuBya2OlnQ0Z29lVsK6Jjf3bYuJJK
6+zJS0vp6yRYUehVukhqyosz4WtHoMbNZz6JMF+glzJTm2pheke3XByHWkNVvbhL
d6kTsMmtYkQHSFe9d3y54HO2eg910MnRSQwaxOA0id0FbcZ+57l7VpuNK6/Y8SF6
OvhPt6Rsm0zwtd4rCrdcnMJwxYLFMzdlFw3rkXgAoHrU5yXxlB7mG+Nbh6rAn5t9
VcT1iXqPZqsevgoGiWa0/VRd/U5sL/pXoV/7zigvOQZ78v6q2GJ5LD0Uwyx+0kMm
T+cIPxjMb9kGHfvKRQ1aGCUm97415CdMNBKFErkQIXYxAykstN0RXZ8Ad5ZB9ZUg
zL4TCThsWpSv0mJfVQD/KbgsBRMunnZNXiabJ40XIIFksLJHpO4=
=Gldt
-----END PGP SIGNATURE-----
Merge tag 'wireless-2025-07-10' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless
Johannes Berg says:
====================
Quite a number of fixes still:
- mt76 (hadn't sent any fixes so far)
- RCU
- scanning
- decapsulation offload
- interface combinations
- rt2x00: build fix (bad function pointer prototype)
- cfg80211: prevent A-MSDU flipping attacks in mesh
- zd1211rw: prevent race ending with NULL ptr deref
- cfg80211/mac80211: more S1G fixes
- mwifiex: avoid WARN on certain RX frames
- mac80211:
- avoid stack data leak in WARN cases
- fix non-transmitted BSSID search
(on certain multi-BSSID APs)
- always initialize key list so driver
iteration won't crash
- fix monitor interface in device restart
- fix __free() annotation usage
* tag 'wireless-2025-07-10' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless: (26 commits)
wifi: mac80211: add the virtual monitor after reconfig complete
wifi: mac80211: always initialize sdata::key_list
wifi: mac80211: Fix uninitialized variable with __free() in ieee80211_ml_epcs()
wifi: mt76: mt792x: Limit the concurrent STA and SoftAP to operate on the same channel
wifi: mt76: mt7925: Fix null-ptr-deref in mt7925_thermal_init()
wifi: mt76: fix queue assignment for deauth packets
wifi: mt76: add a wrapper for wcid access with validation
wifi: mt76: mt7921: prevent decap offload config before STA initialization
wifi: mt76: mt7925: prevent NULL pointer dereference in mt7925_sta_set_decap_offload()
wifi: mt76: mt7925: fix incorrect scan probe IE handling for hw_scan
wifi: mt76: mt7925: fix invalid array index in ssid assignment during hw scan
wifi: mt76: mt7925: fix the wrong config for tx interrupt
wifi: mt76: Remove RCU section in mt7996_mac_sta_rc_work()
wifi: mt76: Move RCU section in mt7996_mcu_add_rate_ctrl()
wifi: mt76: Move RCU section in mt7996_mcu_add_rate_ctrl_fixed()
wifi: mt76: Move RCU section in mt7996_mcu_set_fixed_field()
wifi: mt76: Assume __mt76_connac_mcu_alloc_sta_req runs in atomic context
wifi: prevent A-MSDU attacks in mesh networks
wifi: rt2x00: fix remove callback type mismatch
wifi: mac80211: reject VHT opmode for unsupported channel widths
...
====================
Link: https://patch.msgid.link/20250710122212.24272-3-johannes@sipsolutions.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
7ac5cc2616
|
|
@ -459,7 +459,9 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
|
|||
"auth: receive authentication from %pM\n",
|
||||
ieee_hdr->addr3);
|
||||
} else {
|
||||
if (!priv->wdev.connected)
|
||||
if (!priv->wdev.connected ||
|
||||
!ether_addr_equal(ieee_hdr->addr3,
|
||||
priv->curr_bss_params.bss_descriptor.mac_address))
|
||||
return 0;
|
||||
|
||||
if (ieee80211_is_deauth(ieee_hdr->frame_control)) {
|
||||
|
|
|
|||
|
|
@ -1224,6 +1224,16 @@ static inline int mt76_wed_dma_setup(struct mt76_dev *dev, struct mt76_queue *q,
|
|||
#define mt76_dereference(p, dev) \
|
||||
rcu_dereference_protected(p, lockdep_is_held(&(dev)->mutex))
|
||||
|
||||
static inline struct mt76_wcid *
|
||||
__mt76_wcid_ptr(struct mt76_dev *dev, u16 idx)
|
||||
{
|
||||
if (idx >= ARRAY_SIZE(dev->wcid))
|
||||
return NULL;
|
||||
return rcu_dereference(dev->wcid[idx]);
|
||||
}
|
||||
|
||||
#define mt76_wcid_ptr(dev, idx) __mt76_wcid_ptr(&(dev)->mt76, idx)
|
||||
|
||||
struct mt76_dev *mt76_alloc_device(struct device *pdev, unsigned int size,
|
||||
const struct ieee80211_ops *ops,
|
||||
const struct mt76_driver_ops *drv_ops);
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ mt7603_rx_loopback_skb(struct mt7603_dev *dev, struct sk_buff *skb)
|
|||
if (idx >= MT7603_WTBL_STA - 1)
|
||||
goto free;
|
||||
|
||||
wcid = rcu_dereference(dev->mt76.wcid[idx]);
|
||||
wcid = mt76_wcid_ptr(dev, idx);
|
||||
if (!wcid)
|
||||
goto free;
|
||||
|
||||
|
|
|
|||
|
|
@ -487,10 +487,7 @@ mt7603_rx_get_wcid(struct mt7603_dev *dev, u8 idx, bool unicast)
|
|||
struct mt7603_sta *sta;
|
||||
struct mt76_wcid *wcid;
|
||||
|
||||
if (idx >= MT7603_WTBL_SIZE)
|
||||
return NULL;
|
||||
|
||||
wcid = rcu_dereference(dev->mt76.wcid[idx]);
|
||||
wcid = mt76_wcid_ptr(dev, idx);
|
||||
if (unicast || !wcid)
|
||||
return wcid;
|
||||
|
||||
|
|
@ -1266,12 +1263,9 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data)
|
|||
if (pid == MT_PACKET_ID_NO_ACK)
|
||||
return;
|
||||
|
||||
if (wcidx >= MT7603_WTBL_SIZE)
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
|
||||
wcid = mt76_wcid_ptr(dev, wcidx);
|
||||
if (!wcid)
|
||||
goto out;
|
||||
|
||||
|
|
|
|||
|
|
@ -90,10 +90,7 @@ static struct mt76_wcid *mt7615_rx_get_wcid(struct mt7615_dev *dev,
|
|||
struct mt7615_sta *sta;
|
||||
struct mt76_wcid *wcid;
|
||||
|
||||
if (idx >= MT7615_WTBL_SIZE)
|
||||
return NULL;
|
||||
|
||||
wcid = rcu_dereference(dev->mt76.wcid[idx]);
|
||||
wcid = mt76_wcid_ptr(dev, idx);
|
||||
if (unicast || !wcid)
|
||||
return wcid;
|
||||
|
||||
|
|
@ -1504,7 +1501,7 @@ static void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data)
|
|||
|
||||
rcu_read_lock();
|
||||
|
||||
wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
|
||||
wcid = mt76_wcid_ptr(dev, wcidx);
|
||||
if (!wcid)
|
||||
goto out;
|
||||
|
||||
|
|
|
|||
|
|
@ -1172,7 +1172,7 @@ void mt76_connac2_txwi_free(struct mt76_dev *dev, struct mt76_txwi_cache *t,
|
|||
wcid_idx = wcid->idx;
|
||||
} else {
|
||||
wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
|
||||
wcid = rcu_dereference(dev->wcid[wcid_idx]);
|
||||
wcid = __mt76_wcid_ptr(dev, wcid_idx);
|
||||
|
||||
if (wcid && wcid->sta) {
|
||||
sta = container_of((void *)wcid, struct ieee80211_sta,
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@ __mt76_connac_mcu_alloc_sta_req(struct mt76_dev *dev, struct mt76_vif_link *mvif
|
|||
|
||||
mt76_connac_mcu_get_wlan_idx(dev, wcid, &hdr.wlan_idx_lo,
|
||||
&hdr.wlan_idx_hi);
|
||||
skb = mt76_mcu_msg_alloc(dev, NULL, len);
|
||||
skb = __mt76_mcu_msg_alloc(dev, NULL, len, len, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
|
@ -1740,8 +1740,8 @@ int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif,
|
|||
if (!sreq->ssids[i].ssid_len)
|
||||
continue;
|
||||
|
||||
req->ssids[i].ssid_len = cpu_to_le32(sreq->ssids[i].ssid_len);
|
||||
memcpy(req->ssids[i].ssid, sreq->ssids[i].ssid,
|
||||
req->ssids[n_ssids].ssid_len = cpu_to_le32(sreq->ssids[i].ssid_len);
|
||||
memcpy(req->ssids[n_ssids].ssid, sreq->ssids[i].ssid,
|
||||
sreq->ssids[i].ssid_len);
|
||||
n_ssids++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -262,10 +262,7 @@ mt76x02_rx_get_sta(struct mt76_dev *dev, u8 idx)
|
|||
{
|
||||
struct mt76_wcid *wcid;
|
||||
|
||||
if (idx >= MT76x02_N_WCIDS)
|
||||
return NULL;
|
||||
|
||||
wcid = rcu_dereference(dev->wcid[idx]);
|
||||
wcid = __mt76_wcid_ptr(dev, idx);
|
||||
if (!wcid)
|
||||
return NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -564,9 +564,7 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev,
|
|||
|
||||
rcu_read_lock();
|
||||
|
||||
if (stat->wcid < MT76x02_N_WCIDS)
|
||||
wcid = rcu_dereference(dev->mt76.wcid[stat->wcid]);
|
||||
|
||||
wcid = mt76_wcid_ptr(dev, stat->wcid);
|
||||
if (wcid && wcid->sta) {
|
||||
void *priv;
|
||||
|
||||
|
|
|
|||
|
|
@ -56,10 +56,7 @@ static struct mt76_wcid *mt7915_rx_get_wcid(struct mt7915_dev *dev,
|
|||
struct mt7915_sta *sta;
|
||||
struct mt76_wcid *wcid;
|
||||
|
||||
if (idx >= ARRAY_SIZE(dev->mt76.wcid))
|
||||
return NULL;
|
||||
|
||||
wcid = rcu_dereference(dev->mt76.wcid[idx]);
|
||||
wcid = mt76_wcid_ptr(dev, idx);
|
||||
if (unicast || !wcid)
|
||||
return wcid;
|
||||
|
||||
|
|
@ -917,7 +914,7 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
|
|||
u16 idx;
|
||||
|
||||
idx = FIELD_GET(MT_TX_FREE_WLAN_ID, info);
|
||||
wcid = rcu_dereference(dev->mt76.wcid[idx]);
|
||||
wcid = mt76_wcid_ptr(dev, idx);
|
||||
sta = wcid_to_sta(wcid);
|
||||
if (!sta)
|
||||
continue;
|
||||
|
|
@ -1013,12 +1010,9 @@ static void mt7915_mac_add_txs(struct mt7915_dev *dev, void *data)
|
|||
if (pid < MT_PACKET_ID_WED)
|
||||
return;
|
||||
|
||||
if (wcidx >= mt7915_wtbl_size(dev))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
|
||||
wcid = mt76_wcid_ptr(dev, wcidx);
|
||||
if (!wcid)
|
||||
goto out;
|
||||
|
||||
|
|
|
|||
|
|
@ -3986,7 +3986,7 @@ int mt7915_mcu_wed_wa_tx_stats(struct mt7915_dev *dev, u16 wlan_idx)
|
|||
|
||||
rcu_read_lock();
|
||||
|
||||
wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
|
||||
wcid = mt76_wcid_ptr(dev, wlan_idx);
|
||||
if (wcid)
|
||||
wcid->stats.tx_packets += le32_to_cpu(res->tx_packets);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -587,12 +587,9 @@ static void mt7915_mmio_wed_update_rx_stats(struct mtk_wed_device *wed,
|
|||
|
||||
dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed);
|
||||
|
||||
if (idx >= mt7915_wtbl_size(dev))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
wcid = rcu_dereference(dev->mt76.wcid[idx]);
|
||||
wcid = mt76_wcid_ptr(dev, idx);
|
||||
if (wcid) {
|
||||
wcid->stats.rx_bytes += le32_to_cpu(stats->rx_byte_cnt);
|
||||
wcid->stats.rx_packets += le32_to_cpu(stats->rx_pkt_cnt);
|
||||
|
|
|
|||
|
|
@ -465,7 +465,7 @@ void mt7921_mac_add_txs(struct mt792x_dev *dev, void *data)
|
|||
|
||||
rcu_read_lock();
|
||||
|
||||
wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
|
||||
wcid = mt76_wcid_ptr(dev, wcidx);
|
||||
if (!wcid)
|
||||
goto out;
|
||||
|
||||
|
|
@ -516,7 +516,7 @@ static void mt7921_mac_tx_free(struct mt792x_dev *dev, void *data, int len)
|
|||
|
||||
count++;
|
||||
idx = FIELD_GET(MT_TX_FREE_WLAN_ID, info);
|
||||
wcid = rcu_dereference(dev->mt76.wcid[idx]);
|
||||
wcid = mt76_wcid_ptr(dev, idx);
|
||||
sta = wcid_to_sta(wcid);
|
||||
if (!sta)
|
||||
continue;
|
||||
|
|
@ -816,7 +816,7 @@ void mt7921_usb_sdio_tx_complete_skb(struct mt76_dev *mdev,
|
|||
u16 idx;
|
||||
|
||||
idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
|
||||
wcid = rcu_dereference(mdev->wcid[idx]);
|
||||
wcid = __mt76_wcid_ptr(mdev, idx);
|
||||
sta = wcid_to_sta(wcid);
|
||||
|
||||
if (sta && likely(e->skb->protocol != cpu_to_be16(ETH_P_PAE)))
|
||||
|
|
|
|||
|
|
@ -1180,6 +1180,9 @@ static void mt7921_sta_set_decap_offload(struct ieee80211_hw *hw,
|
|||
struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
|
||||
struct mt792x_dev *dev = mt792x_hw_dev(hw);
|
||||
|
||||
if (!msta->deflink.wcid.sta)
|
||||
return;
|
||||
|
||||
mt792x_mutex_acquire(dev);
|
||||
|
||||
if (enabled)
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ static int mt7925_thermal_init(struct mt792x_phy *phy)
|
|||
|
||||
name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7925_%s",
|
||||
wiphy_name(wiphy));
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy,
|
||||
mt7925_hwmon_groups);
|
||||
|
|
|
|||
|
|
@ -1040,7 +1040,7 @@ void mt7925_mac_add_txs(struct mt792x_dev *dev, void *data)
|
|||
|
||||
rcu_read_lock();
|
||||
|
||||
wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
|
||||
wcid = mt76_wcid_ptr(dev, wcidx);
|
||||
if (!wcid)
|
||||
goto out;
|
||||
|
||||
|
|
@ -1122,7 +1122,7 @@ mt7925_mac_tx_free(struct mt792x_dev *dev, void *data, int len)
|
|||
u16 idx;
|
||||
|
||||
idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info);
|
||||
wcid = rcu_dereference(dev->mt76.wcid[idx]);
|
||||
wcid = mt76_wcid_ptr(dev, idx);
|
||||
sta = wcid_to_sta(wcid);
|
||||
if (!sta)
|
||||
continue;
|
||||
|
|
@ -1445,7 +1445,7 @@ void mt7925_usb_sdio_tx_complete_skb(struct mt76_dev *mdev,
|
|||
u16 idx;
|
||||
|
||||
idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
|
||||
wcid = rcu_dereference(mdev->wcid[idx]);
|
||||
wcid = __mt76_wcid_ptr(mdev, idx);
|
||||
sta = wcid_to_sta(wcid);
|
||||
|
||||
if (sta && likely(e->skb->protocol != cpu_to_be16(ETH_P_PAE)))
|
||||
|
|
|
|||
|
|
@ -1481,7 +1481,7 @@ mt7925_start_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
|||
|
||||
mt792x_mutex_acquire(dev);
|
||||
|
||||
err = mt7925_mcu_sched_scan_req(mphy, vif, req);
|
||||
err = mt7925_mcu_sched_scan_req(mphy, vif, req, ies);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
|
|
@ -1603,6 +1603,9 @@ static void mt7925_sta_set_decap_offload(struct ieee80211_hw *hw,
|
|||
unsigned long valid = mvif->valid_links;
|
||||
u8 i;
|
||||
|
||||
if (!msta->vif)
|
||||
return;
|
||||
|
||||
mt792x_mutex_acquire(dev);
|
||||
|
||||
valid = ieee80211_vif_is_mld(vif) ? mvif->valid_links : BIT(0);
|
||||
|
|
@ -1617,6 +1620,9 @@ static void mt7925_sta_set_decap_offload(struct ieee80211_hw *hw,
|
|||
else
|
||||
clear_bit(MT_WCID_FLAG_HDR_TRANS, &mlink->wcid.flags);
|
||||
|
||||
if (!mlink->wcid.sta)
|
||||
continue;
|
||||
|
||||
mt7925_mcu_wtbl_update_hdr_trans(dev, vif, sta, i);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ mt7925_connac_mcu_set_wow_ctrl(struct mt76_phy *phy, struct ieee80211_vif *vif,
|
|||
bool suspend, struct cfg80211_wowlan *wowlan)
|
||||
{
|
||||
struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;
|
||||
struct ieee80211_scan_ies ies = {};
|
||||
struct mt76_dev *dev = phy->dev;
|
||||
struct {
|
||||
struct {
|
||||
|
|
@ -194,7 +195,7 @@ mt7925_connac_mcu_set_wow_ctrl(struct mt76_phy *phy, struct ieee80211_vif *vif,
|
|||
req.wow_ctrl_tlv.trigger |= (UNI_WOW_DETECT_TYPE_DISCONNECT |
|
||||
UNI_WOW_DETECT_TYPE_BCN_LOST);
|
||||
if (wowlan->nd_config) {
|
||||
mt7925_mcu_sched_scan_req(phy, vif, wowlan->nd_config);
|
||||
mt7925_mcu_sched_scan_req(phy, vif, wowlan->nd_config, &ies);
|
||||
req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_SCH_SCAN_HIT;
|
||||
mt7925_mcu_sched_scan_enable(phy, vif, suspend);
|
||||
}
|
||||
|
|
@ -2818,6 +2819,54 @@ int mt7925_mcu_set_dbdc(struct mt76_phy *phy, bool enable)
|
|||
return err;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7925_mcu_build_scan_ie_tlv(struct mt76_dev *mdev,
|
||||
struct sk_buff *skb,
|
||||
struct ieee80211_scan_ies *scan_ies)
|
||||
{
|
||||
u32 max_len = sizeof(struct scan_ie_tlv) + MT76_CONNAC_SCAN_IE_LEN;
|
||||
struct scan_ie_tlv *ie;
|
||||
enum nl80211_band i;
|
||||
struct tlv *tlv;
|
||||
const u8 *ies;
|
||||
u16 ies_len;
|
||||
|
||||
for (i = 0; i <= NL80211_BAND_6GHZ; i++) {
|
||||
if (i == NL80211_BAND_60GHZ)
|
||||
continue;
|
||||
|
||||
ies = scan_ies->ies[i];
|
||||
ies_len = scan_ies->len[i];
|
||||
|
||||
if (!ies || !ies_len)
|
||||
continue;
|
||||
|
||||
if (ies_len > max_len)
|
||||
return;
|
||||
|
||||
tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_IE,
|
||||
sizeof(*ie) + ies_len);
|
||||
ie = (struct scan_ie_tlv *)tlv;
|
||||
|
||||
memcpy(ie->ies, ies, ies_len);
|
||||
ie->ies_len = cpu_to_le16(ies_len);
|
||||
|
||||
switch (i) {
|
||||
case NL80211_BAND_2GHZ:
|
||||
ie->band = 1;
|
||||
break;
|
||||
case NL80211_BAND_6GHZ:
|
||||
ie->band = 3;
|
||||
break;
|
||||
default:
|
||||
ie->band = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
max_len -= (sizeof(*ie) + ies_len);
|
||||
}
|
||||
}
|
||||
|
||||
int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif,
|
||||
struct ieee80211_scan_request *scan_req)
|
||||
{
|
||||
|
|
@ -2843,7 +2892,8 @@ int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif,
|
|||
|
||||
max_len = sizeof(*hdr) + sizeof(*req) + sizeof(*ssid) +
|
||||
sizeof(*bssid) * MT7925_RNR_SCAN_MAX_BSSIDS +
|
||||
sizeof(*chan_info) + sizeof(*misc) + sizeof(*ie);
|
||||
sizeof(*chan_info) + sizeof(*misc) + sizeof(*ie) +
|
||||
MT76_CONNAC_SCAN_IE_LEN;
|
||||
|
||||
skb = mt76_mcu_msg_alloc(mdev, NULL, max_len);
|
||||
if (!skb)
|
||||
|
|
@ -2869,8 +2919,8 @@ int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif,
|
|||
if (i > MT7925_RNR_SCAN_MAX_BSSIDS)
|
||||
break;
|
||||
|
||||
ssid->ssids[i].ssid_len = cpu_to_le32(sreq->ssids[i].ssid_len);
|
||||
memcpy(ssid->ssids[i].ssid, sreq->ssids[i].ssid,
|
||||
ssid->ssids[n_ssids].ssid_len = cpu_to_le32(sreq->ssids[i].ssid_len);
|
||||
memcpy(ssid->ssids[n_ssids].ssid, sreq->ssids[i].ssid,
|
||||
sreq->ssids[i].ssid_len);
|
||||
n_ssids++;
|
||||
}
|
||||
|
|
@ -2925,13 +2975,6 @@ int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif,
|
|||
}
|
||||
chan_info->channel_type = sreq->n_channels ? 4 : 0;
|
||||
|
||||
tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_IE, sizeof(*ie));
|
||||
ie = (struct scan_ie_tlv *)tlv;
|
||||
if (sreq->ie_len > 0) {
|
||||
memcpy(ie->ies, sreq->ie, sreq->ie_len);
|
||||
ie->ies_len = cpu_to_le16(sreq->ie_len);
|
||||
}
|
||||
|
||||
req->scan_func |= SCAN_FUNC_SPLIT_SCAN;
|
||||
|
||||
tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_MISC, sizeof(*misc));
|
||||
|
|
@ -2942,6 +2985,9 @@ int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif,
|
|||
req->scan_func |= SCAN_FUNC_RANDOM_MAC;
|
||||
}
|
||||
|
||||
/* Append scan probe IEs as the last tlv */
|
||||
mt7925_mcu_build_scan_ie_tlv(mdev, skb, &scan_req->ies);
|
||||
|
||||
err = mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(SCAN_REQ),
|
||||
true);
|
||||
if (err < 0)
|
||||
|
|
@ -2953,7 +2999,8 @@ EXPORT_SYMBOL_GPL(mt7925_mcu_hw_scan);
|
|||
|
||||
int mt7925_mcu_sched_scan_req(struct mt76_phy *phy,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_sched_scan_request *sreq)
|
||||
struct cfg80211_sched_scan_request *sreq,
|
||||
struct ieee80211_scan_ies *ies)
|
||||
{
|
||||
struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;
|
||||
struct ieee80211_channel **scan_list = sreq->channels;
|
||||
|
|
@ -3041,12 +3088,8 @@ int mt7925_mcu_sched_scan_req(struct mt76_phy *phy,
|
|||
}
|
||||
chan_info->channel_type = sreq->n_channels ? 4 : 0;
|
||||
|
||||
tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_IE, sizeof(*ie));
|
||||
ie = (struct scan_ie_tlv *)tlv;
|
||||
if (sreq->ie_len > 0) {
|
||||
memcpy(ie->ies, sreq->ie, sreq->ie_len);
|
||||
ie->ies_len = cpu_to_le16(sreq->ie_len);
|
||||
}
|
||||
/* Append scan probe IEs as the last tlv */
|
||||
mt7925_mcu_build_scan_ie_tlv(mdev, skb, ies);
|
||||
|
||||
return mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(SCAN_REQ),
|
||||
true);
|
||||
|
|
|
|||
|
|
@ -269,7 +269,7 @@ struct scan_ie_tlv {
|
|||
__le16 ies_len;
|
||||
u8 band;
|
||||
u8 pad;
|
||||
u8 ies[MT76_CONNAC_SCAN_IE_LEN];
|
||||
u8 ies[];
|
||||
};
|
||||
|
||||
struct scan_misc_tlv {
|
||||
|
|
@ -673,7 +673,8 @@ int mt7925_mcu_cancel_hw_scan(struct mt76_phy *phy,
|
|||
struct ieee80211_vif *vif);
|
||||
int mt7925_mcu_sched_scan_req(struct mt76_phy *phy,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_sched_scan_request *sreq);
|
||||
struct cfg80211_sched_scan_request *sreq,
|
||||
struct ieee80211_scan_ies *ies);
|
||||
int mt7925_mcu_sched_scan_enable(struct mt76_phy *phy,
|
||||
struct ieee80211_vif *vif,
|
||||
bool enable);
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@
|
|||
|
||||
#define MT_INT_TX_DONE_MCU (MT_INT_TX_DONE_MCU_WM | \
|
||||
MT_INT_TX_DONE_FWDL)
|
||||
#define MT_INT_TX_DONE_ALL (MT_INT_TX_DONE_MCU_WM | \
|
||||
#define MT_INT_TX_DONE_ALL (MT_INT_TX_DONE_MCU | \
|
||||
MT_INT_TX_DONE_BAND0 | \
|
||||
GENMASK(18, 4))
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ static const struct ieee80211_iface_combination if_comb[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static const struct ieee80211_iface_limit if_limits_chanctx[] = {
|
||||
static const struct ieee80211_iface_limit if_limits_chanctx_mcc[] = {
|
||||
{
|
||||
.max = 2,
|
||||
.types = BIT(NL80211_IFTYPE_STATION) |
|
||||
|
|
@ -36,8 +36,23 @@ static const struct ieee80211_iface_limit if_limits_chanctx[] = {
|
|||
},
|
||||
{
|
||||
.max = 1,
|
||||
.types = BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO)
|
||||
.types = BIT(NL80211_IFTYPE_P2P_GO)
|
||||
},
|
||||
{
|
||||
.max = 1,
|
||||
.types = BIT(NL80211_IFTYPE_P2P_DEVICE)
|
||||
}
|
||||
};
|
||||
|
||||
static const struct ieee80211_iface_limit if_limits_chanctx_scc[] = {
|
||||
{
|
||||
.max = 2,
|
||||
.types = BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT)
|
||||
},
|
||||
{
|
||||
.max = 1,
|
||||
.types = BIT(NL80211_IFTYPE_AP)
|
||||
},
|
||||
{
|
||||
.max = 1,
|
||||
|
|
@ -47,11 +62,18 @@ static const struct ieee80211_iface_limit if_limits_chanctx[] = {
|
|||
|
||||
static const struct ieee80211_iface_combination if_comb_chanctx[] = {
|
||||
{
|
||||
.limits = if_limits_chanctx,
|
||||
.n_limits = ARRAY_SIZE(if_limits_chanctx),
|
||||
.limits = if_limits_chanctx_mcc,
|
||||
.n_limits = ARRAY_SIZE(if_limits_chanctx_mcc),
|
||||
.max_interfaces = 3,
|
||||
.num_different_channels = 2,
|
||||
.beacon_int_infra_match = false,
|
||||
},
|
||||
{
|
||||
.limits = if_limits_chanctx_scc,
|
||||
.n_limits = ARRAY_SIZE(if_limits_chanctx_scc),
|
||||
.max_interfaces = 3,
|
||||
.num_different_channels = 1,
|
||||
.beacon_int_infra_match = false,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -142,10 +142,7 @@ struct mt76_wcid *mt792x_rx_get_wcid(struct mt792x_dev *dev, u16 idx,
|
|||
struct mt792x_sta *sta;
|
||||
struct mt76_wcid *wcid;
|
||||
|
||||
if (idx >= ARRAY_SIZE(dev->mt76.wcid))
|
||||
return NULL;
|
||||
|
||||
wcid = rcu_dereference(dev->mt76.wcid[idx]);
|
||||
wcid = mt76_wcid_ptr(dev, idx);
|
||||
if (unicast || !wcid)
|
||||
return wcid;
|
||||
|
||||
|
|
|
|||
|
|
@ -61,10 +61,7 @@ static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev,
|
|||
struct mt76_wcid *wcid;
|
||||
int i;
|
||||
|
||||
if (idx >= ARRAY_SIZE(dev->mt76.wcid))
|
||||
return NULL;
|
||||
|
||||
wcid = rcu_dereference(dev->mt76.wcid[idx]);
|
||||
wcid = mt76_wcid_ptr(dev, idx);
|
||||
if (!wcid)
|
||||
return NULL;
|
||||
|
||||
|
|
@ -1249,7 +1246,7 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
|
|||
u16 idx;
|
||||
|
||||
idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info);
|
||||
wcid = rcu_dereference(dev->mt76.wcid[idx]);
|
||||
wcid = mt76_wcid_ptr(dev, idx);
|
||||
sta = wcid_to_sta(wcid);
|
||||
if (!sta)
|
||||
goto next;
|
||||
|
|
@ -1471,12 +1468,9 @@ static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)
|
|||
if (pid < MT_PACKET_ID_NO_SKB)
|
||||
return;
|
||||
|
||||
if (wcidx >= mt7996_wtbl_size(dev))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
|
||||
wcid = mt76_wcid_ptr(dev, wcidx);
|
||||
if (!wcid)
|
||||
goto out;
|
||||
|
||||
|
|
@ -2353,20 +2347,12 @@ void mt7996_mac_update_stats(struct mt7996_phy *phy)
|
|||
void mt7996_mac_sta_rc_work(struct work_struct *work)
|
||||
{
|
||||
struct mt7996_dev *dev = container_of(work, struct mt7996_dev, rc_work);
|
||||
struct ieee80211_bss_conf *link_conf;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
struct mt7996_sta_link *msta_link;
|
||||
struct mt7996_vif_link *link;
|
||||
struct mt76_vif_link *mlink;
|
||||
struct ieee80211_sta *sta;
|
||||
struct ieee80211_vif *vif;
|
||||
struct mt7996_sta *msta;
|
||||
struct mt7996_vif *mvif;
|
||||
LIST_HEAD(list);
|
||||
u32 changed;
|
||||
u8 link_id;
|
||||
|
||||
rcu_read_lock();
|
||||
spin_lock_bh(&dev->mt76.sta_poll_lock);
|
||||
list_splice_init(&dev->sta_rc_list, &list);
|
||||
|
||||
|
|
@ -2377,46 +2363,28 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
|
|||
|
||||
changed = msta_link->changed;
|
||||
msta_link->changed = 0;
|
||||
|
||||
sta = wcid_to_sta(&msta_link->wcid);
|
||||
link_id = msta_link->wcid.link_id;
|
||||
msta = msta_link->sta;
|
||||
mvif = msta->vif;
|
||||
vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv);
|
||||
|
||||
mlink = rcu_dereference(mvif->mt76.link[link_id]);
|
||||
if (!mlink)
|
||||
continue;
|
||||
|
||||
link_sta = rcu_dereference(sta->link[link_id]);
|
||||
if (!link_sta)
|
||||
continue;
|
||||
|
||||
link_conf = rcu_dereference(vif->link_conf[link_id]);
|
||||
if (!link_conf)
|
||||
continue;
|
||||
mvif = msta_link->sta->vif;
|
||||
vif = container_of((void *)mvif, struct ieee80211_vif,
|
||||
drv_priv);
|
||||
|
||||
spin_unlock_bh(&dev->mt76.sta_poll_lock);
|
||||
|
||||
link = (struct mt7996_vif_link *)mlink;
|
||||
|
||||
if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED |
|
||||
IEEE80211_RC_NSS_CHANGED |
|
||||
IEEE80211_RC_BW_CHANGED))
|
||||
mt7996_mcu_add_rate_ctrl(dev, vif, link_conf,
|
||||
link_sta, link, msta_link,
|
||||
mt7996_mcu_add_rate_ctrl(dev, msta_link->sta, vif,
|
||||
msta_link->wcid.link_id,
|
||||
true);
|
||||
|
||||
if (changed & IEEE80211_RC_SMPS_CHANGED)
|
||||
mt7996_mcu_set_fixed_field(dev, link_sta, link,
|
||||
msta_link, NULL,
|
||||
mt7996_mcu_set_fixed_field(dev, msta_link->sta, NULL,
|
||||
msta_link->wcid.link_id,
|
||||
RATE_PARAM_MMPS_UPDATE);
|
||||
|
||||
spin_lock_bh(&dev->mt76.sta_poll_lock);
|
||||
}
|
||||
|
||||
spin_unlock_bh(&dev->mt76.sta_poll_lock);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void mt7996_mac_work(struct work_struct *work)
|
||||
|
|
|
|||
|
|
@ -1112,9 +1112,8 @@ mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
err = mt7996_mcu_add_rate_ctrl(dev, vif, link_conf,
|
||||
link_sta, link,
|
||||
msta_link, false);
|
||||
err = mt7996_mcu_add_rate_ctrl(dev, msta_link->sta, vif,
|
||||
link_id, false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
|
|||
|
|
@ -555,7 +555,7 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
|
|||
switch (le16_to_cpu(res->tag)) {
|
||||
case UNI_ALL_STA_TXRX_RATE:
|
||||
wlan_idx = le16_to_cpu(res->rate[i].wlan_idx);
|
||||
wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
|
||||
wcid = mt76_wcid_ptr(dev, wlan_idx);
|
||||
|
||||
if (!wcid)
|
||||
break;
|
||||
|
|
@ -565,7 +565,7 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
|
|||
break;
|
||||
case UNI_ALL_STA_TXRX_ADM_STAT:
|
||||
wlan_idx = le16_to_cpu(res->adm_stat[i].wlan_idx);
|
||||
wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
|
||||
wcid = mt76_wcid_ptr(dev, wlan_idx);
|
||||
|
||||
if (!wcid)
|
||||
break;
|
||||
|
|
@ -579,7 +579,7 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
|
|||
break;
|
||||
case UNI_ALL_STA_TXRX_MSDU_COUNT:
|
||||
wlan_idx = le16_to_cpu(res->msdu_cnt[i].wlan_idx);
|
||||
wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
|
||||
wcid = mt76_wcid_ptr(dev, wlan_idx);
|
||||
|
||||
if (!wcid)
|
||||
break;
|
||||
|
|
@ -676,10 +676,7 @@ mt7996_mcu_wed_rro_event(struct mt7996_dev *dev, struct sk_buff *skb)
|
|||
|
||||
e = (void *)skb->data;
|
||||
idx = le16_to_cpu(e->wlan_id);
|
||||
if (idx >= ARRAY_SIZE(dev->mt76.wcid))
|
||||
break;
|
||||
|
||||
wcid = rcu_dereference(dev->mt76.wcid[idx]);
|
||||
wcid = mt76_wcid_ptr(dev, idx);
|
||||
if (!wcid || !wcid->sta)
|
||||
break;
|
||||
|
||||
|
|
@ -1905,22 +1902,35 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
|
|||
MCU_WM_UNI_CMD(RA), true);
|
||||
}
|
||||
|
||||
int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev,
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
struct mt7996_vif_link *link,
|
||||
struct mt7996_sta_link *msta_link,
|
||||
void *data, u32 field)
|
||||
int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct mt7996_sta *msta,
|
||||
void *data, u8 link_id, u32 field)
|
||||
{
|
||||
struct sta_phy_uni *phy = data;
|
||||
struct mt7996_vif *mvif = msta->vif;
|
||||
struct mt7996_sta_link *msta_link;
|
||||
struct sta_rec_ra_fixed_uni *ra;
|
||||
struct sta_phy_uni *phy = data;
|
||||
struct mt76_vif_link *mlink;
|
||||
struct sk_buff *skb;
|
||||
int err = -ENODEV;
|
||||
struct tlv *tlv;
|
||||
|
||||
skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &link->mt76,
|
||||
rcu_read_lock();
|
||||
|
||||
mlink = rcu_dereference(mvif->mt76.link[link_id]);
|
||||
if (!mlink)
|
||||
goto error_unlock;
|
||||
|
||||
msta_link = rcu_dereference(msta->link[link_id]);
|
||||
if (!msta_link)
|
||||
goto error_unlock;
|
||||
|
||||
skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, mlink,
|
||||
&msta_link->wcid,
|
||||
MT7996_STA_UPDATE_MAX_SIZE);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
if (IS_ERR(skb)) {
|
||||
err = PTR_ERR(skb);
|
||||
goto error_unlock;
|
||||
}
|
||||
|
||||
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA_UPDATE, sizeof(*ra));
|
||||
ra = (struct sta_rec_ra_fixed_uni *)tlv;
|
||||
|
|
@ -1935,106 +1945,149 @@ int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev,
|
|||
if (phy)
|
||||
ra->phy = *phy;
|
||||
break;
|
||||
case RATE_PARAM_MMPS_UPDATE:
|
||||
case RATE_PARAM_MMPS_UPDATE: {
|
||||
struct ieee80211_sta *sta = wcid_to_sta(&msta_link->wcid);
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
|
||||
link_sta = rcu_dereference(sta->link[link_id]);
|
||||
if (!link_sta) {
|
||||
dev_kfree_skb(skb);
|
||||
goto error_unlock;
|
||||
}
|
||||
|
||||
ra->mmps_mode = mt7996_mcu_get_mmps_mode(link_sta->smps_mode);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ra->field = cpu_to_le32(field);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
return mt76_mcu_skb_send_msg(&dev->mt76, skb,
|
||||
MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
|
||||
error_unlock:
|
||||
rcu_read_unlock();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev,
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
struct mt7996_vif_link *link,
|
||||
struct mt7996_sta_link *msta_link)
|
||||
mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct mt7996_sta *msta,
|
||||
struct ieee80211_vif *vif, u8 link_id)
|
||||
{
|
||||
struct cfg80211_chan_def *chandef = &link->phy->mt76->chandef;
|
||||
struct cfg80211_bitrate_mask *mask = &link->bitrate_mask;
|
||||
enum nl80211_band band = chandef->chan->band;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
struct cfg80211_bitrate_mask mask;
|
||||
struct mt7996_sta_link *msta_link;
|
||||
struct mt7996_vif_link *link;
|
||||
struct sta_phy_uni phy = {};
|
||||
int ret, nrates = 0;
|
||||
struct ieee80211_sta *sta;
|
||||
int ret, nrates = 0, idx;
|
||||
enum nl80211_band band;
|
||||
bool has_he;
|
||||
|
||||
#define __sta_phy_bitrate_mask_check(_mcs, _gi, _ht, _he) \
|
||||
do { \
|
||||
u8 i, gi = mask->control[band]._gi; \
|
||||
u8 i, gi = mask.control[band]._gi; \
|
||||
gi = (_he) ? gi : gi == NL80211_TXRATE_FORCE_SGI; \
|
||||
phy.sgi = gi; \
|
||||
phy.he_ltf = mask->control[band].he_ltf; \
|
||||
for (i = 0; i < ARRAY_SIZE(mask->control[band]._mcs); i++) { \
|
||||
if (!mask->control[band]._mcs[i]) \
|
||||
phy.he_ltf = mask.control[band].he_ltf; \
|
||||
for (i = 0; i < ARRAY_SIZE(mask.control[band]._mcs); i++) { \
|
||||
if (!mask.control[band]._mcs[i]) \
|
||||
continue; \
|
||||
nrates += hweight16(mask->control[band]._mcs[i]); \
|
||||
phy.mcs = ffs(mask->control[band]._mcs[i]) - 1; \
|
||||
nrates += hweight16(mask.control[band]._mcs[i]); \
|
||||
phy.mcs = ffs(mask.control[band]._mcs[i]) - 1; \
|
||||
if (_ht) \
|
||||
phy.mcs += 8 * i; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
if (link_sta->he_cap.has_he) {
|
||||
rcu_read_lock();
|
||||
|
||||
link = mt7996_vif_link(dev, vif, link_id);
|
||||
if (!link)
|
||||
goto error_unlock;
|
||||
|
||||
msta_link = rcu_dereference(msta->link[link_id]);
|
||||
if (!msta_link)
|
||||
goto error_unlock;
|
||||
|
||||
sta = wcid_to_sta(&msta_link->wcid);
|
||||
link_sta = rcu_dereference(sta->link[link_id]);
|
||||
if (!link_sta)
|
||||
goto error_unlock;
|
||||
|
||||
band = link->phy->mt76->chandef.chan->band;
|
||||
has_he = link_sta->he_cap.has_he;
|
||||
mask = link->bitrate_mask;
|
||||
idx = msta_link->wcid.idx;
|
||||
|
||||
if (has_he) {
|
||||
__sta_phy_bitrate_mask_check(he_mcs, he_gi, 0, 1);
|
||||
} else if (link_sta->vht_cap.vht_supported) {
|
||||
__sta_phy_bitrate_mask_check(vht_mcs, gi, 0, 0);
|
||||
} else if (link_sta->ht_cap.ht_supported) {
|
||||
__sta_phy_bitrate_mask_check(ht_mcs, gi, 1, 0);
|
||||
} else {
|
||||
nrates = hweight32(mask->control[band].legacy);
|
||||
phy.mcs = ffs(mask->control[band].legacy) - 1;
|
||||
nrates = hweight32(mask.control[band].legacy);
|
||||
phy.mcs = ffs(mask.control[band].legacy) - 1;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
#undef __sta_phy_bitrate_mask_check
|
||||
|
||||
/* fall back to auto rate control */
|
||||
if (mask->control[band].gi == NL80211_TXRATE_DEFAULT_GI &&
|
||||
mask->control[band].he_gi == GENMASK(7, 0) &&
|
||||
mask->control[band].he_ltf == GENMASK(7, 0) &&
|
||||
if (mask.control[band].gi == NL80211_TXRATE_DEFAULT_GI &&
|
||||
mask.control[band].he_gi == GENMASK(7, 0) &&
|
||||
mask.control[band].he_ltf == GENMASK(7, 0) &&
|
||||
nrates != 1)
|
||||
return 0;
|
||||
|
||||
/* fixed single rate */
|
||||
if (nrates == 1) {
|
||||
ret = mt7996_mcu_set_fixed_field(dev, link_sta, link,
|
||||
msta_link, &phy,
|
||||
ret = mt7996_mcu_set_fixed_field(dev, msta, &phy, link_id,
|
||||
RATE_PARAM_FIXED_MCS);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* fixed GI */
|
||||
if (mask->control[band].gi != NL80211_TXRATE_DEFAULT_GI ||
|
||||
mask->control[band].he_gi != GENMASK(7, 0)) {
|
||||
if (mask.control[band].gi != NL80211_TXRATE_DEFAULT_GI ||
|
||||
mask.control[band].he_gi != GENMASK(7, 0)) {
|
||||
u32 addr;
|
||||
|
||||
/* firmware updates only TXCMD but doesn't take WTBL into
|
||||
* account, so driver should update here to reflect the
|
||||
* actual txrate hardware sends out.
|
||||
*/
|
||||
addr = mt7996_mac_wtbl_lmac_addr(dev, msta_link->wcid.idx, 7);
|
||||
if (link_sta->he_cap.has_he)
|
||||
addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 7);
|
||||
if (has_he)
|
||||
mt76_rmw_field(dev, addr, GENMASK(31, 24), phy.sgi);
|
||||
else
|
||||
mt76_rmw_field(dev, addr, GENMASK(15, 12), phy.sgi);
|
||||
|
||||
ret = mt7996_mcu_set_fixed_field(dev, link_sta, link,
|
||||
msta_link, &phy,
|
||||
ret = mt7996_mcu_set_fixed_field(dev, msta, &phy, link_id,
|
||||
RATE_PARAM_FIXED_GI);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* fixed HE_LTF */
|
||||
if (mask->control[band].he_ltf != GENMASK(7, 0)) {
|
||||
ret = mt7996_mcu_set_fixed_field(dev, link_sta, link,
|
||||
msta_link, &phy,
|
||||
if (mask.control[band].he_ltf != GENMASK(7, 0)) {
|
||||
ret = mt7996_mcu_set_fixed_field(dev, msta, &phy, link_id,
|
||||
RATE_PARAM_FIXED_HE_LTF);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_unlock:
|
||||
rcu_read_unlock();
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -2145,21 +2198,44 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,
|
|||
memset(ra->rx_rcpi, INIT_RCPI, sizeof(ra->rx_rcpi));
|
||||
}
|
||||
|
||||
int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *link_conf,
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
struct mt7996_vif_link *link,
|
||||
struct mt7996_sta_link *msta_link, bool changed)
|
||||
int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct mt7996_sta *msta,
|
||||
struct ieee80211_vif *vif, u8 link_id,
|
||||
bool changed)
|
||||
{
|
||||
struct ieee80211_bss_conf *link_conf;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
struct mt7996_sta_link *msta_link;
|
||||
struct mt7996_vif_link *link;
|
||||
struct ieee80211_sta *sta;
|
||||
struct sk_buff *skb;
|
||||
int ret;
|
||||
int ret = -ENODEV;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
link = mt7996_vif_link(dev, vif, link_id);
|
||||
if (!link)
|
||||
goto error_unlock;
|
||||
|
||||
msta_link = rcu_dereference(msta->link[link_id]);
|
||||
if (!msta_link)
|
||||
goto error_unlock;
|
||||
|
||||
sta = wcid_to_sta(&msta_link->wcid);
|
||||
link_sta = rcu_dereference(sta->link[link_id]);
|
||||
if (!link_sta)
|
||||
goto error_unlock;
|
||||
|
||||
link_conf = rcu_dereference(vif->link_conf[link_id]);
|
||||
if (!link_conf)
|
||||
goto error_unlock;
|
||||
|
||||
skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &link->mt76,
|
||||
&msta_link->wcid,
|
||||
MT7996_STA_UPDATE_MAX_SIZE);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
if (IS_ERR(skb)) {
|
||||
ret = PTR_ERR(skb);
|
||||
goto error_unlock;
|
||||
}
|
||||
|
||||
/* firmware rc algorithm refers to sta_rec_he for HE control.
|
||||
* once dev->rc_work changes the settings driver should also
|
||||
|
|
@ -2173,12 +2249,19 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev,
|
|||
*/
|
||||
mt7996_mcu_sta_rate_ctrl_tlv(skb, dev, vif, link_conf, link_sta, link);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
|
||||
MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return mt7996_mcu_add_rate_ctrl_fixed(dev, link_sta, link, msta_link);
|
||||
return mt7996_mcu_add_rate_ctrl_fixed(dev, msta, vif, link_id);
|
||||
|
||||
error_unlock:
|
||||
rcu_read_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
|||
|
|
@ -620,23 +620,17 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev,
|
|||
int mt7996_mcu_add_obss_spr(struct mt7996_phy *phy,
|
||||
struct mt7996_vif_link *link,
|
||||
struct ieee80211_he_obss_pd *he_obss_pd);
|
||||
int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *link_conf,
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
struct mt7996_vif_link *link,
|
||||
struct mt7996_sta_link *msta_link, bool changed);
|
||||
int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct mt7996_sta *msta,
|
||||
struct ieee80211_vif *vif, u8 link_id,
|
||||
bool changed);
|
||||
int mt7996_set_channel(struct mt76_phy *mphy);
|
||||
int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag);
|
||||
int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *link_conf);
|
||||
int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
|
||||
void *data, u16 version);
|
||||
int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev,
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
struct mt7996_vif_link *link,
|
||||
struct mt7996_sta_link *msta_link,
|
||||
void *data, u32 field);
|
||||
int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct mt7996_sta *msta,
|
||||
void *data, u8 link_id, u32 field);
|
||||
int mt7996_mcu_set_eeprom(struct mt7996_dev *dev);
|
||||
int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len);
|
||||
int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num);
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ mt76_tx_status_unlock(struct mt76_dev *dev, struct sk_buff_head *list)
|
|||
struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
|
||||
struct mt76_wcid *wcid;
|
||||
|
||||
wcid = rcu_dereference(dev->wcid[cb->wcid]);
|
||||
wcid = __mt76_wcid_ptr(dev, cb->wcid);
|
||||
if (wcid) {
|
||||
status.sta = wcid_to_sta(wcid);
|
||||
if (status.sta && (wcid->rate.flags || wcid->rate.legacy)) {
|
||||
|
|
@ -251,9 +251,7 @@ void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *
|
|||
|
||||
rcu_read_lock();
|
||||
|
||||
if (wcid_idx < ARRAY_SIZE(dev->wcid))
|
||||
wcid = rcu_dereference(dev->wcid[wcid_idx]);
|
||||
|
||||
wcid = __mt76_wcid_ptr(dev, wcid_idx);
|
||||
mt76_tx_check_non_aql(dev, wcid, skb);
|
||||
|
||||
#ifdef CONFIG_NL80211_TESTMODE
|
||||
|
|
@ -538,7 +536,7 @@ mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid)
|
|||
break;
|
||||
|
||||
mtxq = (struct mt76_txq *)txq->drv_priv;
|
||||
wcid = rcu_dereference(dev->wcid[mtxq->wcid]);
|
||||
wcid = __mt76_wcid_ptr(dev, mtxq->wcid);
|
||||
if (!wcid || test_bit(MT_WCID_FLAG_PS, &wcid->flags))
|
||||
continue;
|
||||
|
||||
|
|
@ -617,7 +615,8 @@ mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid,
|
|||
if ((dev->drv->drv_flags & MT_DRV_HW_MGMT_TXQ) &&
|
||||
!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
|
||||
!ieee80211_is_data(hdr->frame_control) &&
|
||||
!ieee80211_is_bufferable_mmpdu(skb))
|
||||
(!ieee80211_is_bufferable_mmpdu(skb) ||
|
||||
ieee80211_is_deauth(hdr->frame_control)))
|
||||
qid = MT_TXQ_PSD;
|
||||
|
||||
q = phy->q_tx[qid];
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ int mt76_get_min_avg_rssi(struct mt76_dev *dev, u8 phy_idx)
|
|||
if (!(mask & 1))
|
||||
continue;
|
||||
|
||||
wcid = rcu_dereference(dev->wcid[j]);
|
||||
wcid = __mt76_wcid_ptr(dev, j);
|
||||
if (!wcid || wcid->phy_idx != phy_idx)
|
||||
continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00soc_probe);
|
||||
|
||||
int rt2x00soc_remove(struct platform_device *pdev)
|
||||
void rt2x00soc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ieee80211_hw *hw = platform_get_drvdata(pdev);
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
|
|
@ -119,8 +119,6 @@ int rt2x00soc_remove(struct platform_device *pdev)
|
|||
rt2x00lib_remove_dev(rt2x00dev);
|
||||
rt2x00soc_free_reg(rt2x00dev);
|
||||
ieee80211_free_hw(hw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00soc_remove);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
* SoC driver handlers.
|
||||
*/
|
||||
int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops);
|
||||
int rt2x00soc_remove(struct platform_device *pdev);
|
||||
void rt2x00soc_remove(struct platform_device *pdev);
|
||||
#ifdef CONFIG_PM
|
||||
int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state);
|
||||
int rt2x00soc_resume(struct platform_device *pdev);
|
||||
|
|
|
|||
|
|
@ -583,7 +583,11 @@ void zd_mac_tx_to_dev(struct sk_buff *skb, int error)
|
|||
|
||||
skb_queue_tail(q, skb);
|
||||
while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS) {
|
||||
zd_mac_tx_status(hw, skb_dequeue(q),
|
||||
skb = skb_dequeue(q);
|
||||
if (!skb)
|
||||
break;
|
||||
|
||||
zd_mac_tx_status(hw, skb,
|
||||
mac->ack_pending ? mac->ack_signal : 0,
|
||||
NULL);
|
||||
mac->ack_pending = 0;
|
||||
|
|
|
|||
|
|
@ -662,18 +662,6 @@ static inline bool ieee80211_s1g_has_cssid(__le16 fc)
|
|||
(fc & cpu_to_le16(IEEE80211_S1G_BCN_CSSID));
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_is_s1g_short_beacon - check if frame is an S1G short beacon
|
||||
* @fc: frame control bytes in little-endian byteorder
|
||||
* Return: whether or not the frame is an S1G short beacon,
|
||||
* i.e. it is an S1G beacon with 'next TBTT' flag set
|
||||
*/
|
||||
static inline bool ieee80211_is_s1g_short_beacon(__le16 fc)
|
||||
{
|
||||
return ieee80211_is_s1g_beacon(fc) &&
|
||||
(fc & cpu_to_le16(IEEE80211_S1G_BCN_NEXT_TBTT));
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_is_atim - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_ATIM
|
||||
* @fc: frame control bytes in little-endian byteorder
|
||||
|
|
@ -4901,6 +4889,39 @@ static inline bool ieee80211_is_ftm(struct sk_buff *skb)
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_is_s1g_short_beacon - check if frame is an S1G short beacon
|
||||
* @fc: frame control bytes in little-endian byteorder
|
||||
* @variable: pointer to the beacon frame elements
|
||||
* @variable_len: length of the frame elements
|
||||
* Return: whether or not the frame is an S1G short beacon. As per
|
||||
* IEEE80211-2024 11.1.3.10.1, The S1G beacon compatibility element shall
|
||||
* always be present as the first element in beacon frames generated at a
|
||||
* TBTT (Target Beacon Transmission Time), so any frame not containing
|
||||
* this element must have been generated at a TSBTT (Target Short Beacon
|
||||
* Transmission Time) that is not a TBTT. Additionally, short beacons are
|
||||
* prohibited from containing the S1G beacon compatibility element as per
|
||||
* IEEE80211-2024 9.3.4.3 Table 9-76, so if we have an S1G beacon with
|
||||
* either no elements or the first element is not the beacon compatibility
|
||||
* element, we have a short beacon.
|
||||
*/
|
||||
static inline bool ieee80211_is_s1g_short_beacon(__le16 fc, const u8 *variable,
|
||||
size_t variable_len)
|
||||
{
|
||||
if (!ieee80211_is_s1g_beacon(fc))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* If the frame does not contain at least 1 element (this is perfectly
|
||||
* valid in a short beacon) and is an S1G beacon, we have a short
|
||||
* beacon.
|
||||
*/
|
||||
if (variable_len < 2)
|
||||
return true;
|
||||
|
||||
return variable[0] != WLAN_EID_S1G_BCN_COMPAT;
|
||||
}
|
||||
|
||||
struct element {
|
||||
u8 id;
|
||||
u8 datalen;
|
||||
|
|
|
|||
|
|
@ -1959,6 +1959,20 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
|
|||
ieee80211_sta_init_nss(link_sta);
|
||||
|
||||
if (params->opmode_notif_used) {
|
||||
enum nl80211_chan_width width = link->conf->chanreq.oper.width;
|
||||
|
||||
switch (width) {
|
||||
case NL80211_CHAN_WIDTH_20:
|
||||
case NL80211_CHAN_WIDTH_40:
|
||||
case NL80211_CHAN_WIDTH_80:
|
||||
case NL80211_CHAN_WIDTH_160:
|
||||
case NL80211_CHAN_WIDTH_80P80:
|
||||
case NL80211_CHAN_WIDTH_320: /* not VHT, allowed for HE/EHT */
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* returned value is only needed for rc update, but the
|
||||
* rc isn't initialized here yet, so ignore it
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1150,6 +1150,8 @@ static void ieee80211_sdata_init(struct ieee80211_local *local,
|
|||
{
|
||||
sdata->local = local;
|
||||
|
||||
INIT_LIST_HEAD(&sdata->key_list);
|
||||
|
||||
/*
|
||||
* Initialize the default link, so we can use link_id 0 for non-MLD,
|
||||
* and that continues to work for non-MLD-aware drivers that use just
|
||||
|
|
@ -2210,8 +2212,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
|||
|
||||
ieee80211_init_frag_cache(&sdata->frags);
|
||||
|
||||
INIT_LIST_HEAD(&sdata->key_list);
|
||||
|
||||
wiphy_delayed_work_init(&sdata->dec_tailroom_needed_wk,
|
||||
ieee80211_delayed_tailroom_dec);
|
||||
|
||||
|
|
|
|||
|
|
@ -3934,6 +3934,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
|
||||
if (frame_buf)
|
||||
memset(frame_buf, 0, IEEE80211_DEAUTH_FRAME_LEN);
|
||||
|
||||
if (WARN_ON(!ap_sta))
|
||||
return;
|
||||
|
||||
|
|
@ -7195,6 +7198,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
|
|||
struct ieee80211_bss_conf *bss_conf = link->conf;
|
||||
struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg;
|
||||
struct ieee80211_mgmt *mgmt = (void *) hdr;
|
||||
struct ieee80211_ext *ext = NULL;
|
||||
size_t baselen;
|
||||
struct ieee802_11_elems *elems;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
|
@ -7220,7 +7224,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
|
|||
/* Process beacon from the current BSS */
|
||||
bssid = ieee80211_get_bssid(hdr, len, sdata->vif.type);
|
||||
if (ieee80211_is_s1g_beacon(mgmt->frame_control)) {
|
||||
struct ieee80211_ext *ext = (void *) mgmt;
|
||||
ext = (void *)mgmt;
|
||||
variable = ext->u.s1g_beacon.variable +
|
||||
ieee80211_s1g_optional_len(ext->frame_control);
|
||||
}
|
||||
|
|
@ -7407,7 +7411,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
|
|||
}
|
||||
|
||||
if ((ncrc == link->u.mgd.beacon_crc && link->u.mgd.beacon_crc_valid) ||
|
||||
ieee80211_is_s1g_short_beacon(mgmt->frame_control))
|
||||
(ext && ieee80211_is_s1g_short_beacon(ext->frame_control,
|
||||
parse_params.start,
|
||||
parse_params.len)))
|
||||
goto free;
|
||||
link->u.mgd.beacon_crc = ncrc;
|
||||
link->u.mgd.beacon_crc_valid = true;
|
||||
|
|
@ -10699,8 +10705,8 @@ static void ieee80211_ml_epcs(struct ieee80211_sub_if_data *sdata,
|
|||
*/
|
||||
for_each_mle_subelement(sub, (const u8 *)elems->ml_epcs,
|
||||
elems->ml_epcs_len) {
|
||||
struct ieee802_11_elems *link_elems __free(kfree) = NULL;
|
||||
struct ieee80211_link_data *link;
|
||||
struct ieee802_11_elems *link_elems __free(kfree);
|
||||
u8 *pos = (void *)sub->data;
|
||||
u16 control;
|
||||
ssize_t len;
|
||||
|
|
|
|||
|
|
@ -758,7 +758,6 @@ static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len,
|
|||
{
|
||||
const struct element *elem, *sub;
|
||||
size_t profile_len = 0;
|
||||
bool found = false;
|
||||
|
||||
if (!bss || !bss->transmitted_bss)
|
||||
return profile_len;
|
||||
|
|
@ -809,15 +808,14 @@ static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len,
|
|||
index[2],
|
||||
new_bssid);
|
||||
if (ether_addr_equal(new_bssid, bss->bssid)) {
|
||||
found = true;
|
||||
elems->bssid_index_len = index[1];
|
||||
elems->bssid_index = (void *)&index[2];
|
||||
break;
|
||||
return profile_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found ? profile_len : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -2144,11 +2144,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
|||
cfg80211_sched_scan_stopped_locked(local->hw.wiphy, 0);
|
||||
|
||||
wake_up:
|
||||
|
||||
if (local->virt_monitors > 0 &&
|
||||
local->virt_monitors == local->open_count)
|
||||
ieee80211_add_virtual_monitor(local);
|
||||
|
||||
/*
|
||||
* Clear the WLAN_STA_BLOCK_BA flag so new aggregation
|
||||
* sessions can be established after a resume.
|
||||
|
|
@ -2202,6 +2197,10 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
|||
}
|
||||
}
|
||||
|
||||
if (local->virt_monitors > 0 &&
|
||||
local->virt_monitors == local->open_count)
|
||||
ieee80211_add_virtual_monitor(local);
|
||||
|
||||
if (!suspended)
|
||||
return 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -229,6 +229,7 @@ static int validate_beacon_head(const struct nlattr *attr,
|
|||
unsigned int len = nla_len(attr);
|
||||
const struct element *elem;
|
||||
const struct ieee80211_mgmt *mgmt = (void *)data;
|
||||
const struct ieee80211_ext *ext;
|
||||
unsigned int fixedlen, hdrlen;
|
||||
bool s1g_bcn;
|
||||
|
||||
|
|
@ -237,8 +238,10 @@ static int validate_beacon_head(const struct nlattr *attr,
|
|||
|
||||
s1g_bcn = ieee80211_is_s1g_beacon(mgmt->frame_control);
|
||||
if (s1g_bcn) {
|
||||
fixedlen = offsetof(struct ieee80211_ext,
|
||||
u.s1g_beacon.variable);
|
||||
ext = (struct ieee80211_ext *)mgmt;
|
||||
fixedlen =
|
||||
offsetof(struct ieee80211_ext, u.s1g_beacon.variable) +
|
||||
ieee80211_s1g_optional_len(ext->frame_control);
|
||||
hdrlen = offsetof(struct ieee80211_ext, u.s1g_beacon);
|
||||
} else {
|
||||
fixedlen = offsetof(struct ieee80211_mgmt,
|
||||
|
|
|
|||
|
|
@ -820,6 +820,52 @@ bool ieee80211_is_valid_amsdu(struct sk_buff *skb, u8 mesh_hdr)
|
|||
}
|
||||
EXPORT_SYMBOL(ieee80211_is_valid_amsdu);
|
||||
|
||||
|
||||
/*
|
||||
* Detects if an MSDU frame was maliciously converted into an A-MSDU
|
||||
* frame by an adversary. This is done by parsing the received frame
|
||||
* as if it were a regular MSDU, even though the A-MSDU flag is set.
|
||||
*
|
||||
* For non-mesh interfaces, detection involves checking whether the
|
||||
* payload, when interpreted as an MSDU, begins with a valid RFC1042
|
||||
* header. This is done by comparing the A-MSDU subheader's destination
|
||||
* address to the start of the RFC1042 header.
|
||||
*
|
||||
* For mesh interfaces, the MSDU includes a 6-byte Mesh Control field
|
||||
* and an optional variable-length Mesh Address Extension field before
|
||||
* the RFC1042 header. The position of the RFC1042 header must therefore
|
||||
* be calculated based on the mesh header length.
|
||||
*
|
||||
* Since this function intentionally parses an A-MSDU frame as an MSDU,
|
||||
* it only assumes that the A-MSDU subframe header is present, and
|
||||
* beyond this it performs its own bounds checks under the assumption
|
||||
* that the frame is instead parsed as a non-aggregated MSDU.
|
||||
*/
|
||||
static bool
|
||||
is_amsdu_aggregation_attack(struct ethhdr *eth, struct sk_buff *skb,
|
||||
enum nl80211_iftype iftype)
|
||||
{
|
||||
int offset;
|
||||
|
||||
/* Non-mesh case can be directly compared */
|
||||
if (iftype != NL80211_IFTYPE_MESH_POINT)
|
||||
return ether_addr_equal(eth->h_dest, rfc1042_header);
|
||||
|
||||
offset = __ieee80211_get_mesh_hdrlen(eth->h_dest[0]);
|
||||
if (offset == 6) {
|
||||
/* Mesh case with empty address extension field */
|
||||
return ether_addr_equal(eth->h_source, rfc1042_header);
|
||||
} else if (offset + ETH_ALEN <= skb->len) {
|
||||
/* Mesh case with non-empty address extension field */
|
||||
u8 temp[ETH_ALEN];
|
||||
|
||||
skb_copy_bits(skb, offset, temp, ETH_ALEN);
|
||||
return ether_addr_equal(temp, rfc1042_header);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
|
||||
const u8 *addr, enum nl80211_iftype iftype,
|
||||
const unsigned int extra_headroom,
|
||||
|
|
@ -861,8 +907,10 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
|
|||
/* the last MSDU has no padding */
|
||||
if (subframe_len > remaining)
|
||||
goto purge;
|
||||
/* mitigate A-MSDU aggregation injection attacks */
|
||||
if (ether_addr_equal(hdr.eth.h_dest, rfc1042_header))
|
||||
/* mitigate A-MSDU aggregation injection attacks, to be
|
||||
* checked when processing first subframe (offset == 0).
|
||||
*/
|
||||
if (offset == 0 && is_amsdu_aggregation_attack(&hdr.eth, skb, iftype))
|
||||
goto purge;
|
||||
|
||||
offset += sizeof(struct ethhdr);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user