+static void print_power_mode(struct nlattr *a)
+{
+ enum nl80211_mesh_power_mode pm = nla_get_u32(a);
+
+ switch (pm) {
+ case NL80211_MESH_POWER_ACTIVE:
+ printf("ACTIVE");
+ break;
+ case NL80211_MESH_POWER_LIGHT_SLEEP:
+ printf("LIGHT SLEEP");
+ break;
+ case NL80211_MESH_POWER_DEEP_SLEEP:
+ printf("DEEP SLEEP");
+ break;
+ default:
+ printf("UNKNOWN");
+ break;
+ }
+}
+
+void parse_tid_stats(struct nlattr *tid_stats_attr)
+{
+ struct nlattr *stats_info[NL80211_TID_STATS_MAX + 1], *tidattr, *info;
+ static struct nla_policy stats_policy[NL80211_TID_STATS_MAX + 1] = {
+ [NL80211_TID_STATS_RX_MSDU] = { .type = NLA_U64 },
+ [NL80211_TID_STATS_TX_MSDU] = { .type = NLA_U64 },
+ [NL80211_TID_STATS_TX_MSDU_RETRIES] = { .type = NLA_U64 },
+ [NL80211_TID_STATS_TX_MSDU_FAILED] = { .type = NLA_U64 },
+ };
+ int rem, i = 0;
+
+ printf("\n\tMSDU:\n\t\tTID\trx\ttx\ttx retries\ttx failed");
+ nla_for_each_nested(tidattr, tid_stats_attr, rem) {
+ if (nla_parse_nested(stats_info, NL80211_TID_STATS_MAX,
+ tidattr, stats_policy)) {
+ printf("failed to parse nested stats attributes!");
+ return;
+ }
+ printf("\n\t\t%d", i++);
+ info = stats_info[NL80211_TID_STATS_RX_MSDU];
+ if (info)
+ printf("\t%llu", (unsigned long long)nla_get_u64(info));
+ info = stats_info[NL80211_TID_STATS_TX_MSDU];
+ if (info)
+ printf("\t%llu", (unsigned long long)nla_get_u64(info));
+ info = stats_info[NL80211_TID_STATS_TX_MSDU_RETRIES];
+ if (info)
+ printf("\t%llu", (unsigned long long)nla_get_u64(info));
+ info = stats_info[NL80211_TID_STATS_TX_MSDU_FAILED];
+ if (info)
+ printf("\t\t%llu", (unsigned long long)nla_get_u64(info));
+ }
+}
+
+void parse_bss_param(struct nlattr *bss_param_attr)
+{
+ struct nlattr *bss_param_info[NL80211_STA_BSS_PARAM_MAX + 1], *info;
+ static struct nla_policy bss_poilcy[NL80211_STA_BSS_PARAM_MAX + 1] = {
+ [NL80211_STA_BSS_PARAM_CTS_PROT] = { .type = NLA_FLAG },
+ [NL80211_STA_BSS_PARAM_SHORT_PREAMBLE] = { .type = NLA_FLAG },
+ [NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME] = { .type = NLA_FLAG },
+ [NL80211_STA_BSS_PARAM_DTIM_PERIOD] = { .type = NLA_U8 },
+ [NL80211_STA_BSS_PARAM_BEACON_INTERVAL] = { .type = NLA_U16 },
+ };
+
+ if (nla_parse_nested(bss_param_info, NL80211_STA_BSS_PARAM_MAX,
+ bss_param_attr, bss_poilcy)) {
+ printf("failed to parse nested bss param attributes!");
+ }
+
+ info = bss_param_info[NL80211_STA_BSS_PARAM_DTIM_PERIOD];
+ if (info)
+ printf("\n\tDTIM period:\t%u", nla_get_u8(info));
+ info = bss_param_info[NL80211_STA_BSS_PARAM_BEACON_INTERVAL];
+ if (info)
+ printf("\n\tbeacon interval:%u", nla_get_u16(info));
+ info = bss_param_info[NL80211_STA_BSS_PARAM_CTS_PROT];
+ if (info) {
+ printf("\n\tCTS protection:");
+ if (nla_get_u16(info))
+ printf("\tyes");
+ else
+ printf("\tno");
+ }
+ info = bss_param_info[NL80211_STA_BSS_PARAM_SHORT_PREAMBLE];
+ if (info) {
+ printf("\n\tshort preamble:");
+ if (nla_get_u16(info))
+ printf("\tyes");
+ else
+ printf("\tno");
+ }
+ info = bss_param_info[NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME];
+ if (info) {
+ printf("\n\tshort slot time:");
+ if (nla_get_u16(info))
+ printf("yes");
+ else
+ printf("no");
+ }
+}
+
+void parse_bitrate(struct nlattr *bitrate_attr, char *buf, int buflen)
+{
+ int rate = 0;
+ char *pos = buf;
+ struct nlattr *rinfo[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_40_MHZ_WIDTH] = { .type = NLA_FLAG },
+ [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
+ };
+
+ if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
+ bitrate_attr, rate_policy)) {
+ snprintf(buf, buflen, "failed to parse nested rate attributes!");
+ return;
+ }
+
+ if (rinfo[NL80211_RATE_INFO_BITRATE32])
+ rate = nla_get_u32(rinfo[NL80211_RATE_INFO_BITRATE32]);
+ else if (rinfo[NL80211_RATE_INFO_BITRATE])
+ rate = nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]);
+ if (rate > 0)
+ pos += snprintf(pos, buflen - (pos - buf),
+ "%d.%d MBit/s", rate / 10, rate % 10);
+
+ if (rinfo[NL80211_RATE_INFO_MCS])
+ pos += snprintf(pos, buflen - (pos - buf),
+ " MCS %d", nla_get_u8(rinfo[NL80211_RATE_INFO_MCS]));
+ if (rinfo[NL80211_RATE_INFO_VHT_MCS])
+ pos += snprintf(pos, buflen - (pos - buf),
+ " VHT-MCS %d", nla_get_u8(rinfo[NL80211_RATE_INFO_VHT_MCS]));
+ if (rinfo[NL80211_RATE_INFO_40_MHZ_WIDTH])
+ pos += snprintf(pos, buflen - (pos - buf), " 40MHz");
+ if (rinfo[NL80211_RATE_INFO_80_MHZ_WIDTH])
+ pos += snprintf(pos, buflen - (pos - buf), " 80MHz");
+ if (rinfo[NL80211_RATE_INFO_80P80_MHZ_WIDTH])
+ pos += snprintf(pos, buflen - (pos - buf), " 80P80MHz");
+ if (rinfo[NL80211_RATE_INFO_160_MHZ_WIDTH])
+ pos += snprintf(pos, buflen - (pos - buf), " 160MHz");
+ if (rinfo[NL80211_RATE_INFO_SHORT_GI])
+ pos += snprintf(pos, buflen - (pos - buf), " short GI");
+ if (rinfo[NL80211_RATE_INFO_VHT_NSS])
+ pos += snprintf(pos, buflen - (pos - buf),
+ " VHT-NSS %d", nla_get_u8(rinfo[NL80211_RATE_INFO_VHT_NSS]));
+}
+
+static char *get_chain_signal(struct nlattr *attr_list)
+{
+ struct nlattr *attr;
+ static char buf[64];
+ char *cur = buf;
+ int i = 0, rem;
+ const char *prefix;