--- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -2175,6 +2175,10 @@ struct hostap_sta_driver_data { u8 tx_mcs; u8 rx_vht_nss; u8 tx_vht_nss; + u8 rx_hemcs; + u8 tx_hemcs; + u8 rx_he_nss; + u8 tx_he_nss; }; struct hostapd_sta_add_params { --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -7010,6 +7010,8 @@ static int get_sta_handler(struct nl_msg [NL80211_RATE_INFO_VHT_MCS] = { .type = NLA_U8 }, [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG }, [NL80211_RATE_INFO_VHT_NSS] = { .type = NLA_U8 }, + [NL80211_RATE_INFO_HE_NSS] = { .type = NLA_U8 }, + [NL80211_RATE_INFO_HE_MCS] = { .type = NLA_U8 }, }; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), @@ -7102,6 +7104,10 @@ static int get_sta_handler(struct nl_msg nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]); data->flags |= STA_DRV_DATA_TX_VHT_NSS; } + if (rate[NL80211_RATE_INFO_HE_MCS]) + data->tx_hemcs = nla_get_u8(rate[NL80211_RATE_INFO_HE_MCS]); + if (rate[NL80211_RATE_INFO_HE_NSS]) + data->tx_he_nss = nla_get_u8(rate[NL80211_RATE_INFO_HE_NSS]); } if (stats[NL80211_STA_INFO_RX_BITRATE] && @@ -7132,11 +7138,16 @@ static int get_sta_handler(struct nl_msg nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]); data->flags |= STA_DRV_DATA_RX_VHT_NSS; } + if (rate[NL80211_RATE_INFO_HE_MCS]) + data->rx_hemcs = nla_get_u8(rate[NL80211_RATE_INFO_HE_MCS]); + if (rate[NL80211_RATE_INFO_HE_NSS]) + data->rx_he_nss = nla_get_u8(rate[NL80211_RATE_INFO_HE_NSS]); } if (stats[NL80211_STA_INFO_TID_STATS]) get_sta_tid_stats(data, stats[NL80211_STA_INFO_TID_STATS]); + return NL_SKIP; } --- a/src/ap/ubus.c +++ b/src/ap/ubus.c @@ -306,6 +306,36 @@ hostapd_bss_get_clients(struct ubus_cont blobmsg_add_u32(&b, "tx", sta_driver_data.current_tx_rate * 100); blobmsg_close_table(&b, r); blobmsg_add_u32(&b, "signal", sta_driver_data.signal); + + r = blobmsg_open_table(&b, "mcs"); + if (sta_driver_data.rx_hemcs) { + blobmsg_add_u32(&b, "he", 1); + blobmsg_add_u32(&b, "rx", sta_driver_data.rx_hemcs); + blobmsg_add_u32(&b, "tx", sta_driver_data.tx_hemcs); + } else if (sta_driver_data.rx_vhtmcs) { + blobmsg_add_u32(&b, "vht", 1); + blobmsg_add_u32(&b, "rx", sta_driver_data.rx_vhtmcs); + blobmsg_add_u32(&b, "tx", sta_driver_data.tx_vhtmcs); + } else { + blobmsg_add_u32(&b, "rx", sta_driver_data.rx_mcs); + blobmsg_add_u32(&b, "tx", sta_driver_data.tx_mcs); + } + blobmsg_close_table(&b, r); + + r = blobmsg_open_table(&b, "nss"); + if (sta_driver_data.rx_he_nss) { + blobmsg_add_u32(&b, "he", 1); + blobmsg_add_u32(&b, "rx", sta_driver_data.rx_he_nss); + blobmsg_add_u32(&b, "tx", sta_driver_data.tx_he_nss); + } else if (sta_driver_data.rx_vht_nss) { + blobmsg_add_u32(&b, "vht", 1); + blobmsg_add_u32(&b, "rx", sta_driver_data.rx_vht_nss); + blobmsg_add_u32(&b, "tx", sta_driver_data.tx_vht_nss); + } else { + blobmsg_add_u32(&b, "rx", sta_driver_data.rx_mcs); + blobmsg_add_u32(&b, "tx", sta_driver_data.tx_mcs); + } + blobmsg_close_table(&b, r); } hostapd_parse_capab_blobmsg(sta);