u16 valid_links;
        struct ieee80211_link_sta deflink;
-       struct ieee80211_link_sta *link[IEEE80211_MLD_MAX_NUM_LINKS];
+       struct ieee80211_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
 
        /* must be last */
        u8 drv_priv[] __aligned(sizeof(void *));
 
 
        if (params->ht_capa)
                ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
-                                                 params->ht_capa, sta, 0);
+                                                 params->ht_capa,
+                                                 &sta->deflink);
 
        /* VHT can override some HT caps such as the A-MSDU max length */
        if (params->vht_capa)
                ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
-                                                   params->vht_capa, sta, 0);
+                                                   params->vht_capa,
+                                                   &sta->deflink);
 
        if (params->he_capa)
                ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband,
                                                  (void *)params->he_capa,
                                                  params->he_capa_len,
                                                  (void *)params->he_6ghz_capa,
-                                                 sta, 0);
+                                                 &sta->deflink);
 
        if (params->eht_capa)
                ieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband,
                                                    params->he_capa_len,
                                                    params->eht_capa,
                                                    params->eht_capa_len,
-                                                   sta, 0);
+                                                   &sta->deflink);
 
        if (params->opmode_notif_used) {
                /* returned value is only needed for rc update, but the
                 * rc isn't initialized here yet, so ignore it
                 */
-               __ieee80211_vht_handle_opmode(sdata, sta, 0,
+               __ieee80211_vht_handle_opmode(sdata, &sta->deflink,
                                              params->opmode_notif,
                                              sband->band);
        }
 
 static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta,
                                                    unsigned int link_id)
 {
-       enum ieee80211_sta_rx_bandwidth width =
-               ieee80211_sta_cap_rx_bw(sta, link_id);
+       enum ieee80211_sta_rx_bandwidth width;
+       struct link_sta_info *link_sta;
+
+       link_sta = rcu_dereference(sta->link[link_id]);
 
        /* no effect if this STA has no presence on this link */
-       if (!sta->sta.link[link_id])
+       if (!link_sta)
                return NL80211_CHAN_WIDTH_20_NOHT;
 
+       width = ieee80211_sta_cap_rx_bw(link_sta);
+
        switch (width) {
        case IEEE80211_STA_RX_BW_20:
-               if (sta->sta.link[link_id]->ht_cap.ht_supported)
+               if (link_sta->pub->ht_cap.ht_supported)
                        return NL80211_CHAN_WIDTH_20;
                else
                        return NL80211_CHAN_WIDTH_20_NOHT;
                for (link_id = 0; link_id < ARRAY_SIZE(sta->sdata->link); link_id++) {
                        struct ieee80211_bss_conf *link_conf =
                                sdata->vif.link_conf[link_id];
+                       struct link_sta_info *link_sta;
 
                        if (!link_conf)
                                continue;
                        if (rcu_access_pointer(link_conf->chanctx_conf) != &ctx->conf)
                                continue;
 
-                       new_sta_bw = ieee80211_sta_cur_vht_bw(sta, link_id);
+                       link_sta = rcu_dereference(sta->link[link_id]);
+                       if (!link_sta)
+                               continue;
+
+                       new_sta_bw = ieee80211_sta_cur_vht_bw(link_sta);
 
                        /* nothing change */
-                       if (new_sta_bw == sta->sta.link[link_id]->bandwidth)
+                       if (new_sta_bw == link_sta->pub->bandwidth)
                                continue;
 
                        /* vif changed to narrow BW and narrow BW for station wasn't
                         * requested or vise versa */
-                       if ((new_sta_bw < sta->sta.link[link_id]->bandwidth) == !narrowed)
+                       if ((new_sta_bw < link_sta->pub->bandwidth) == !narrowed)
                                continue;
 
-                       sta->sta.link[link_id]->bandwidth = new_sta_bw;
+                       link_sta->pub->bandwidth = new_sta_bw;
                        rate_control_rate_update(local, sband, sta, link_id,
                                                 IEEE80211_RC_BW_CHANGED);
                }
 
                                    struct ieee80211_supported_band *sband,
                                    const u8 *he_cap_ie, u8 he_cap_len,
                                    const struct ieee80211_eht_cap_elem *eht_cap_ie_elem,
-                                   u8 eht_cap_len, struct sta_info *sta,
-                                   unsigned int link_id)
+                                   u8 eht_cap_len,
+                                   struct link_sta_info *link_sta)
 {
-       struct ieee80211_sta_eht_cap *eht_cap =
-               &sta->sta.link[link_id]->eht_cap;
+       struct ieee80211_sta_eht_cap *eht_cap = &link_sta->pub->eht_cap;
        struct ieee80211_he_cap_elem *he_cap_ie_elem = (void *)he_cap_ie;
        u8 eht_ppe_size = 0;
        u8 mcs_nss_size;
 
        eht_cap->has_eht = true;
 
-       sta->link[link_id]->cur_max_bandwidth =
-               ieee80211_sta_cap_rx_bw(sta, link_id);
-       sta->sta.link[link_id]->bandwidth =
-               ieee80211_sta_cur_vht_bw(sta, link_id);
+       link_sta->cur_max_bandwidth = ieee80211_sta_cap_rx_bw(link_sta);
+       link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta);
 }
 
 
 static void
 ieee80211_update_from_he_6ghz_capa(const struct ieee80211_he_6ghz_capa *he_6ghz_capa,
-                                  struct sta_info *sta, unsigned int link_id)
+                                  struct link_sta_info *link_sta)
 {
+       struct sta_info *sta = link_sta->sta;
        enum ieee80211_smps_mode smps_mode;
 
        if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
                break;
        }
 
