link_sta_info->status_stats.msdu_failed[tid];
        }
 
-       if (tid < IEEE80211_NUM_TIDS) {
+       if (link_id < 0 && tid < IEEE80211_NUM_TIDS) {
                spin_lock_bh(&local->fq.lock);
                rcu_read_lock();
 
        }
 }
 
+static void sta_set_link_sinfo(struct sta_info *sta,
+                              struct link_station_info *link_sinfo,
+                              struct ieee80211_link_data *link,
+                              bool tidstats)
+{
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
+       struct ieee80211_sta_rx_stats *last_rxstats;
+       int i, ac, cpu, link_id = link->link_id;
+       struct link_sta_info *link_sta_info;
+       u32 thr = 0;
+
+       last_rxstats = sta_get_last_rx_stats(sta, link_id);
+
+       link_sta_info = wiphy_dereference(sta->local->hw.wiphy,
+                                         sta->link[link_id]);
+
+       /* do before driver, so beacon filtering drivers have a
+        * chance to e.g. just add the number of filtered beacons
+        * (or just modify the value entirely, of course)
+        */
+       if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               link_sinfo->rx_beacon = link->u.mgd.count_beacon_signal;
+
+       ether_addr_copy(link_sinfo->addr, link_sta_info->addr);
+
+       /* TODO: add drv_link_sta_statistics() ops to fill link_station
+        * statistics of station.
+        */
+
+       link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME) |
+                        BIT_ULL(NL80211_STA_INFO_BSS_PARAM) |
+                        BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC);
+
+       if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+               link_sinfo->beacon_loss_count =
+                       link->u.mgd.beacon_loss_count;
+               link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_LOSS);
+       }
+
+       link_sinfo->inactive_time =
+               jiffies_to_msecs(jiffies - ieee80211_sta_last_active(sta, link_id));
+
+       if (!(link_sinfo->filled & (BIT_ULL(NL80211_STA_INFO_TX_BYTES64) |
+                                   BIT_ULL(NL80211_STA_INFO_TX_BYTES)))) {
+               link_sinfo->tx_bytes = 0;
+               for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+                       link_sinfo->tx_bytes +=
+                               link_sta_info->tx_stats.bytes[ac];
+               link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64);
+       }
+
+       if (!(link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_PACKETS))) {
+               link_sinfo->tx_packets = 0;
+               for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+                       link_sinfo->tx_packets +=
+                               link_sta_info->tx_stats.packets[ac];
+               link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS);
+       }
+
+       if (!(link_sinfo->filled & (BIT_ULL(NL80211_STA_INFO_RX_BYTES64) |
+                              BIT_ULL(NL80211_STA_INFO_RX_BYTES)))) {
+               link_sinfo->rx_bytes +=
+                       sta_get_stats_bytes(&link_sta_info->rx_stats);
+
+               if (link_sta_info->pcpu_rx_stats) {
+                       for_each_possible_cpu(cpu) {
+                               struct ieee80211_sta_rx_stats *cpurxs;
+
+                               cpurxs = per_cpu_ptr(link_sta_info->pcpu_rx_stats,
+                                                    cpu);
+                               link_sinfo->rx_bytes +=
+                                       sta_get_stats_bytes(cpurxs);
+                       }
+               }
+
+               link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES64);
+       }
+
+       if (!(link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_PACKETS))) {
+               link_sinfo->rx_packets = link_sta_info->rx_stats.packets;
+               if (link_sta_info->pcpu_rx_stats) {
+                       for_each_possible_cpu(cpu) {
+                               struct ieee80211_sta_rx_stats *cpurxs;
+
+                               cpurxs = per_cpu_ptr(link_sta_info->pcpu_rx_stats,
+                                                    cpu);
+                               link_sinfo->rx_packets += cpurxs->packets;
+                       }
+               }
+               link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS);
+       }
+
+       if (!(link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_RETRIES))) {
+               link_sinfo->tx_retries =
+                       link_sta_info->status_stats.retry_count;
+               link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES);
+       }
+
+       if (!(link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_FAILED))) {
+               link_sinfo->tx_failed =
+                       link_sta_info->status_stats.retry_failed;
+               link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
+       }
+
+       if (!(link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_DURATION))) {
+               for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+                       link_sinfo->rx_duration += sta->airtime[ac].rx_airtime;
+               link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION);
+       }
+
+       if (!(link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_DURATION))) {
+               for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+                       link_sinfo->tx_duration += sta->airtime[ac].tx_airtime;
+               link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_DURATION);
+       }
+
+       if (!(link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT))) {
+               link_sinfo->airtime_weight = sta->airtime_weight;
+               link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT);
+       }
+
+       link_sinfo->rx_dropped_misc = link_sta_info->rx_stats.dropped;
+       if (link_sta_info->pcpu_rx_stats) {
+               for_each_possible_cpu(cpu) {
+                       struct ieee80211_sta_rx_stats *cpurxs;
+
+                       cpurxs = per_cpu_ptr(link_sta_info->pcpu_rx_stats,
+                                            cpu);
+                       link_sinfo->rx_dropped_misc += cpurxs->dropped;
+               }
+       }
+
+       if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+           !(sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER)) {
+               link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_RX) |
+                                BIT_ULL(NL80211_STA_INFO_BEACON_SIGNAL_AVG);
+               link_sinfo->rx_beacon_signal_avg =
+                       ieee80211_ave_rssi(&sdata->vif, -1);
+       }
+
+       if (ieee80211_hw_check(&sta->local->hw, SIGNAL_DBM) ||
+           ieee80211_hw_check(&sta->local->hw, SIGNAL_UNSPEC)) {
+               if (!(link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_SIGNAL))) {
+                       link_sinfo->signal = (s8)last_rxstats->last_signal;
+                       link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
+               }
+
+               if (!link_sta_info->pcpu_rx_stats &&
+                   !(link_sinfo->filled &
+                      BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG))) {
+                       link_sinfo->signal_avg =
+                               -ewma_signal_read(&link_sta_info->rx_stats_avg.signal);
+                       link_sinfo->filled |=
+                               BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG);
+               }
+       }
+
+       /* for the average - if pcpu_rx_stats isn't set - rxstats must point to
+        * the sta->rx_stats struct, so the check here is fine with and without
+        * pcpu statistics
+        */
+       if (last_rxstats->chains &&
+           !(link_sinfo->filled & (BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL) |
+                              BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)))) {
+               link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL);
+               if (!link_sta_info->pcpu_rx_stats)
+                       link_sinfo->filled |=
+                               BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG);
+
+               link_sinfo->chains = last_rxstats->chains;
+
+               for (i = 0; i < ARRAY_SIZE(link_sinfo->chain_signal); i++) {
+                       link_sinfo->chain_signal[i] =
+                               last_rxstats->chain_signal_last[i];
+                       link_sinfo->chain_signal_avg[i] =
+                               -ewma_signal_read(
+                                       &link_sta_info->rx_stats_avg.chain_signal[i]);
+               }
+       }
+
+       if (!(link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE)) &&
+           ieee80211_rate_valid(&link_sta_info->tx_stats.last_rate)) {
+               sta_set_rate_info_tx(sta, &link_sta_info->tx_stats.last_rate,
+                                    &link_sinfo->txrate);
+               link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
+       }
+
+       if (!(link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE))) {
+               if (sta_set_rate_info_rx(sta, &link_sinfo->rxrate,
+                                        link_id) == 0)
+                       link_sinfo->filled |=
+                               BIT_ULL(NL80211_STA_INFO_RX_BITRATE);
+       }
+
+       if (tidstats && !cfg80211_link_sinfo_alloc_tid_stats(link_sinfo,
+                                                            GFP_KERNEL)) {
+               for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++)
+                       sta_set_tidstats(sta, &link_sinfo->pertid[i], i,
+                                        link_id);
+       }
+
+       link_sinfo->bss_param.flags = 0;
+       if (sdata->vif.bss_conf.use_cts_prot)
+               link_sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
+       if (sdata->vif.bss_conf.use_short_preamble)
+               link_sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
+       if (sdata->vif.bss_conf.use_short_slot)
+               link_sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
+       link_sinfo->bss_param.dtim_period = link->conf->dtim_period;
+       link_sinfo->bss_param.beacon_interval = link->conf->beacon_int;
+
+       thr = sta_get_expected_throughput(sta);
+
+       if (thr != 0) {
+               link_sinfo->filled |=
+                       BIT_ULL(NL80211_STA_INFO_EXPECTED_THROUGHPUT);
+               link_sinfo->expected_throughput = thr;
+       }
+
+       if (!(link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL)) &&
+           link_sta_info->status_stats.ack_signal_filled) {
+               link_sinfo->ack_signal =
+                       link_sta_info->status_stats.last_ack_signal;
+               link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL);
+       }
+
+       if (!(link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG)) &&
+           link_sta_info->status_stats.ack_signal_filled) {
+               link_sinfo->avg_ack_signal =
+                       -(s8)ewma_avg_signal_read(
+                               &link_sta_info->status_stats.avg_ack_signal);
+               link_sinfo->filled |=
+                       BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG);
+       }
+}
+
 void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
                   bool tidstats)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        struct ieee80211_local *local = sdata->local;
        u32 thr = 0;
-       int i, ac, cpu;
+       int i, ac, cpu, link_id;
        struct ieee80211_sta_rx_stats *last_rxstats;
 
        last_rxstats = sta_get_last_rx_stats(sta, -1);
                sinfo->filled |=
                        BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG);
        }
+
+       if (sta->sta.valid_links) {
+               struct ieee80211_link_data *link;
+               struct link_sta_info *link_sta;
+
+               ether_addr_copy(sinfo->mld_addr, sta->addr);
+               for_each_valid_link(sinfo, link_id) {
+                       link_sta = wiphy_dereference(sta->local->hw.wiphy,
+                                                    sta->link[link_id]);
+                       link = wiphy_dereference(sdata->local->hw.wiphy,
+                                                sdata->link[link_id]);
+
+                       if (!link_sta || !sinfo->links[link_id] || !link)
+                               continue;
+
+                       sinfo->valid_links = sta->sta.valid_links;
+                       sta_set_link_sinfo(sta, sinfo->links[link_id],
+                                          link, tidstats);
+               }
+       }
 }
 
 u32 sta_get_expected_throughput(struct sta_info *sta)