]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Add TX/RX rate info and signal strength into STA output
authorbhagavathi perumal s <bperumal@qti.qualcomm.com>
Tue, 26 Sep 2017 06:25:52 +0000 (11:55 +0530)
committerJouni Malinen <j@w1.fi>
Thu, 5 Oct 2017 09:12:24 +0000 (12:12 +0300)
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>
src/ap/ctrl_iface_ap.c
src/drivers/driver.h
src/drivers/driver_nl80211.c

index 6356e17c38998423b454c06aef6969af2fda8dfe..1a2b4e587727194c534814b13333c0f050721983 100644 (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;
 }
 
 
index f8631c7ba7ce14aa638ee8d89e84b92a748c46d2..e0be4e51b3c488c47f14dce7e35d75bf0cb57ce1 100644 (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 {
index 23bfae1de6897764ccc85a9d2c4e1ab24d13082d..7ff4f45e010752a7c404f9b8ec4fe89f16f5500b 100644 (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;
 }