-       sta->sta.link[link_id]->he_6ghz_capa = *he_6ghz_capa;
+       link_sta->pub->he_6ghz_capa = *he_6ghz_capa;
 }
 
 static void ieee80211_he_mcs_disable(__le16 *he_mcs)
                                  struct ieee80211_supported_band *sband,
                                  const u8 *he_cap_ie, u8 he_cap_len,
                                  const struct ieee80211_he_6ghz_capa *he_6ghz_capa,
-                                 struct sta_info *sta, unsigned int link_id)
+                                 struct link_sta_info *link_sta)
 {
-       struct ieee80211_sta_he_cap *he_cap = &sta->sta.link[link_id]->he_cap;
+       struct ieee80211_sta_he_cap *he_cap = &link_sta->pub->he_cap;
        struct ieee80211_sta_he_cap own_he_cap;
        struct ieee80211_he_cap_elem *he_cap_ie_elem = (void *)he_cap_ie;
        u8 he_ppe_size;
 
        he_cap->has_he = true;
 
-       sta->link[link_id]->cur_max_bandwidth =
-               ieee80211_sta_cap_rx_bw(sta, link_id);
-       sta->sta.link[link_id]->bandwidth =
-               ieee80211_sta_cur_vht_bw(sta, link_id);
+       link_sta->cur_max_bandwidth = ieee80211_sta_cap_rx_bw(link_sta);
+       link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta);
 
        if (sband->band == NL80211_BAND_6GHZ && he_6ghz_capa)
-               ieee80211_update_from_he_6ghz_capa(he_6ghz_capa, sta, link_id);
+               ieee80211_update_from_he_6ghz_capa(he_6ghz_capa, link_sta);
 
        ieee80211_he_mcs_intersection(&own_he_cap.he_mcs_nss_supp.rx_mcs_80,
                                      &he_cap->he_mcs_nss_supp.rx_mcs_80,
 
 bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
                                       struct ieee80211_supported_band *sband,
                                       const struct ieee80211_ht_cap *ht_cap_ie,
-                                      struct sta_info *sta, unsigned int link_id)
+                                      struct link_sta_info *link_sta)
 {
+       struct sta_info *sta = link_sta->sta;
        struct ieee80211_sta_ht_cap ht_cap, own_cap;
        u8 ampdu_info, tx_mcs_set_cap;
        int i, max_tx_streams;
                sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_3839;
 
  apply:
-       changed = memcmp(&sta->sta.link[link_id]->ht_cap,
-                        &ht_cap, sizeof(ht_cap));
+       changed = memcmp(&link_sta->pub->ht_cap, &ht_cap, sizeof(ht_cap));
 
-       memcpy(&sta->sta.link[link_id]->ht_cap, &ht_cap, sizeof(ht_cap));
+       memcpy(&link_sta->pub->ht_cap, &ht_cap, sizeof(ht_cap));
 
-       switch (sdata->vif.link_conf[link_id]->chandef.width) {
+       switch (sdata->vif.link_conf[link_sta->link_id]->chandef.width) {
        default:
                WARN_ON_ONCE(1);
                fallthrough;
                break;
        }
 
-       sta->sta.link[link_id]->bandwidth = bw;
+       link_sta->pub->bandwidth = bw;
 
-       sta->link[link_id]->cur_max_bandwidth =
+       link_sta->cur_max_bandwidth =
                ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
                                IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
 
 
                memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie));
                rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
                                                                   &htcap_ie,
