wifi: mt76: add a wrapper for wcid access with validation
authorFelix Fietkau <nbd@nbd.name>
Mon, 7 Jul 2025 15:47:01 +0000 (17:47 +0200)
committerFelix Fietkau <nbd@nbd.name>
Mon, 7 Jul 2025 16:02:26 +0000 (18:02 +0200)
Several places use rcu_dereference to get a wcid entry without validating
if the index exceeds the array boundary. Fix this by using a helper function,
which handles validation.

Link: https://patch.msgid.link/20250707154702.1726-1-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
17 files changed:
drivers/net/wireless/mediatek/mt76/mt76.h
drivers/net/wireless/mediatek/mt76/mt7603/dma.c
drivers/net/wireless/mediatek/mt76/mt7603/mac.c
drivers/net/wireless/mediatek/mt76/mt7615/mac.c
drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
drivers/net/wireless/mediatek/mt76/mt76x02.h
drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
drivers/net/wireless/mediatek/mt76/mt7915/mac.c
drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
drivers/net/wireless/mediatek/mt76/mt7921/mac.c
drivers/net/wireless/mediatek/mt76/mt7925/mac.c
drivers/net/wireless/mediatek/mt76/mt792x_mac.c
drivers/net/wireless/mediatek/mt76/mt7996/mac.c
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
drivers/net/wireless/mediatek/mt76/tx.c
drivers/net/wireless/mediatek/mt76/util.c

index 5f8d81cda6cdb7cbb3fe45535148758d5773affc..74b75035d3614852b7666f6eafba72b0074d56bf 100644 (file)
@@ -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);
index 863e5770df51d5b4a62c9a16e3446ea4b26f1519..e26cc78fff949394912d6aa0e4f2a892b6f3076a 100644 (file)
@@ -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;
 
index 413973d05b4319139639df01f44c374aec7e8d8f..6387f9e61060a20a3f54d70b0946b5d63c01a9ab 100644 (file)
@@ -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;
 
index 3ca4fae7c4b0feb6e8dbf2a7b8a39c1e0417ad24..f8d2cc94b742c766f060ff7a21825d2a36453953 100644 (file)
@@ -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;
 
index e9ac8a7317a11ccec0255b9e31fce52332356553..0db00efe88b0b7565d47af9d8075b082306d237b 100644 (file)
@@ -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,
index 4cd63bacd742c506d1f9521d55f88b8e23f85e85..9d7ee09b6cc971c87fe33676738a94fbf4105595 100644 (file)
@@ -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;
 
index d5db6ffd6d365fd75e92057bc46f1296d4d312df..83488b2d6efb90126ea8b954af77871f74234183 100644 (file)
@@ -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;
 
index 9400e4af2a044c606975487b6f17d3c18f6c81b1..6639976afcee6a8d0b3eee9e07e6eb8a334bf845 100644 (file)
@@ -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;
 
index 427542777abcfaf2c55ed2594617a5a6ec0cd3c0..c6584d2b7509282e89400aaafd5ad9c1a9c3c2bd 100644 (file)
@@ -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
index 9c4d5cea0c42e9127eba3939139cdaf54a54d655..4a82f8e4c118061fc76459dc0e38f7ee27e25a3a 100644 (file)
@@ -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);
index 5dd57de59f275a7296af3d228542cd79272bf7ba..f1f76506b0a5b77120f6e65e2f1275d8e2bacb0d 100644 (file)
@@ -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)))
index c871d2f9688b89341844b84ddf5d98f08670f727..75823c9fd3a10bb817b133f34671a438169195e9 100644 (file)
@@ -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)))
index 05978d9c7b916aad596f362f01886489188eb187..3f1d9ba49076fe3a45a03dfa142242cf231623c6 100644 (file)
@@ -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;
 
index 445fe149ac0d7e194497a2dc884a599b9546c9ef..92148518f6a5158525cc46ab824a889f8787dc54 100644 (file)
@@ -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;
 
index 77ab1f4854a43643c296f6ed28c08da99bfdcb04..994526c65bfc3234aa6f9efd0ea00e2459980df1 100644 (file)
@@ -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;
 
index 513916469ca2f62a80e9675ffd8ea927d2bd0b86..251ee3ce5e4d1833ae1fbca7da7dda37e063809b 100644 (file)
@@ -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;
 
index 95b3dc96e4c45c53c35fc4bcb1305b54bd05e0c5..97249ebb4bc8fe42f31cc3a3f6bc956075bb7072 100644 (file)
@@ -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;