diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c index 6356e17c3..1a2b4e587 100644 --- a/src/ap/ctrl_iface_ap.c +++ b/src/ap/ctrl_iface_ap.c @@ -32,17 +32,86 @@ static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd, { struct hostap_sta_driver_data data; int ret; + int len = 0; if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0) return 0; ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n" - "rx_bytes=%llu\ntx_bytes=%llu\ninactive_msec=%lu\n", + "rx_bytes=%llu\ntx_bytes=%llu\ninactive_msec=%lu\n" + "signal=%d\n", data.rx_packets, data.tx_packets, - data.rx_bytes, data.tx_bytes, data.inactive_msec); + data.rx_bytes, data.tx_bytes, data.inactive_msec, + data.signal); if (os_snprintf_error(buflen, ret)) return 0; - return ret; + len += ret; + + ret = os_snprintf(buf + len, buflen - len, "rx_rate_info=%lu", + data.current_rx_rate); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + if (data.flags & STA_DRV_DATA_RX_MCS) { + ret = os_snprintf(buf + len, buflen - len, " mcs %u", + data.rx_mcs); + if (!os_snprintf_error(buflen - len, ret)) + len += ret; + } + if (data.flags & STA_DRV_DATA_RX_VHT_MCS) { + ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u", + data.rx_vhtmcs); + if (!os_snprintf_error(buflen - len, ret)) + len += ret; + } + if (data.flags & STA_DRV_DATA_RX_VHT_NSS) { + ret = os_snprintf(buf + len, buflen - len, " vhtnss %u", + data.rx_vht_nss); + if (!os_snprintf_error(buflen - len, ret)) + len += ret; + } + if (data.flags & STA_DRV_DATA_RX_SHORT_GI) { + ret = os_snprintf(buf + len, buflen - len, " shortGI"); + if (!os_snprintf_error(buflen - len, ret)) + len += ret; + } + ret = os_snprintf(buf + len, buflen - len, "\n"); + if (!os_snprintf_error(buflen - len, ret)) + len += ret; + + ret = os_snprintf(buf + len, buflen - len, "tx_rate_info=%lu", + data.current_tx_rate); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + if (data.flags & STA_DRV_DATA_TX_MCS) { + ret = os_snprintf(buf + len, buflen - len, " mcs %u", + data.tx_mcs); + if (!os_snprintf_error(buflen - len, ret)) + len += ret; + } + if (data.flags & STA_DRV_DATA_TX_VHT_MCS) { + ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u", + data.tx_vhtmcs); + if (!os_snprintf_error(buflen - len, ret)) + len += ret; + } + if (data.flags & STA_DRV_DATA_TX_VHT_NSS) { + ret = os_snprintf(buf + len, buflen - len, " vhtnss %u", + data.tx_vht_nss); + if (!os_snprintf_error(buflen - len, ret)) + len += ret; + } + if (data.flags & STA_DRV_DATA_TX_SHORT_GI) { + ret = os_snprintf(buf + len, buflen - len, " shortGI"); + if (!os_snprintf_error(buflen - len, ret)) + len += ret; + } + ret = os_snprintf(buf + len, buflen - len, "\n"); + if (!os_snprintf_error(buflen - len, ret)) + len += ret; + + return len; } diff --git a/src/drivers/driver.h b/src/drivers/driver.h index f8631c7ba..e0be4e51b 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1684,18 +1684,35 @@ struct wpa_driver_capa { struct hostapd_data; +#define STA_DRV_DATA_TX_MCS BIT(0) +#define STA_DRV_DATA_RX_MCS BIT(1) +#define STA_DRV_DATA_TX_VHT_MCS BIT(2) +#define STA_DRV_DATA_RX_VHT_MCS BIT(3) +#define STA_DRV_DATA_TX_VHT_NSS BIT(4) +#define STA_DRV_DATA_RX_VHT_NSS BIT(5) +#define STA_DRV_DATA_TX_SHORT_GI BIT(6) +#define STA_DRV_DATA_RX_SHORT_GI BIT(7) + struct hostap_sta_driver_data { unsigned long rx_packets, tx_packets; unsigned long long rx_bytes, tx_bytes; int bytes_64bit; /* whether 64-bit byte counters are supported */ unsigned long current_tx_rate; + unsigned long current_rx_rate; unsigned long inactive_msec; - unsigned long flags; + unsigned long flags; /* bitfield of STA_DRV_DATA_* */ unsigned long num_ps_buf_frames; unsigned long tx_retry_failed; unsigned long tx_retry_count; int last_rssi; int last_ack_rssi; + s8 signal; + u8 rx_vhtmcs; + u8 tx_vhtmcs; + u8 rx_mcs; + u8 tx_mcs; + u8 rx_vht_nss; + u8 tx_vht_nss; }; struct hostapd_sta_add_params { diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 23bfae1de..7ff4f45e0 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -5941,6 +5941,16 @@ static int get_sta_handler(struct nl_msg *msg, void *arg) [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 }, [NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 }, [NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 }, + [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, + }; + struct nlattr *rate[NL80211_RATE_INFO_MAX + 1]; + static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = { + [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 }, + [NL80211_RATE_INFO_BITRATE32] = { .type = NLA_U32 }, + [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 }, + [NL80211_RATE_INFO_VHT_MCS] = { .type = NLA_U8 }, + [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG }, + [NL80211_RATE_INFO_VHT_NSS] = { .type = NLA_U8 }, }; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), @@ -5992,6 +6002,67 @@ static int get_sta_handler(struct nl_msg *msg, void *arg) if (stats[NL80211_STA_INFO_TX_FAILED]) data->tx_retry_failed = nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]); + if (stats[NL80211_STA_INFO_SIGNAL]) + data->signal = nla_get_u8(stats[NL80211_STA_INFO_SIGNAL]); + + if (stats[NL80211_STA_INFO_TX_BITRATE] && + nla_parse_nested(rate, NL80211_RATE_INFO_MAX, + stats[NL80211_STA_INFO_TX_BITRATE], + rate_policy) == 0) { + if (rate[NL80211_RATE_INFO_BITRATE32]) + data->current_tx_rate = + nla_get_u32(rate[NL80211_RATE_INFO_BITRATE32]); + else if (rate[NL80211_RATE_INFO_BITRATE]) + data->current_tx_rate = + nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]); + + if (rate[NL80211_RATE_INFO_MCS]) { + data->tx_mcs = nla_get_u8(rate[NL80211_RATE_INFO_MCS]); + data->flags |= STA_DRV_DATA_TX_MCS; + } + if (rate[NL80211_RATE_INFO_VHT_MCS]) { + data->tx_vhtmcs = + nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]); + data->flags |= STA_DRV_DATA_TX_VHT_MCS; + } + if (rate[NL80211_RATE_INFO_SHORT_GI]) + data->flags |= STA_DRV_DATA_TX_SHORT_GI; + if (rate[NL80211_RATE_INFO_VHT_NSS]) { + data->tx_vht_nss = + nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]); + data->flags |= STA_DRV_DATA_TX_VHT_NSS; + } + } + + if (stats[NL80211_STA_INFO_RX_BITRATE] && + nla_parse_nested(rate, NL80211_RATE_INFO_MAX, + stats[NL80211_STA_INFO_RX_BITRATE], + rate_policy) == 0) { + if (rate[NL80211_RATE_INFO_BITRATE32]) + data->current_rx_rate = + nla_get_u32(rate[NL80211_RATE_INFO_BITRATE32]); + else if (rate[NL80211_RATE_INFO_BITRATE]) + data->current_rx_rate = + nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]); + + if (rate[NL80211_RATE_INFO_MCS]) { + data->rx_mcs = + nla_get_u8(rate[NL80211_RATE_INFO_MCS]); + data->flags |= STA_DRV_DATA_RX_MCS; + } + if (rate[NL80211_RATE_INFO_VHT_MCS]) { + data->rx_vhtmcs = + nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]); + data->flags |= STA_DRV_DATA_RX_VHT_MCS; + } + if (rate[NL80211_RATE_INFO_SHORT_GI]) + data->flags |= STA_DRV_DATA_RX_SHORT_GI; + if (rate[NL80211_RATE_INFO_VHT_NSS]) { + data->rx_vht_nss = + nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]); + data->flags |= STA_DRV_DATA_RX_VHT_NSS; + } + } return NL_SKIP; }