-                                                                  sta, 0);
+                                                                  &sta->deflink);
 
                if (elems->vht_operation && elems->vht_cap_elem &&
                    sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20 &&
                                                   &chandef);
                        memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie));
                        ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
-                                                           &cap_ie, sta, 0);
+                                                           &cap_ie,
+                                                           &sta->deflink);
                        if (memcmp(&cap, &sta->sta.deflink.vht_cap, sizeof(cap)))
                                rates_updated |= true;
                }
 
 bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
                                       struct ieee80211_supported_band *sband,
                                       const struct ieee80211_ht_cap *ht_cap_ie,
-                                      struct sta_info *sta, unsigned int link_id);
+                                      struct link_sta_info *link_sta);
 void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
                          const u8 *da, u16 tid,
                          u16 initiator, u16 reason_code);
 ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
                                    struct ieee80211_supported_band *sband,
                                    const struct ieee80211_vht_cap *vht_cap_ie,
-                                   struct sta_info *sta, unsigned int link_id);
-enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta,
-                                                       unsigned int link_id);
-enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta,
-                                                        unsigned int link_id);
-void ieee80211_sta_set_rx_nss(struct sta_info *sta, unsigned int link_id);
+                                   struct link_sta_info *link_sta);
+enum ieee80211_sta_rx_bandwidth
+ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta);
+enum ieee80211_sta_rx_bandwidth
+ieee80211_sta_cur_vht_bw(struct link_sta_info *link_sta);
+void ieee80211_sta_set_rx_nss(struct link_sta_info *link_sta);
 enum ieee80211_sta_rx_bandwidth
 ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width);
-enum nl80211_chan_width ieee80211_sta_cap_chan_bw(struct sta_info *sta,
-                                                 unsigned int link_id);
+enum nl80211_chan_width
+ieee80211_sta_cap_chan_bw(struct link_sta_info *link_sta);
 void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata,
                                 unsigned int link_id,
                                 struct ieee80211_mgmt *mgmt);
 u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
-                                 struct sta_info *sta, unsigned int link_id,
+                                 struct link_sta_info *sta,
                                  u8 opmode, enum nl80211_band band);
 void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
-                                struct sta_info *sta, unsigned int link_id,
+                                struct link_sta_info *sta,
                                 u8 opmode, enum nl80211_band band);
 void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata,
                                      struct ieee80211_sta_vht_cap *vht_cap);
 void ieee80211_get_vht_mask_from_cap(__le16 vht_cap,
                                     u16 vht_mask[NL80211_VHT_NSS_MAX]);
 enum nl80211_chan_width
-ieee80211_sta_rx_bw_to_chan_width(struct sta_info *sta, unsigned int link_id);
+ieee80211_sta_rx_bw_to_chan_width(struct link_sta_info *sta);
 
 /* HE */
 void
                                  struct ieee80211_supported_band *sband,
                                  const u8 *he_cap_ie, u8 he_cap_len,
                                  const struct ieee80211_he_6ghz_capa *he_6ghz_capa,
-                                 struct sta_info *sta, unsigned int link_id);
+                                 struct link_sta_info *link_sta);
 void
 ieee80211_he_spr_ie_to_bss_conf(struct ieee80211_vif *vif,
                                const struct ieee80211_he_spr *he_spr_ie_elem);
                                    struct ieee80211_supported_band *sband,
                                    const u8 *he_cap_ie, u8 he_cap_len,
                                    const struct ieee80211_eht_cap_elem *eht_cap_ie_elem,
-                                   u8 eht_cap_len, struct sta_info *sta,
-                                   unsigned int link_id);
+                                   u8 eht_cap_len,
+                                   struct link_sta_info *link_sta);
 #endif /* IEEE80211_I_H */
 
                        sta = sta_info_get_bss(sdata, mgmt->sa);
 
                        if (sta)
