Add TX/RX rate info and signal strength into STA output

These allow external programs to fetch the TX and RX rate information
and signal strength for a specific STA through the hostapd control
interface command "STA <addr>". The values of these attributes are
filled in the response of nl80211 command NL80211_CMD_GET_STATION.

Signed-off-by: bhagavathi perumal s <bperumal@qti.qualcomm.com>
This commit is contained in:
bhagavathi perumal s 2017-09-26 11:55:52 +05:30 committed by Jouni Malinen
parent fa4b605a0d
commit 3567641ebb
3 changed files with 161 additions and 4 deletions

View file

@ -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;
}

View file

@ -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 {

View file

@ -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;
}