Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

wifi: cfg80211: add statistics for providing overview for MLO station

Currently statistics are handled at link level for multi-link
operation(MLO). There is no provision to check accumulated statistics
for a multi-link(ML) station. Other statistics, such as signal, rates,
are also managed at the link level only.

Statistics such as packets, bytes, signal, rates, etc are useful to
provide overall overview for the ML stations.

Statistics such as packets, bytes are accumulated statistics at MLO level.
However, MLO statistics for rates and signal can not be accumulated since
it won't make much sense. Hence, handle other statistics such as signal,
rates, etc bit differently at MLO level.

The signal could be the best of all links-
e.g. if Link 1 has a signal strength of -70 dBm and Link 2 has -65 dBm,
the signal for MLO will be -65 dBm.

The rate could be determined based on the most recently updated link-
e.g. if link 1 has a rate of 300 Mbps and link 2 has a rate of 450 Mbps,
the MLO rate can be calculated based on the inactivity of each link.
If the inactive time for link 1 is 20 seconds and for link 2 is 10 seconds,
the MLO rate will be the most recently updated rate, which is link 2's
rate of 450 Mbps.

The inactive time, dtim_period and beacon_interval can be taken as the
least value of field from link level.

Similarly, other MLO level applicable fields are handled and the fields
which don't make much sense at MLO level, a subsequent change will handle
to embed NL message.

Hence, add accumulated and other statistics for MLO station if valid links
are present to represent comprehensive overview for the ML stations.

Signed-off-by: Sarika Sharma <quic_sarishar@quicinc.com>
Link: https://patch.msgid.link/20250528054420.3050133-5-quic_sarishar@quicinc.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Sarika Sharma and committed by
Johannes Berg
2d226d41 82d7f841

