Currently, sinfo structure is supported to fill information at deflink( or one of the links) level for station. This has problems when applied to fetch multi-link(ML) station information. Hence, add changes to verify if driver supports link level statistics and if valid_links are present and if so, support filling link_sinfo structure. This will be helpful to check the link related statistics during MLO. Signed-off-by: Sarika Sharma <quic_sarishar@xxxxxxxxxxx> --- net/mac80211/sta_info.c | 68 +++++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 16 deletions(-) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 195eacaca492..cf5d0c86a355 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -2637,14 +2637,21 @@ static void sta_set_mesh_sinfo(struct sta_info *sta, static void sta_set_link_sinfo(struct sta_info *sta, struct link_station_info *sinfo, struct ieee80211_link_data *link_sdata, bool tidstats) { - struct link_sta_info *link_sta_info = &sta->deflink; struct ieee80211_sub_if_data *sdata = sta->sdata; struct ieee80211_local *local = sdata->local; struct ieee80211_sta_rx_stats *last_rxstats; + struct link_sta_info *link_sta_info; u32 thr = 0; - int i, ac, cpu; + int i, ac, cpu, link_id; + + link_id = sinfo->link_id; + last_rxstats = sta_get_last_rx_stats(sta, link_id); - last_rxstats = sta_get_last_rx_stats(sta, -1); + if (link_id < 0) + link_sta_info = &sta->deflink; + else + 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 @@ -2653,6 +2660,8 @@ static void sta_set_link_sinfo(struct sta_info *sta, struct link_station_info *s if (sdata->vif.type == NL80211_IFTYPE_STATION) sinfo->rx_beacon = link_sdata->u.mgd.count_beacon_signal; + memcpy(sinfo->addr, link_sta_info->addr, ETH_ALEN); + drv_link_sta_statistics(local, sdata, &sta->sta, sinfo); sinfo->filled |= BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME) | BIT_ULL(NL80211_STA_INFO_BSS_PARAM) | @@ -2665,7 +2674,7 @@ static void sta_set_link_sinfo(struct sta_info *sta, struct link_station_info *s } sinfo->inactive_time = - jiffies_to_msecs(jiffies - ieee80211_sta_last_active(sta, -1)); + jiffies_to_msecs(jiffies - ieee80211_sta_last_active(sta, link_id)); if (!(sinfo->filled & (BIT_ULL(NL80211_STA_INFO_TX_BYTES64) | BIT_ULL(NL80211_STA_INFO_TX_BYTES)))) { @@ -2754,7 +2763,7 @@ static void sta_set_link_sinfo(struct sta_info *sta, struct link_station_info *s !(sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER)) { sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_RX) | BIT_ULL(NL80211_STA_INFO_BEACON_SIGNAL_AVG); - sinfo->rx_beacon_signal_avg = ieee80211_ave_rssi(&sdata->vif, -1); + sinfo->rx_beacon_signal_avg = ieee80211_ave_rssi(&sdata->vif, link_id); } if (ieee80211_hw_check(&sta->local->hw, SIGNAL_DBM) || @@ -2794,22 +2803,20 @@ static void sta_set_link_sinfo(struct sta_info *sta, struct link_station_info *s } if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE)) && - !sta->sta.valid_links && ieee80211_rate_valid(&link_sta_info->tx_stats.last_rate)) { sta_set_rate_info_tx(sta, &link_sta_info->tx_stats.last_rate, &sinfo->txrate); sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); } - if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE)) && - !sta->sta.valid_links) { - if (sta_set_rate_info_rx(sta, &sinfo->rxrate, -1) == 0) + if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE))) { + if (sta_set_rate_info_rx(sta, &sinfo->rxrate, link_id) == 0) sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE); } if (tidstats && !cfg80211_sinfo_alloc_tid_stats(sinfo, GFP_KERNEL)) { for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) - sta_set_tidstats(sta, &sinfo->pertid[i], i, -1); + sta_set_tidstats(sta, &sinfo->pertid[i], i, link_id); } sinfo->bss_param.flags = 0; @@ -2849,10 +2856,16 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo, bool tidstats) { struct ieee80211_sub_if_data *sdata = sta->sdata; - struct link_station_info *link_sinfo = sinfo->links[0]; - struct ieee80211_link_data *link_sdata = &sdata->deflink; + struct link_station_info *link_sinfo; + struct ieee80211_link_data *link_sdata; + struct link_sta_info *link_sta; + int link_id; sinfo->generation = sdata->local->sta_generation; + sinfo->valid_links = sta->sta.valid_links; + sinfo->is_per_link_stats_support = + !!(sdata->local->hw.wiphy->flags & + WIPHY_FLAG_SUPPORTS_MLO_STA_PER_LINK_STATS); sinfo->filled |= BIT_ULL(NL80211_STA_INFO_STA_FLAGS) | BIT_ULL(NL80211_STA_INFO_CONNECTED_TIME) | @@ -2889,11 +2902,34 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo, if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); - link_sinfo = kzalloc(sizeof(*link_sinfo), GFP_KERNEL); - if (!link_sinfo) - return; + if (sinfo->is_per_link_stats_support && sinfo->valid_links) { + memcpy(sinfo->mld_addr, sta->addr, ETH_ALEN); + + for_each_valid_link(sinfo, link_id) { + link_sta = wiphy_dereference(sta->local->hw.wiphy, + sta->link[link_id]); + if (!link_sta) + continue; + + link_sinfo = kzalloc(sizeof(*link_sinfo), GFP_KERNEL); + if (!link_sinfo) + return; - sta_set_link_sinfo(sta, link_sinfo, link_sdata, tidstats); + link_sinfo->link_id = link_id; + link_sdata = wiphy_dereference(sdata->local->hw.wiphy, + sdata->link[link_id]); + sta_set_link_sinfo(sta, link_sinfo, link_sdata, tidstats); + sinfo->links[link_id] = link_sinfo; + } + } else { + link_sinfo = kzalloc(sizeof(*link_sinfo), GFP_KERNEL); + if (!link_sinfo) + return; + link_sinfo->link_id = -1; + link_sdata = &sdata->deflink; + sta_set_link_sinfo(sta, link_sinfo, link_sdata, tidstats); + sinfo->links[0] = link_sinfo; + } } u32 sta_get_expected_throughput(struct sta_info *sta) -- 2.34.1