-                               ieee80211_vht_handle_opmode(sdata, sta, 0,
+                               ieee80211_vht_handle_opmode(sdata,
+                                                           &sta->deflink,
                                                            opmode, band);
 
                        mutex_unlock(&local->sta_mtx);
 
        sta->sta.deflink.supp_rates[sband->band] = rates;
 
        if (ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
-                                             elems->ht_cap_elem, sta, 0))
+                                             elems->ht_cap_elem,
+                                             &sta->deflink))
                changed |= IEEE80211_RC_BW_CHANGED;
 
        ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
-                                           elems->vht_cap_elem, sta, 0);
+                                           elems->vht_cap_elem,
+                                           &sta->deflink);
 
        ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband, elems->he_cap,
                                          elems->he_cap_len,
                                          elems->he_6ghz_capa,
-                                         sta, 0);
+                                         &sta->deflink);
 
        if (bw != sta->sta.deflink.bandwidth)
                changed |= IEEE80211_RC_BW_CHANGED;
 
        /* Set up internal HT/VHT capabilities */
        if (elems->ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT))
                ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
-                                                 elems->ht_cap_elem, sta, 0);
+                                                 elems->ht_cap_elem,
+                                                 &sta->deflink);
 
        if (elems->vht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
                ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
                                                    elems->vht_cap_elem,
-                                                   sta, 0);
+                                                   &sta->deflink);
 
        if (elems->he_operation && !(ifmgd->flags & IEEE80211_STA_DISABLE_HE) &&
            elems->he_cap) {
                                                  elems->he_cap,
                                                  elems->he_cap_len,
                                                  elems->he_6ghz_capa,
-                                                 sta, 0);
+                                                 &sta->deflink);
 
                bss_conf->he_support = sta->sta.deflink.he_cap.has_he;
                if (elems->rsnx && elems->rsnx_len &&
                                                            elems->he_cap_len,
                                                            elems->eht_cap,
                                                            elems->eht_cap_len,
-                                                           sta, 0);
+                                                           &sta->deflink);
 
                        bss_conf->eht_support = sta->sta.deflink.eht_cap.has_eht;
                } else {
        }
 
        if (sta && elems->opmode_notif)
