@@ -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)
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@quicinc.com> --- net/mac80211/sta_info.c | 68 +++++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 16 deletions(-)