BLOCKED
};
-enum plink_actions {
- PLINK_ACTION_UNDEFINED,
- PLINK_ACTION_OPEN,
- PLINK_ACTION_BLOCK,
-};
-
static void print_power_mode(struct nlattr *a)
{
enum nl80211_mesh_power_mode pm = nla_get_u32(a);
}
}
+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;
+
+ if (!attr_list)
+ return "";
+
+ nla_for_each_nested(attr, attr_list, rem) {
+ if (i++ > 0)
+ prefix = ", ";
+ else
+ prefix = "[";
+
+ cur += snprintf(cur, sizeof(buf) - (cur - buf), "%s%d", prefix,
+ (int8_t) nla_get_u8(attr));
+ }
+
+ if (i)
+ snprintf(cur, sizeof(buf) - (cur - buf), "] ");
+
+ return buf;
+}
+
static int print_sta_handler(struct nl_msg *msg, void *arg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
- struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
char mac_addr[20], state_name[10], dev[20];
struct nl80211_sta_flag_update *sta_flags;
static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
[NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
[NL80211_STA_INFO_T_OFFSET] = { .type = NLA_U64 },
[NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED },
+ [NL80211_STA_INFO_RX_BITRATE] = { .type = NLA_NESTED },
[NL80211_STA_INFO_LLID] = { .type = NLA_U16 },
[NL80211_STA_INFO_PLID] = { .type = NLA_U16 },
[NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 },
[NL80211_STA_INFO_LOCAL_PM] = { .type = NLA_U32},
[NL80211_STA_INFO_PEER_PM] = { .type = NLA_U32},
[NL80211_STA_INFO_NONPEER_PM] = { .type = NLA_U32},
+ [NL80211_STA_INFO_CHAIN_SIGNAL] = { .type = NLA_NESTED },
+ [NL80211_STA_INFO_CHAIN_SIGNAL_AVG] = { .type = NLA_NESTED },
};
-
- 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 },
- };
+ char *chain;
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
if (sinfo[NL80211_STA_INFO_TX_FAILED])
printf("\n\ttx failed:\t%u",
nla_get_u32(sinfo[NL80211_STA_INFO_TX_FAILED]));
+
+ chain = get_chain_signal(sinfo[NL80211_STA_INFO_CHAIN_SIGNAL]);
if (sinfo[NL80211_STA_INFO_SIGNAL])
- printf("\n\tsignal: \t%d dBm",
- (int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]));
+ printf("\n\tsignal: \t%d %sdBm",
+ (int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]),
+ chain);
+
+ chain = get_chain_signal(sinfo[NL80211_STA_INFO_CHAIN_SIGNAL_AVG]);
if (sinfo[NL80211_STA_INFO_SIGNAL_AVG])
- printf("\n\tsignal avg:\t%d dBm",
- (int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL_AVG]));
+ printf("\n\tsignal avg:\t%d %sdBm",
+ (int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL_AVG]),
+ chain);
+
if (sinfo[NL80211_STA_INFO_T_OFFSET])
printf("\n\tToffset:\t%lld us",
(unsigned long long)nla_get_u64(sinfo[NL80211_STA_INFO_T_OFFSET]));
if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
- if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
- sinfo[NL80211_STA_INFO_TX_BITRATE], rate_policy)) {
- fprintf(stderr, "failed to parse nested rate attributes!\n");
- } else {
- int rate = 0;
- printf("\n\ttx bitrate:\t");
- 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)
- printf("%d.%d MBit/s", rate / 10, rate % 10);
-
- if (rinfo[NL80211_RATE_INFO_MCS])
- printf(" MCS %d", nla_get_u8(rinfo[NL80211_RATE_INFO_MCS]));
- if (rinfo[NL80211_RATE_INFO_40_MHZ_WIDTH])
- printf(" 40Mhz");
- if (rinfo[NL80211_RATE_INFO_SHORT_GI])
- printf(" short GI");
- }
+ char buf[100];
+
+ parse_bitrate(sinfo[NL80211_STA_INFO_TX_BITRATE], buf, sizeof(buf));
+ printf("\n\ttx bitrate:\t%s", buf);
+ }
+
+ if (sinfo[NL80211_STA_INFO_RX_BITRATE]) {
+ char buf[100];
+
+ parse_bitrate(sinfo[NL80211_STA_INFO_RX_BITRATE], buf, sizeof(buf));
+ printf("\n\trx bitrate:\t%s", buf);
+ }
+
+ if (sinfo[NL80211_STA_INFO_EXPECTED_THROUGHPUT]) {
+ uint32_t thr;
+
+ thr = nla_get_u32(sinfo[NL80211_STA_INFO_EXPECTED_THROUGHPUT]);
+ /* convert in Mbps but scale by 1000 to save kbps units */
+ thr = thr * 1000 / 1024;
+
+ printf("\n\texpected throughput:\t%u.%uMbps",
+ thr / 1000, thr % 1000);
}
if (sinfo[NL80211_STA_INFO_LLID])
}
if (sta_flags->mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
- printf("\n\tTDLS peer:\t\t");
+ printf("\n\tTDLS peer:\t");
if (sta_flags->set & BIT(NL80211_STA_FLAG_TDLS_PEER))
printf("yes");
else
}
}
+ if (sinfo[NL80211_STA_INFO_CONNECTED_TIME])
+ printf("\n\tconnected time:\t%u seconds",
+ nla_get_u32(sinfo[NL80211_STA_INFO_CONNECTED_TIME]));
+
printf("\n");
return NL_SKIP;
}
static int handle_station_get(struct nl80211_state *state,
- struct nl_cb *cb,
struct nl_msg *msg,
int argc, char **argv,
enum id_input id)
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
- nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_sta_handler, NULL);
+ register_handler(print_sta_handler, NULL);
return 0;
nla_put_failure:
}
static int handle_station_set_plink(struct nl80211_state *state,
- struct nl_cb *cb,
struct nl_msg *msg,
int argc, char **argv,
enum id_input id)
argv++;
if (strcmp("open", argv[0]) == 0)
- plink_action = PLINK_ACTION_OPEN;
+ plink_action = NL80211_PLINK_ACTION_OPEN;
else if (strcmp("block", argv[0]) == 0)
- plink_action = PLINK_ACTION_BLOCK;
+ plink_action = NL80211_PLINK_ACTION_BLOCK;
else {
fprintf(stderr, "plink action not supported\n");
return 2;
select_station_cmd, station_set_plink);
static int handle_station_set_vlan(struct nl80211_state *state,
- struct nl_cb *cb,
struct nl_msg *msg,
int argc, char **argv,
enum id_input id)
select_station_cmd, station_set_vlan);
static int handle_station_set_mesh_power_mode(struct nl80211_state *state,
- struct nl_cb *cb,
struct nl_msg *msg,
int argc, char **argv,
enum id_input id)
select_station_cmd, station_set_mesh_power_mode);
static int handle_station_dump(struct nl80211_state *state,
- struct nl_cb *cb,
struct nl_msg *msg,
int argc, char **argv,
enum id_input id)
{
- nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_sta_handler, NULL);
+ register_handler(print_sta_handler, NULL);
return 0;
}
COMMAND(station, dump, NULL,