-               ieee80211_vht_handle_opmode(sdata, sta, 0,
+               ieee80211_vht_handle_opmode(sdata,
+                                           &sta->deflink,
                                            *elems->opmode_notif,
                                            rx_status->band);
        mutex_unlock(&local->sta_mtx);
 
        struct ieee80211_supported_band *sband;
        struct ieee80211_chanctx_conf *chanctx_conf;
 
-       ieee80211_sta_set_rx_nss(sta, 0);
+       ieee80211_sta_set_rx_nss(&sta->deflink);
 
        if (!ref)
                return;
 
                        if (chanwidth == IEEE80211_HT_CHANWIDTH_20MHZ)
                                max_bw = IEEE80211_STA_RX_BW_20;
                        else
-                               max_bw = ieee80211_sta_cap_rx_bw(rx->sta, 0);
+                               max_bw = ieee80211_sta_cap_rx_bw(&rx->sta->deflink);
 
                        /* set cur_max_bandwidth and recalc sta bw */
                        rx->sta->deflink.cur_max_bandwidth = max_bw;
-                       new_bw = ieee80211_sta_cur_vht_bw(rx->sta, 0);
+                       new_bw = ieee80211_sta_cur_vht_bw(&rx->sta->deflink);
 
                        if (rx->sta->sta.deflink.bandwidth == new_bw)
                                goto handled;
                        rx->sta->sta.deflink.bandwidth = new_bw;
                        sband = rx->local->hw.wiphy->bands[status->band];
                        sta_opmode.bw =
-                               ieee80211_sta_rx_bw_to_chan_width(rx->sta, 0);
+                               ieee80211_sta_rx_bw_to_chan_width(&rx->sta->deflink);
                        sta_opmode.changed = STA_OPMODE_MAX_BW_CHANGED;
 
                        rate_control_rate_update(local, sband, rx->sta, 0,
 
 struct sta_link_alloc {
        struct link_sta_info info;
        struct ieee80211_link_sta sta;
+       struct rcu_head rcu_head;
 };
 
 static const struct rhashtable_params sta_rht_params = {
 static void sta_remove_link(struct sta_info *sta, unsigned int link_id)
 {
        struct sta_link_alloc *alloc = NULL;
+       struct link_sta_info *link_sta;
 
-       if (WARN_ON(!sta->link[link_id]))
+       link_sta = rcu_dereference_protected(sta->link[link_id],
+                                            lockdep_is_held(&sta->local->sta_mtx));
+
+       if (WARN_ON(!link_sta))
                return;
 
-       if (sta->link[link_id] != &sta->deflink)
-               alloc = container_of(sta->link[link_id], typeof(*alloc), info);
+       if (link_sta != &sta->deflink)
+               alloc = container_of(link_sta, typeof(*alloc), info);
 
        sta->sta.valid_links &= ~BIT(link_id);
-       sta->link[link_id] = NULL;
-       sta->sta.link[link_id] = NULL;
+       RCU_INIT_POINTER(sta->link[link_id], NULL);
+       RCU_INIT_POINTER(sta->sta.link[link_id], NULL);
        if (alloc) {
                sta_info_free_link(&alloc->info);
-               kfree(alloc);
+               kfree_rcu(alloc, rcu_head);
        }
 }
 
 {
        link_info->sta = sta;
        link_info->link_id = link_id;
-       sta->link[link_id] = link_info;
-       sta->sta.link[link_id] = link_sta;
+       link_info->pub = link_sta;
+       rcu_assign_pointer(sta->link[link_id], link_info);
+       rcu_assign_pointer(sta->sta.link[link_id], link_sta);
 }
 
 struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
 int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
+       struct link_sta_info *link_sta;
        u16 old_links = sta->sta.valid_links;
        u16 new_links = old_links | BIT(link_id);
        int ret;
 
-       lockdep_assert_held(&sdata->local->sta_mtx);
+       link_sta = rcu_dereference_protected(sta->link[link_id],
+                                            lockdep_is_held(&sdata->local->sta_mtx));
 
-       if (WARN_ON(old_links == new_links || !sta->link[link_id]))
+       if (WARN_ON(old_links == new_links || !link_sta))
                return -EINVAL;
 
        sta->sta.valid_links = new_links;
 
  * @status_stats.last_ack_signal: last ACK signal
  * @status_stats.ack_signal_filled: last ACK signal validity
  * @status_stats.avg_ack_signal: average ACK signal
+ * @pub: public (driver visible) link STA data
  * TODO Move other link params from sta_info as required for MLD operation
  */
 struct link_sta_info {
        } tx_stats;
 
        enum ieee80211_sta_rx_bandwidth cur_max_bandwidth;
+
+       struct ieee80211_link_sta *pub;
 };
 
 /**
        struct ieee80211_fragment_cache frags;
 
        struct link_sta_info deflink;
-       struct link_sta_info *link[IEEE80211_MLD_MAX_NUM_LINKS];
+       struct link_sta_info __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
 
        /* keep last! */
        struct ieee80211_sta sta;
 
        /* IEEE802.11ac-2013 Table E-4 */
        u16 centers_80mhz[] = { 5210, 5290, 5530, 5610, 5690, 5775 };
        struct cfg80211_chan_def uc = sta->tdls_chandef;
-       enum nl80211_chan_width max_width = ieee80211_sta_cap_chan_bw(sta, 0);
+       enum nl80211_chan_width max_width =
+               ieee80211_sta_cap_chan_bw(&sta->deflink);
        int i;
 
        /* only support upgrading non-narrow channels up to 80Mhz */
                        enum ieee80211_sta_rx_bandwidth bw;
 
                        bw = ieee80211_chan_width_to_rx_bw(conf->def.width);
-                       bw = min(bw, ieee80211_sta_cap_rx_bw(sta, 0));
+                       bw = min(bw, ieee80211_sta_cap_rx_bw(&sta->deflink));
                        if (bw != sta->sta.deflink.bandwidth) {
                                sta->sta.deflink.bandwidth = bw;
                                rate_control_rate_update(local, sband, sta, 0,
 
 ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
                                    struct ieee80211_supported_band *sband,
                                    const struct ieee80211_vht_cap *vht_cap_ie,
-                                   struct sta_info *sta, unsigned int link_id)
+                                   struct link_sta_info *link_sta)
 {
-       struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.link[link_id]->vht_cap;
+       struct ieee80211_sta_vht_cap *vht_cap = &link_sta->pub->vht_cap;
        struct ieee80211_sta_vht_cap own_cap;
        u32 cap_info, i;
        bool have_80mhz;
 
        memset(vht_cap, 0, sizeof(*vht_cap));
 
-       if (!sta->sta.link[link_id]->ht_cap.ht_supported)
+       if (!link_sta->pub->ht_cap.ht_supported)
                return;
 
        if (!vht_cap_ie || !sband->vht_cap.vht_supported)
         * our own capabilities and then use those below.
         */
        if (sdata->vif.type == NL80211_IFTYPE_STATION &&
-           !test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+           !test_sta_flag(link_sta->sta, WLAN_STA_TDLS_PEER))
                ieee80211_apply_vhtcap_overrides(sdata, &own_cap);
 
        /* take some capabilities as-is */
         */
        if (vht_cap->vht_mcs.rx_mcs_map == cpu_to_le16(0xFFFF)) {
                vht_cap->vht_supported = false;
-               sdata_info(sdata, "Ignoring VHT IE from %pM due to invalid rx_mcs_map\n",
-                          sta->addr);
+               sdata_info(sdata,
+                          "Ignoring VHT IE from %pM (link:%pM) due to invalid rx_mcs_map\n",
+                          link_sta->sta->addr, link_sta->addr);
                return;
        }
 
        switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
        case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
        case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
-               sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_160;
+               link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160;
                break;
        default:
-               sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_80;
+               link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80;
 
                if (!(vht_cap->vht_mcs.tx_highest &
                                cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE)))
                 * above) between 160 and 80+80 yet.
                 */
                if (cap_info & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK)
-                       sta->link[link_id]->cur_max_bandwidth =
+                       link_sta->cur_max_bandwidth =
                                IEEE80211_STA_RX_BW_160;
        }
 