+188
+188
net/wireless/nl80211.c
··· 7176 7176 return -EMSGSIZE; 7177 7177 } 7178 7178 7179 + static void cfg80211_sta_set_mld_sinfo(struct station_info *sinfo) 7180 + { 7181 + struct link_station_info *link_sinfo; 7182 + int link_id, init = 0; 7183 + u32 link_inactive_time; 7184 + 7185 + sinfo->signal = -99; 7186 + 7187 + for_each_valid_link(sinfo, link_id) { 7188 + link_sinfo = sinfo->links[link_id]; 7189 + if (!link_sinfo) 7190 + continue; 7191 + 7192 + if ((link_sinfo->filled & 7193 + BIT_ULL(NL80211_STA_INFO_TX_PACKETS))) { 7194 + sinfo->tx_packets += link_sinfo->tx_packets; 7195 + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS); 7196 + } 7197 + 7198 + if ((link_sinfo->filled & 7199 + BIT_ULL(NL80211_STA_INFO_RX_PACKETS))) { 7200 + sinfo->rx_packets += link_sinfo->rx_packets; 7201 + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS); 7202 + } 7203 + 7204 + if (link_sinfo->filled & 7205 + (BIT_ULL(NL80211_STA_INFO_TX_BYTES) | 7206 + BIT_ULL(NL80211_STA_INFO_TX_BYTES64))) { 7207 + sinfo->tx_bytes += link_sinfo->tx_bytes; 7208 + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES); 7209 + } 7210 + 7211 + if (link_sinfo->filled & 7212 + (BIT_ULL(NL80211_STA_INFO_RX_BYTES) | 7213 + BIT_ULL(NL80211_STA_INFO_TX_BYTES64))) { 7214 + sinfo->rx_bytes += link_sinfo->rx_bytes; 7215 + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES); 7216 + } 7217 + 7218 + if (link_sinfo->filled & 7219 + BIT_ULL(NL80211_STA_INFO_TX_RETRIES)) { 7220 + sinfo->tx_retries += link_sinfo->tx_retries; 7221 + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); 7222 + } 7223 + 7224 + if (link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_FAILED)) { 7225 + sinfo->tx_failed += link_sinfo->tx_failed; 7226 + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); 7227 + } 7228 + 7229 + if (link_sinfo->filled & 7230 + BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC)) { 7231 + sinfo->rx_dropped_misc += link_sinfo->rx_dropped_misc; 7232 + sinfo->filled |= 7233 + BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC); 7234 + } 7235 + 7236 + if (link_sinfo->filled & 7237 + BIT_ULL(NL80211_STA_INFO_BEACON_LOSS)) { 7238 + sinfo->beacon_loss_count += 7239 + link_sinfo->beacon_loss_count; 7240 + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_LOSS); 7241 + } 7242 + 7243 + if (link_sinfo->filled & 7244 + BIT_ULL(NL80211_STA_INFO_EXPECTED_THROUGHPUT)) { 7245 + sinfo->expected_throughput += 7246 + link_sinfo->expected_throughput; 7247 + sinfo->filled |= 7248 + BIT_ULL(NL80211_STA_INFO_EXPECTED_THROUGHPUT); 7249 + } 7250 + 7251 + if (link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_MPDUS)) { 7252 + sinfo->rx_mpdu_count += link_sinfo->rx_mpdu_count; 7253 + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_MPDUS); 7254 + } 7255 + 7256 + if (link_sinfo->filled & 7257 + BIT_ULL(NL80211_STA_INFO_FCS_ERROR_COUNT)) { 7258 + sinfo->fcs_err_count += link_sinfo->fcs_err_count; 7259 + sinfo->filled |= 7260 + BIT_ULL(NL80211_STA_INFO_FCS_ERROR_COUNT); 7261 + } 7262 + 7263 + if (link_sinfo->filled & 7264 + BIT_ULL(NL80211_STA_INFO_BEACON_RX)) { 7265 + sinfo->rx_beacon += link_sinfo->rx_beacon; 7266 + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_RX); 7267 + } 7268 + 7269 + /* Update MLO signal, signal_avg as best among links */ 7270 + if ((link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_SIGNAL)) && 7271 + link_sinfo->signal > sinfo->signal) { 7272 + sinfo->signal = link_sinfo->signal; 7273 + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); 7274 + } 7275 + 7276 + if ((link_sinfo->filled & 7277 + BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG)) && 7278 + link_sinfo->signal_avg > sinfo->signal_avg) { 7279 + sinfo->signal_avg = link_sinfo->signal_avg; 7280 + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG); 7281 + } 7282 + 7283 + /* Update MLO inactive_time, bss_param based on least 7284 + * value for corresponding field of link. 7285 + */ 7286 + if ((link_sinfo->filled & 7287 + BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME)) && 7288 + (!init || 7289 + link_inactive_time > link_sinfo->inactive_time)) { 7290 + link_inactive_time = link_sinfo->inactive_time; 7291 + sinfo->inactive_time = link_sinfo->inactive_time; 7292 + sinfo->filled |= NL80211_STA_INFO_INACTIVE_TIME; 7293 + } 7294 + 7295 + if (link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_BSS_PARAM) && 7296 + (!init || 7297 + sinfo->bss_param.dtim_period > 7298 + link_sinfo->bss_param.dtim_period)) { 7299 + sinfo->bss_param.dtim_period = 7300 + link_sinfo->bss_param.dtim_period; 7301 + sinfo->filled |= NL80211_STA_BSS_PARAM_DTIM_PERIOD; 7302 + sinfo->bss_param.beacon_interval = 7303 + link_sinfo->bss_param.beacon_interval; 7304 + sinfo->filled |= NL80211_STA_BSS_PARAM_BEACON_INTERVAL; 7305 + } 7306 + 7307 + /* Update MLO rates as per last updated link rate */ 7308 + if ((link_sinfo->filled & 7309 + BIT_ULL(NL80211_STA_INFO_TX_BITRATE)) && 7310 + (!init || 7311 + link_inactive_time > link_sinfo->inactive_time)) { 7312 + sinfo->txrate = link_sinfo->txrate; 7313 + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); 7314 + } 7315 + if ((link_sinfo->filled & 7316 + BIT_ULL(NL80211_STA_INFO_RX_BITRATE)) && 7317 + (!init || 7318 + link_inactive_time > link_sinfo->inactive_time)) { 7319 + sinfo->rxrate = link_sinfo->rxrate; 7320 + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE); 7321 + } 7322 + 7323 + if (link_sinfo->filled & 7324 + BIT_ULL(NL80211_STA_INFO_TX_DURATION) && 7325 + (!init || 7326 + link_inactive_time > link_sinfo->inactive_time)) { 7327 + sinfo->tx_duration += link_sinfo->tx_duration; 7328 + sinfo->filled |= 7329 + BIT_ULL(NL80211_STA_INFO_TX_DURATION); 7330 + } 7331 + if (link_sinfo->filled & 7332 + BIT_ULL(NL80211_STA_INFO_RX_DURATION) && 7333 + (!init || 7334 + link_inactive_time > link_sinfo->inactive_time)) { 7335 + sinfo->rx_duration += link_sinfo->rx_duration; 7336 + sinfo->filled |= 7337 + BIT_ULL(NL80211_STA_INFO_RX_DURATION); 7338 + } 7339 + init++; 7340 + 7341 + /* pertid stats accumulate for rx/tx fields */ 7342 + if (sinfo->pertid) { 7343 + sinfo->pertid->rx_msdu += 7344 + link_sinfo->pertid->rx_msdu; 7345 + sinfo->pertid->tx_msdu += 7346 + link_sinfo->pertid->tx_msdu; 7347 + sinfo->pertid->tx_msdu_retries += 7348 + link_sinfo->pertid->tx_msdu_retries; 7349 + sinfo->pertid->tx_msdu_failed += 7350 + link_sinfo->pertid->tx_msdu_failed; 7351 + 7352 + sinfo->pertid->filled |= 7353 + BIT(NL80211_TID_STATS_RX_MSDU) | 7354 + BIT(NL80211_TID_STATS_TX_MSDU) | 7355 + BIT(NL80211_TID_STATS_TX_MSDU_RETRIES) | 7356 + BIT(NL80211_TID_STATS_TX_MSDU_FAILED); 7357 + } 7358 + } 7359 + } 7360 + 7179 7361 static int nl80211_dump_station(struct sk_buff *skb, 7180 7362 struct netlink_callback *cb) 7181 7363 { ··· 7392 7210 break; 7393 7211 if (err) 7394 7212 goto out_err; 7213 + 7214 + if (sinfo.valid_links) 7215 + cfg80211_sta_set_mld_sinfo(&sinfo); 7395 7216 7396 7217 if (nl80211_send_station(skb, NL80211_CMD_NEW_STATION, 7397 7218 NETLINK_CB(cb->skb).portid, ··· 7443 7258 cfg80211_sinfo_release_content(&sinfo); 7444 7259 return -ENOMEM; 7445 7260 } 7261 + 7262 + if (sinfo.valid_links) 7263 + cfg80211_sta_set_mld_sinfo(&sinfo); 7446 7264 7447 7265 if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION, 7448 7266 info->snd_portid, info->snd_seq, 0,