@@ -6728,6 +6728,185 @@ static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal,
67286728 return true;
67296729}
67306730
6731+ static int nl80211_fill_link_station(struct sk_buff *msg,
6732+ struct cfg80211_registered_device *rdev,
6733+ struct link_station_info *link_sinfo)
6734+ {
6735+ struct nlattr *bss_param, *link_sinfoattr;
6736+
6737+ #define PUT_LINK_SINFO(attr, memb, type) do { \
6738+ BUILD_BUG_ON(sizeof(type) == sizeof(u64)); \
6739+ if (link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_ ## attr) && \
6740+ nla_put_ ## type(msg, NL80211_STA_INFO_ ## attr, \
6741+ link_sinfo->memb)) \
6742+ goto nla_put_failure; \
6743+ } while (0)
6744+ #define PUT_LINK_SINFO_U64(attr, memb) do { \
6745+ if (link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_ ## attr) && \
6746+ nla_put_u64_64bit(msg, NL80211_STA_INFO_ ## attr, \
6747+ link_sinfo->memb, NL80211_STA_INFO_PAD)) \
6748+ goto nla_put_failure; \
6749+ } while (0)
6750+
6751+ link_sinfoattr = nla_nest_start_noflag(msg, NL80211_ATTR_STA_INFO);
6752+ if (!link_sinfoattr)
6753+ goto nla_put_failure;
6754+
6755+ PUT_LINK_SINFO(INACTIVE_TIME, inactive_time, u32);
6756+
6757+ if (link_sinfo->filled & (BIT_ULL(NL80211_STA_INFO_RX_BYTES) |
6758+ BIT_ULL(NL80211_STA_INFO_RX_BYTES64)) &&
6759+ nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES,
6760+ (u32)link_sinfo->rx_bytes))
6761+ goto nla_put_failure;
6762+
6763+ if (link_sinfo->filled & (BIT_ULL(NL80211_STA_INFO_TX_BYTES) |
6764+ BIT_ULL(NL80211_STA_INFO_TX_BYTES64)) &&
6765+ nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES,
6766+ (u32)link_sinfo->tx_bytes))
6767+ goto nla_put_failure;
6768+
6769+ PUT_LINK_SINFO_U64(RX_BYTES64, rx_bytes);
6770+ PUT_LINK_SINFO_U64(TX_BYTES64, tx_bytes);
6771+ PUT_LINK_SINFO_U64(RX_DURATION, rx_duration);
6772+ PUT_LINK_SINFO_U64(TX_DURATION, tx_duration);
6773+
6774+ if (wiphy_ext_feature_isset(&rdev->wiphy,
6775+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
6776+ PUT_LINK_SINFO(AIRTIME_WEIGHT, airtime_weight, u16);
6777+
6778+ switch (rdev->wiphy.signal_type) {
6779+ case CFG80211_SIGNAL_TYPE_MBM:
6780+ PUT_LINK_SINFO(SIGNAL, signal, u8);
6781+ PUT_LINK_SINFO(SIGNAL_AVG, signal_avg, u8);
6782+ break;
6783+ default:
6784+ break;
6785+ }
6786+ if (link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) {
6787+ if (!nl80211_put_signal(msg, link_sinfo->chains,
6788+ link_sinfo->chain_signal,
6789+ NL80211_STA_INFO_CHAIN_SIGNAL))
6790+ goto nla_put_failure;
6791+ }
6792+ if (link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) {
6793+ if (!nl80211_put_signal(msg, link_sinfo->chains,
6794+ link_sinfo->chain_signal_avg,
6795+ NL80211_STA_INFO_CHAIN_SIGNAL_AVG))
6796+ goto nla_put_failure;
6797+ }
6798+ if (link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE)) {
6799+ if (!nl80211_put_sta_rate(msg, &link_sinfo->txrate,
6800+ NL80211_STA_INFO_TX_BITRATE))
6801+ goto nla_put_failure;
6802+ }
6803+ if (link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE)) {
6804+ if (!nl80211_put_sta_rate(msg, &link_sinfo->rxrate,
6805+ NL80211_STA_INFO_RX_BITRATE))
6806+ goto nla_put_failure;
6807+ }
6808+
6809+ PUT_LINK_SINFO(RX_PACKETS, rx_packets, u32);
6810+ PUT_LINK_SINFO(TX_PACKETS, tx_packets, u32);
6811+ PUT_LINK_SINFO(TX_RETRIES, tx_retries, u32);
6812+ PUT_LINK_SINFO(TX_FAILED, tx_failed, u32);
6813+ PUT_LINK_SINFO(EXPECTED_THROUGHPUT, expected_throughput, u32);
6814+ PUT_LINK_SINFO(BEACON_LOSS, beacon_loss_count, u32);
6815+
6816+ if (link_sinfo->filled & BIT_ULL(NL80211_STA_INFO_BSS_PARAM)) {
6817+ bss_param = nla_nest_start_noflag(msg,
6818+ NL80211_STA_INFO_BSS_PARAM);
6819+ if (!bss_param)
6820+ goto nla_put_failure;
6821+
6822+ if (((link_sinfo->bss_param.flags &
6823+ BSS_PARAM_FLAGS_CTS_PROT) &&
6824+ nla_put_flag(msg, NL80211_STA_BSS_PARAM_CTS_PROT)) ||
6825+ ((link_sinfo->bss_param.flags &
6826+ BSS_PARAM_FLAGS_SHORT_PREAMBLE) &&
6827+ nla_put_flag(msg,
6828+ NL80211_STA_BSS_PARAM_SHORT_PREAMBLE)) ||
6829+ ((link_sinfo->bss_param.flags &
6830+ BSS_PARAM_FLAGS_SHORT_SLOT_TIME) &&
6831+ nla_put_flag(msg,
6832+ NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME)) ||
6833+ nla_put_u8(msg, NL80211_STA_BSS_PARAM_DTIM_PERIOD,
6834+ link_sinfo->bss_param.dtim_period) ||
6835+ nla_put_u16(msg, NL80211_STA_BSS_PARAM_BEACON_INTERVAL,
6836+ link_sinfo->bss_param.beacon_interval))
6837+ goto nla_put_failure;
6838+
6839+ nla_nest_end(msg, bss_param);
6840+ }
6841+
6842+ PUT_LINK_SINFO_U64(RX_DROP_MISC, rx_dropped_misc);
6843+ PUT_LINK_SINFO_U64(BEACON_RX, rx_beacon);
6844+ PUT_LINK_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8);
6845+ PUT_LINK_SINFO(RX_MPDUS, rx_mpdu_count, u32);
6846+ PUT_LINK_SINFO(FCS_ERROR_COUNT, fcs_err_count, u32);
6847+ if (wiphy_ext_feature_isset(&rdev->wiphy,
6848+ NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT)) {
6849+ PUT_LINK_SINFO(ACK_SIGNAL, ack_signal, u8);
6850+ PUT_LINK_SINFO(ACK_SIGNAL_AVG, avg_ack_signal, s8);
6851+ }
6852+
6853+ #undef PUT_LINK_SINFO
6854+ #undef PUT_LINK_SINFO_U64
6855+
6856+ if (link_sinfo->pertid) {
6857+ struct nlattr *tidsattr;
6858+ int tid;
6859+
6860+ tidsattr = nla_nest_start_noflag(msg,
6861+ NL80211_STA_INFO_TID_STATS);
6862+ if (!tidsattr)
6863+ goto nla_put_failure;
6864+
6865+ for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) {
6866+ struct cfg80211_tid_stats *tidstats;
6867+ struct nlattr *tidattr;
6868+
6869+ tidstats = &link_sinfo->pertid[tid];
6870+
6871+ if (!tidstats->filled)
6872+ continue;
6873+
6874+ tidattr = nla_nest_start_noflag(msg, tid + 1);
6875+ if (!tidattr)
6876+ goto nla_put_failure;
6877+
6878+ #define PUT_TIDVAL_U64(attr, memb) do { \
6879+ if (tidstats->filled & BIT(NL80211_TID_STATS_ ## attr) && \
6880+ nla_put_u64_64bit(msg, NL80211_TID_STATS_ ## attr, \
6881+ tidstats->memb, NL80211_TID_STATS_PAD)) \
6882+ goto nla_put_failure; \
6883+ } while (0)
6884+
6885+ PUT_TIDVAL_U64(RX_MSDU, rx_msdu);
6886+ PUT_TIDVAL_U64(TX_MSDU, tx_msdu);
6887+ PUT_TIDVAL_U64(TX_MSDU_RETRIES, tx_msdu_retries);
6888+ PUT_TIDVAL_U64(TX_MSDU_FAILED, tx_msdu_failed);
6889+
6890+ #undef PUT_TIDVAL_U64
6891+ if ((tidstats->filled &
6892+ BIT(NL80211_TID_STATS_TXQ_STATS)) &&
6893+ !nl80211_put_txq_stats(msg, &tidstats->txq_stats,
6894+ NL80211_TID_STATS_TXQ_STATS))
6895+ goto nla_put_failure;
6896+
6897+ nla_nest_end(msg, tidattr);
6898+ }
6899+
6900+ nla_nest_end(msg, tidsattr);
6901+ }
6902+
6903+ nla_nest_end(msg, link_sinfoattr);
6904+ return 0;
6905+
6906+ nla_put_failure:
6907+ return -EMSGSIZE;
6908+ }
6909+
67316910static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
67326911 u32 seq, int flags,
67336912 struct cfg80211_registered_device *rdev,
@@ -6736,6 +6915,9 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
67366915{
67376916 void *hdr;
67386917 struct nlattr *sinfoattr, *bss_param;
6918+ struct link_station_info *link_sinfo;
6919+ struct nlattr *links, *link;
6920+ int link_id;
67396921
67406922 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
67416923 if (!hdr) {
@@ -6950,6 +7132,40 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
69507132 goto nla_put_failure;
69517133 }
69527134
7135+ if (sinfo->valid_links) {
7136+ links = nla_nest_start(msg, NL80211_ATTR_MLO_LINKS);
7137+ if (!links)
7138+ goto nla_put_failure;
7139+
7140+ for_each_valid_link(sinfo, link_id) {
7141+ link_sinfo = sinfo->links[link_id];
7142+
7143+ if (WARN_ON_ONCE(!link_sinfo))
7144+ continue;
7145+
7146+ if (!is_valid_ether_addr(link_sinfo->addr))
7147+ continue;
7148+
7149+ link = nla_nest_start(msg, link_id + 1);
7150+ if (!link)
7151+ goto nla_put_failure;
7152+
7153+ if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID,
7154+ link_id))
7155+ goto nla_put_failure;
7156+
7157+ if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN,
7158+ link_sinfo->addr))
7159+ goto nla_put_failure;
7160+
7161+ if (nl80211_fill_link_station(msg, rdev, link_sinfo))
7162+ goto nla_put_failure;
7163+
7164+ nla_nest_end(msg, link);
7165+ }
7166+ nla_nest_end(msg, links);
7167+ }
7168+
69537169 cfg80211_sinfo_release_content(sinfo);
69547170 genlmsg_end(msg, hdr);
69557171 return 0;
0 commit comments