-       sta->sta.link[link_id]->bandwidth = ieee80211_sta_cur_vht_bw(sta, link_id);
+       link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta);
 
+       /*
+        * FIXME - should the amsdu len be per link? store per link
+        * and maintain a minimum?
+        */
        switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) {
        case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
-               sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_11454;
+               link_sta->sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_11454;
                break;
        case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991:
-               sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_7991;
+               link_sta->sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_7991;
                break;
        case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895:
        default:
-               sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_3895;
+               link_sta->sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_3895;
                break;
        }
 }
 
 /* FIXME: move this to some better location - parses HE/EHT now */
-enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta,
-                                                       unsigned int link_id)
+enum ieee80211_sta_rx_bandwidth
+ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta)
 {
-       struct ieee80211_bss_conf *link_conf = sta->sdata->vif.link_conf[link_id];
-       struct ieee80211_link_sta *link_sta = sta->sta.link[link_id];
-       struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap;
-       struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap;
-       struct ieee80211_sta_eht_cap *eht_cap = &link_sta->eht_cap;
+       unsigned int link_id = link_sta->link_id;
+       struct ieee80211_sub_if_data *sdata = link_sta->sta->sdata;
+       struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id];
+       struct ieee80211_sta_vht_cap *vht_cap = &link_sta->pub->vht_cap;
+       struct ieee80211_sta_he_cap *he_cap = &link_sta->pub->he_cap;
+       struct ieee80211_sta_eht_cap *eht_cap = &link_sta->pub->eht_cap;
        u32 cap_width;
 
        if (he_cap->has_he) {
        }
 
        if (!vht_cap->vht_supported)
-               return link_sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
+               return link_sta->pub->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
                                IEEE80211_STA_RX_BW_40 :
                                IEEE80211_STA_RX_BW_20;
 
        return IEEE80211_STA_RX_BW_80;
 }
 
-enum nl80211_chan_width ieee80211_sta_cap_chan_bw(struct sta_info *sta,
-                                                 unsigned int link_id)
+enum nl80211_chan_width
+ieee80211_sta_cap_chan_bw(struct link_sta_info *link_sta)
 {
-       struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.link[link_id]->vht_cap;
+       struct ieee80211_sta_vht_cap *vht_cap = &link_sta->pub->vht_cap;
        u32 cap_width;
 
        if (!vht_cap->vht_supported) {
-               if (!sta->sta.link[link_id]->ht_cap.ht_supported)
+               if (!link_sta->pub->ht_cap.ht_supported)
                        return NL80211_CHAN_WIDTH_20_NOHT;
 
-               return sta->sta.link[link_id]->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
+               return link_sta->pub->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
                                NL80211_CHAN_WIDTH_40 : NL80211_CHAN_WIDTH_20;
        }
 
 }
 
 enum nl80211_chan_width
