[PATCH] wifi: mt76: mt7925: add wcid publish check in mt76_sta_add

Sean Wang sean.wang at kernel.org
Tue May 26 14:52:32 PDT 2026


Hi,

On Tue, May 26, 2026 at 1:09 AM Jiajia Liu <liujiajia at kylinos.cn> wrote:
>
> Since mt7925_mac_sta_add publishes wcid, add publish check in mt76_sta_add
> to avoid reinitializing the wcid->poll_list for mt7925.
>
> Found dev->sta_poll_list corruption when using mt7925 and 7.0-rc4.
> According to the corruption information, prev->next was changed to itself.
>
> wlan0: disconnect from AP 90:fb:5d:94:8b:e3 for new auth to 90:fb:5d:94:8b:e2
> wlan0: authenticate with 90:fb:5d:94:8b:e2 (local address=84:9e:56:9c:7e:6b)
> wlan0: send auth to 90:fb:5d:94:8b:e2 (try 1/3)
>  slab kmalloc-8k start ffff8c80958a6000 pointer offset 4160 size 8192
> list_add corruption. prev->next should be next (ffff8c808a7488f8), but was ffff8c80958a7040. (prev=ffff8c80958a7040).
>
>  mt76_wcid_add_poll+0x95/0xd0 [mt76]
>  mt7925_mac_add_txs.part.0+0xa5/0xe0 [mt7925_common]
>  mt7925_rx_check+0xa7/0xc0 [mt7925_common]
>  mt76_dma_rx_poll+0x50d/0x790 [mt76]
>  mt792x_poll_rx+0x52/0xe0 [mt792x_lib]
>
> Signed-off-by: Jiajia Liu <liujiajia at kylinos.cn>
> ---
>
> Reproduced and tested using the script below over ssh. Roam between two
> bssids with the same SSID on a router.
>
> #!/bin/bash
>
> set -ex
>
> while :; do
>         num=$(sudo iw wlan0 scan | grep Polaris | wc -l)
>         if [ $num -eq 2 ]; then
>                 break
>         fi
> done
>
> for i in $(seq 1 500); do
>
> echo "index $i"
> wpa_cli -i wlan0 roam 90:fb:5d:94:8b:e3
> sleep 5
> wpa_cli -i wlan0 roam 90:fb:5d:94:8b:e2
> sleep 5
>
> done
>
> ---
>  drivers/net/wireless/mediatek/mt76/mac80211.c    | 11 ++++++++---
>  drivers/net/wireless/mediatek/mt76/mt76.h        |  1 +
>  drivers/net/wireless/mediatek/mt76/mt7925/main.c |  3 +++
>  3 files changed, 12 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
> index 4ae5e4715a9c..83f4f941b890 100644
> --- a/drivers/net/wireless/mediatek/mt76/mac80211.c
> +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
> @@ -1595,11 +1595,16 @@ mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif,
>                 mtxq->wcid = wcid->idx;
>         }
>
> -       ewma_signal_init(&wcid->rssi);
> -       rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
> +       if (!test_bit(MT_WCID_FLAG_DRV_PUBLISH, &wcid->flags)) {
> +               ewma_signal_init(&wcid->rssi);
> +               rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
> +               mt76_wcid_init(wcid, phy->band_idx);
> +       } else {
> +               wcid->phy_idx = phy->band_idx;
> +       }
> +
>         phy->num_sta++;
>

Thanks for spotting the roaming issue.

I think we can avoid adding MT_WCID_FLAG_DRV_PUBLISH and instead use the
WCID table itself for the publish check.

dev->wcid[] already encodes whether a WCID has been published, so checking
it directly avoids adding a second mirror state. MT_WCID_FLAG_* is also
better kept for WCID features that affect WTBL setup or data-path handling,
rather than common bookkeeping state.

Something like:

@@ -1620,6 +1620,7 @@ mt76_sta_add(struct mt76_phy *phy, struct
ieee80211_vif *vif,
{
  struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
  struct mt76_dev *dev = phy->dev;
+       struct mt76_wcid *published;
  int ret;
  int i;

@@ -1639,7 +1640,10 @@ mt76_sta_add(struct mt76_phy *phy, struct
ieee80211_vif *vif,
          mtxq->wcid = wcid->idx;
  }

-       if (!test_bit(MT_WCID_FLAG_DRV_PUBLISH, &wcid->flags)) {
+       published = rcu_dereference_protected(dev->wcid[wcid->idx],
+                                             lockdep_is_held(&dev->mutex));
+       if (published != wcid) {
+               WARN_ON_ONCE(published);
                 ewma_signal_init(&wcid->rssi);
                 rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
                 mt76_wcid_init(wcid, phy->band_idx);

   ....


> -       mt76_wcid_init(wcid, phy->band_idx);
>  out:
>         mutex_unlock(&dev->mutex);
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
> index 527bef97e122..8bfce686bff7 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt76.h
> @@ -361,6 +361,7 @@ enum mt76_wcid_flags {
>         MT_WCID_FLAG_PS,
>         MT_WCID_FLAG_4ADDR,
>         MT_WCID_FLAG_HDR_TRANS,
> +       MT_WCID_FLAG_DRV_PUBLISH,
>  };
>
>  #define MT76_N_WCIDS 1088
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
> index 73d3722739d0..35b5c718475c 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
> @@ -1102,6 +1102,9 @@ int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
>                                               &msta->deflink);
>         }
>
> +       if (!err)
> +               set_bit(MT_WCID_FLAG_DRV_PUBLISH, &msta->deflink.wcid.flags);
> +
>         return err;
>  }
>  EXPORT_SYMBOL_GPL(mt7925_mac_sta_add);
> --
> 2.53.0
>
>



More information about the linux-arm-kernel mailing list