@@ -2174,6 +2174,12 @@ struct link_station_info {
* @valid_links: bitmap of valid links, or 0 for non-MLO. Drivers fill this
* information in cfg80211_new_sta(), cfg80211_del_sta_sinfo(),
* get_station() and dump_station() callbacks.
+ * @rx_packets: packets (MSDUs & MMPDUs) received from this station
+ * @tx_packets: packets (MSDUs & MMPDUs) transmitted to this station
+ * @rx_bytes: bytes (size of MPDUs) received from this station
+ * @tx_bytes: bytes (size of MPDUs) transmitted to this station
+ * @tx_retries: cumulative retry counts (MPDUs)
+ * @tx_failed: number of failed transmissions (MPDUs) (retries exceeded, no ACK)
* @deflink: This holds the default link STA information, for non MLO STA
* all link specific STA information is accessed through @deflink.
* @links: reference to Link sta entries for MLO.
@@ -2206,6 +2212,13 @@ struct station_info {
size_t assoc_resp_ies_len;
u16 valid_links;
+ u32 rx_packets;
+ u32 tx_packets;
+ u64 rx_bytes;
+ u64 tx_bytes;
+ u32 tx_retries;
+ u32 tx_failed;
+
struct link_station_info deflink;
/* TODO: Need to check and add protection access to links memory */
struct link_station_info *links[IEEE80211_MLD_MAX_NUM_LINKS];
@@ -2836,6 +2836,55 @@ static void sta_set_link_sinfo(struct sta_info *sta, struct link_station_info *l
}
}
+static void sta_set_mld_sinfo(struct station_info *sinfo, struct sta_info *sta)
+{
+ struct link_station_info *link_sinfo;
+ struct link_sta_info *link_sta;
+ int link_id;
+
+ for_each_valid_link(sinfo, link_id) {
+ link_sta =
+ rcu_dereference_protected(sta->link[link_id],
+ lockdep_is_held(&sta->local->hw.wiphy->mtx));
+ if (!link_sta)
+ continue;
+
+ link_sinfo = sinfo->links[link_id];
+
+ if ((link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_PACKETS))) {
+ sinfo->tx_packets += link_sinfo->tx_packets;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS);
+ }
+
+ if ((link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_PACKETS))) {
+ sinfo->rx_packets += link_sinfo->rx_packets;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS);
+ }
+
+ if (link_sinfo->filled & (BIT_ULL(NL80211_STA_INFO_TX_BYTES) |
+ BIT_ULL(NL80211_STA_INFO_TX_BYTES64))) {
+ sinfo->tx_bytes += link_sinfo->tx_bytes;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES);
+ }
+
+ if (link_sinfo->filled & (BIT_ULL(NL80211_STA_INFO_RX_BYTES) |
+ BIT_ULL(NL80211_STA_INFO_TX_BYTES64))) {
+ sinfo->rx_bytes += link_sinfo->rx_bytes;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES);
+ }
+
+ if (link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_RETRIES)) {
+ sinfo->tx_retries += link_sinfo->tx_retries;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES);
+ }
+
+ if (link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_FAILED)) {
+ sinfo->tx_failed += link_sinfo->tx_failed;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
+ }
+ }
+}
+
void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
bool tidstats)
{
@@ -2905,6 +2954,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
sta_set_link_sinfo(sta, link_sinfo, link_sdata, tidstats);
sinfo->links[link_id] = link_sinfo;
}
+ sta_set_mld_sinfo(sinfo, sta);
} else {
link_sinfo = &sinfo->deflink;
link_sinfo->link_id = -1;
@@ -6838,6 +6838,36 @@ static int nl80211_fill_link_station(struct sk_buff *msg,
return 0;
}
+static int nl80211_fill_mld_station(struct sk_buff *msg,
+ struct station_info *sinfo)
+{
+#define PUT_SINFO(attr, memb, type) do { \
+ BUILD_BUG_ON(sizeof(type) == sizeof(u64)); \
+ if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_ ## attr) && \
+ nla_put_ ## type(msg, NL80211_STA_INFO_ ## attr, \
+ sinfo->memb)) \
+ return -EMSGSIZE; \
+ } while (0)
+#define PUT_SINFO_U64(attr, memb) do { \
+ if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_ ## attr) && \
+ nla_put_u64_64bit(msg, NL80211_STA_INFO_ ## attr, \
+ sinfo->memb, NL80211_STA_INFO_PAD)) \
+ return -EMSGSIZE; \
+ } while (0)
+
+ PUT_SINFO(RX_PACKETS, rx_packets, u32);
+ PUT_SINFO(TX_PACKETS, tx_packets, u32);
+ PUT_SINFO_U64(RX_BYTES, rx_bytes);
+ PUT_SINFO_U64(TX_BYTES, tx_bytes);
+ PUT_SINFO(TX_RETRIES, tx_retries, u32);
+ PUT_SINFO(TX_FAILED, tx_failed, u32);
+
+#undef PUT_SINFO
+#undef PUT_SINFO_U64
+
+ return 0;
+}
+
static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
u32 seq, int flags,
struct cfg80211_registered_device *rdev,
@@ -6912,9 +6942,9 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
#undef PUT_SINFO_U64
if (sinfo->valid_links) {
- /* TODO: Add accumulated stats for packets, bytes for
- * better representation at MLO level.
- */
+ ret = nl80211_fill_mld_station(msg, sinfo);
+ if (ret)
+ goto nla_put_failure;
/* Closing nested STA_INFO as MLO links ATTR should not
* be in nested STA_INFO
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. Accumulated statistics are useful to provide comprehensive overview for the ML stations. Statistics such as packets and bytes are useful for observing the total packets sent and received at the station level. However, MLO statistics for rates and signal can not be accumulated since it won't make much sense. Hence, a subsequent change will handle signal and rates bit differently at MLO level. Hence, add accumulated statistics for MLO station. Also, for non-ML station accumulated statistics make no sense. The statistics could be embedded into NL message as below: For MLO: cmd -> NL80211_ATTR_IFINDEX NL80211_ATTR_MAC NL80211_ATTR_GENERATION ......etc NL80211_ATTR_STA_INFO | nest flag NL80211_STA_INFO_CONNECTED_TIME, NL80211_STA_INFO_STA_FLAGS, NL80211_STA_INFO_RX_BYTES, //accumulated data NL80211_STA_INFO_TX_BYTES, ......etc NL80211_ATTR_MLO_LINK_ID, NL80211_ATTR_MLD_ADDR, NL80211_ATTR_MLO_LINKS | nested link_id-1 | nested NL80211_ATTR_MLO_LINK_ID, NL80211_ATTR_MLD_ADDR, NL80211_ATTR_STA_INFO | nest flag NL80211_STA_INFO_RX_BYTES, NL80211_STA_INFO_TX_BYTES, ..........etc. link_id-2 | nested NL80211_ATTR_MLO_LINK_ID, NL80211_ATTR_MLD_ADDR, NL80211_ATTR_STA_INFO | nest flag NL80211_STA_INFO_RX_BYTES, NL80211_STA_INFO_TX_BYTES, .........etc The output of iw dev wlan0 station dump for MLO could look like below: Station 00:03:7f:04:31:78 (on wlan0) authorized: yes authenticated: yes associated: yes preamble: long WMM/WME: yes MFP: yes TDLS peer: no connected time: 383 seconds associated at [boottime]: 93.740s associated at: 93685 ms rx bytes: 1439 rx packets: 15 tx bytes: 1538 tx packets: 8 tx retries: 0 tx failed: 0 current time: 474340 ms MLD address: 00:03:7f:04:31:78 Link 0: Address: 00:03:7f:04:31:78 inactive time: 330120 ms rx bytes: 116 rx packets: 3 tx bytes: 0 tx packets: 0 tx retries: 0 tx failed: 0 rx drop misc: 0 signal: -95 dBm tx bitrate: 6.0 MBit/s tx duration: 2669 us rx duration: 0 us DTIM period: 2 beacon interval:100 Link 1: Address: 00:03:7f:04:31:79 inactive time: 81268 ms rx bytes: 1323 rx packets: 12 tx bytes: 1538 tx packets: 8 tx retries: 0 tx failed: 0 rx drop misc: 0 signal: -95 dBm tx bitrate: 6.0 MBit/s tx duration: 2669 us rx bitrate: 6.0 MBit/s rx duration: 0 us DTIM period: 2 beacon interval:100 Signed-off-by: Sarika Sharma <quic_sarishar@quicinc.com> --- include/net/cfg80211.h | 13 +++++++++++ net/mac80211/sta_info.c | 50 +++++++++++++++++++++++++++++++++++++++++ net/wireless/nl80211.c | 36 ++++++++++++++++++++++++++--- 3 files changed, 96 insertions(+), 3 deletions(-)