-ieee80211_sta_rx_bw_to_chan_width(struct sta_info *sta, unsigned int link_id)
+ieee80211_sta_rx_bw_to_chan_width(struct link_sta_info *link_sta)
 {
        enum ieee80211_sta_rx_bandwidth cur_bw =
-               sta->sta.link[link_id]->bandwidth;
+               link_sta->pub->bandwidth;
        struct ieee80211_sta_vht_cap *vht_cap =
-               &sta->sta.link[link_id]->vht_cap;
+               &link_sta->pub->vht_cap;
        u32 cap_width;
 
        switch (cur_bw) {
        case IEEE80211_STA_RX_BW_20:
-               if (!sta->sta.link[link_id]->ht_cap.ht_supported)
+               if (!link_sta->pub->ht_cap.ht_supported)
                        return NL80211_CHAN_WIDTH_20_NOHT;
                else
                        return NL80211_CHAN_WIDTH_20;
 }
 
 /* FIXME: rename/move - this deals with everything not just VHT */
-enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta,
-                                                        unsigned int link_id)
+enum ieee80211_sta_rx_bandwidth
+ieee80211_sta_cur_vht_bw(struct link_sta_info *link_sta)
 {
-       struct ieee80211_bss_conf *link_conf = sta->sdata->vif.link_conf[link_id];
+       struct sta_info *sta = link_sta->sta;
+       struct ieee80211_bss_conf *link_conf =
+               sta->sdata->vif.link_conf[link_sta->link_id];
        enum nl80211_chan_width bss_width = link_conf->chandef.width;
        enum ieee80211_sta_rx_bandwidth bw;
 
-       bw = ieee80211_sta_cap_rx_bw(sta, link_id);
-       bw = min(bw, sta->link[link_id]->cur_max_bandwidth);
+       bw = ieee80211_sta_cap_rx_bw(link_sta);
+       bw = min(bw, link_sta->cur_max_bandwidth);
 
        /* Don't consider AP's bandwidth for TDLS peers, section 11.23.1 of
         * IEEE80211-2016 specification makes higher bandwidth operation
        return bw;
 }
 
-void ieee80211_sta_set_rx_nss(struct sta_info *sta, unsigned int link_id)
+void ieee80211_sta_set_rx_nss(struct link_sta_info *link_sta)
 {
        u8 ht_rx_nss = 0, vht_rx_nss = 0, he_rx_nss = 0, eht_rx_nss = 0, rx_nss;
        bool support_160;
 
        /* if we received a notification already don't overwrite it */
-       if (sta->sta.link[link_id]->rx_nss)
+       if (link_sta->pub->rx_nss)
                return;
 
-       if (sta->sta.link[link_id]->eht_cap.has_eht) {
+       if (link_sta->pub->eht_cap.has_eht) {
                int i;
-               const u8 *rx_nss_mcs = (void *)&sta->sta.link[link_id]->eht_cap.eht_mcs_nss_supp;
+               const u8 *rx_nss_mcs = (void *)&link_sta->pub->eht_cap.eht_mcs_nss_supp;
 
                /* get the max nss for EHT over all possible bandwidths and mcs */
                for (i = 0; i < sizeof(struct ieee80211_eht_mcs_nss_supp); i++)
                                                       IEEE80211_EHT_MCS_NSS_RX));
        }
 
-       if (sta->sta.link[link_id]->he_cap.has_he) {
+       if (link_sta->pub->he_cap.has_he) {
                int i;
                u8 rx_mcs_80 = 0, rx_mcs_160 = 0;
-               const struct ieee80211_sta_he_cap *he_cap = &sta->sta.link[link_id]->he_cap;
+               const struct ieee80211_sta_he_cap *he_cap = &link_sta->pub->he_cap;
                u16 mcs_160_map =
                        le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160);
                u16 mcs_80_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80);
                        he_rx_nss = rx_mcs_80;
        }
 
-       if (sta->sta.link[link_id]->ht_cap.ht_supported) {
-               if (sta->sta.link[link_id]->ht_cap.mcs.rx_mask[0])
+       if (link_sta->pub->ht_cap.ht_supported) {
+               if (link_sta->pub->ht_cap.mcs.rx_mask[0])
                        ht_rx_nss++;
-               if (sta->sta.link[link_id]->ht_cap.mcs.rx_mask[1])
+               if (link_sta->pub->ht_cap.mcs.rx_mask[1])
                        ht_rx_nss++;
-               if (sta->sta.link[link_id]->ht_cap.mcs.rx_mask[2])
+               if (link_sta->pub->ht_cap.mcs.rx_mask[2])
                        ht_rx_nss++;
-               if (sta->sta.link[link_id]->ht_cap.mcs.rx_mask[3])
+               if (link_sta->pub->ht_cap.mcs.rx_mask[3])
                        ht_rx_nss++;
                /* FIXME: consider rx_highest? */
        }
 
-       if (sta->sta.link[link_id]->vht_cap.vht_supported) {
+       if (link_sta->pub->vht_cap.vht_supported) {
                int i;
                u16 rx_mcs_map;
 
-               rx_mcs_map = le16_to_cpu(sta->sta.link[link_id]->vht_cap.vht_mcs.rx_mcs_map);
+               rx_mcs_map = le16_to_cpu(link_sta->pub->vht_cap.vht_mcs.rx_mcs_map);
 
                for (i = 7; i >= 0; i--) {
                        u8 mcs = (rx_mcs_map >> (2 * i)) & 3;
        rx_nss = max(vht_rx_nss, ht_rx_nss);
        rx_nss = max(he_rx_nss, rx_nss);
        rx_nss = max(eht_rx_nss, rx_nss);
-       sta->sta.link[link_id]->rx_nss = max_t(u8, 1, rx_nss);
+       link_sta->pub->rx_nss = max_t(u8, 1, rx_nss);
 }
 
 u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
-                                 struct sta_info *sta, unsigned int link_id,
+                                 struct link_sta_info *link_sta,
                                  u8 opmode, enum nl80211_band band)
 {
        enum ieee80211_sta_rx_bandwidth new_bw;
        nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT;
        nss += 1;
 
-       if (sta->sta.link[link_id]->rx_nss != nss) {
-               sta->sta.link[link_id]->rx_nss = nss;
+       if (link_sta->pub->rx_nss != nss) {
+               link_sta->pub->rx_nss = nss;
                sta_opmode.rx_nss = nss;
                changed |= IEEE80211_RC_NSS_CHANGED;
                sta_opmode.changed |= STA_OPMODE_N_SS_CHANGED;
        switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) {
        case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ:
                /* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */
-               sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_20;
+               link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_20;
                break;
        case IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ:
                /* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */
-               sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_40;
+               link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_40;
                break;
        case IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ:
                if (opmode & IEEE80211_OPMODE_NOTIF_BW_160_80P80)
-                       sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_160;
+                       link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160;
                else
-                       sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_80;
+                       link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80;
                break;
        case IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ:
                /* legacy only, no longer used by newer spec */
-               sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_160;
+               link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160;
                break;
        }
 
-       new_bw = ieee80211_sta_cur_vht_bw(sta, link_id);
-       if (new_bw != sta->sta.link[link_id]->bandwidth) {
-               sta->sta.link[link_id]->bandwidth = new_bw;
-               sta_opmode.bw = ieee80211_sta_rx_bw_to_chan_width(sta, link_id);
+       new_bw = ieee80211_sta_cur_vht_bw(link_sta);
+       if (new_bw != link_sta->pub->bandwidth) {
+               link_sta->pub->bandwidth = new_bw;
+               sta_opmode.bw = ieee80211_sta_rx_bw_to_chan_width(link_sta);
                changed |= IEEE80211_RC_BW_CHANGED;
                sta_opmode.changed |= STA_OPMODE_MAX_BW_CHANGED;
        }
 
        if (sta_opmode.changed)
-               cfg80211_sta_opmode_change_notify(sdata->dev, sta->addr,
+               cfg80211_sta_opmode_change_notify(sdata->dev, link_sta->addr,
                                                  &sta_opmode, GFP_KERNEL);
 
        return changed;
 EXPORT_SYMBOL_GPL(ieee80211_update_mu_groups);
 
 void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
-                                struct sta_info *sta, unsigned int link_id,
+                                struct link_sta_info *link_sta,
                                 u8 opmode, enum nl80211_band band)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
 
-       u32 changed = __ieee80211_vht_handle_opmode(sdata, sta, link_id,
+       u32 changed = __ieee80211_vht_handle_opmode(sdata, link_sta,
                                                    opmode, band);
 
        if (changed > 0) {
                ieee80211_recalc_min_chandef(sdata);
-               rate_control_rate_update(local, sband, sta, link_id, changed);
+               rate_control_rate_update(local, sband, link_sta->sta,
+                                        link_sta->link_id, changed);
        }
 }