]> git.ipfire.org Git - thirdparty/iw.git/blobdiff - event.c
info: macro-ify ext_feat_print()
[thirdparty/iw.git] / event.c
diff --git a/event.c b/event.c
index 3945e81e57e200d7da62f0e811f6f19f25da8c0e..100f644d00d1a0ba41a30ea0c6376139ebf4a640 100644 (file)
--- a/event.c
+++ b/event.c
@@ -355,6 +355,205 @@ static void parse_nan_term(struct nlattr **attrs)
        }
 }
 
+static const char *ftm_fail_reason(unsigned int reason)
+{
+#define FTM_FAIL_REASON(x) case NL80211_PMSR_FTM_FAILURE_##x: return #x
+       switch (reason) {
+       FTM_FAIL_REASON(UNSPECIFIED);
+       FTM_FAIL_REASON(NO_RESPONSE);
+       FTM_FAIL_REASON(REJECTED);
+       FTM_FAIL_REASON(WRONG_CHANNEL);
+       FTM_FAIL_REASON(PEER_NOT_CAPABLE);
+       FTM_FAIL_REASON(INVALID_TIMESTAMP);
+       FTM_FAIL_REASON(PEER_BUSY);
+       FTM_FAIL_REASON(BAD_CHANGED_PARAMS);
+       default:
+               return "unknown";
+       }
+}
+
+static void parse_pmsr_ftm_data(struct nlattr *data)
+{
+       struct nlattr *ftm[NL80211_PMSR_FTM_RESP_ATTR_MAX + 1];
+
+       printf("    FTM");
+       nla_parse_nested(ftm, NL80211_PMSR_FTM_RESP_ATTR_MAX, data, NULL);
+
+       if (ftm[NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON]) {
+               printf(" failed: %s (%d)",
+                      ftm_fail_reason(nla_get_u32(ftm[NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON])),
+                      nla_get_u32(ftm[NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON]));
+               if (ftm[NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME])
+                       printf(" retry after %us",
+                              nla_get_u32(ftm[NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME]));
+               printf("\n");
+               return;
+       }
+
+       printf("\n");
+
+#define PFTM(tp, attr, sign)                                                   \
+       do {                                                                    \
+               if (ftm[NL80211_PMSR_FTM_RESP_ATTR_##attr])                     \
+                       printf("      " #attr ": %lld\n",                       \
+                              (sign long long)nla_get_##tp(                    \
+                               ftm[NL80211_PMSR_FTM_RESP_ATTR_##attr]));       \
+       } while (0)
+
+       PFTM(u32, BURST_INDEX, unsigned);
+       PFTM(u32, NUM_FTMR_ATTEMPTS, unsigned);
+       PFTM(u32, NUM_FTMR_SUCCESSES, unsigned);
+       PFTM(u8, NUM_BURSTS_EXP, unsigned);
+       PFTM(u8, BURST_DURATION, unsigned);
+       PFTM(u8, FTMS_PER_BURST, unsigned);
+       PFTM(u32, RSSI_AVG, signed);
+       PFTM(u32, RSSI_SPREAD, unsigned);
+       PFTM(u64, RTT_AVG, signed);
+       PFTM(u64, RTT_VARIANCE, unsigned);
+       PFTM(u64, RTT_SPREAD, unsigned);
+       PFTM(u64, DIST_AVG, signed);
+       PFTM(u64, DIST_VARIANCE, unsigned);
+       PFTM(u64, DIST_SPREAD, unsigned);
+
+       if (ftm[NL80211_PMSR_FTM_RESP_ATTR_TX_RATE]) {
+               char buf[100];
+
+               parse_bitrate(ftm[NL80211_PMSR_FTM_RESP_ATTR_TX_RATE],
+                             buf, sizeof(buf));
+               printf("      TX bitrate: %s\n", buf);
+       }
+
+       if (ftm[NL80211_PMSR_FTM_RESP_ATTR_RX_RATE]) {
+               char buf[100];
+
+               parse_bitrate(ftm[NL80211_PMSR_FTM_RESP_ATTR_RX_RATE],
+                             buf, sizeof(buf));
+               printf("      RX bitrate: %s\n", buf);
+       }
+
+       if (ftm[NL80211_PMSR_FTM_RESP_ATTR_LCI])
+               iw_hexdump("      LCI",
+                          nla_data(ftm[NL80211_PMSR_FTM_RESP_ATTR_LCI]),
+                          nla_len(ftm[NL80211_PMSR_FTM_RESP_ATTR_LCI]));
+
+       if (ftm[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC])
+               iw_hexdump("      civic location",
+                          nla_data(ftm[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC]),
+                          nla_len(ftm[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC]));
+}
+
+static const char *pmsr_status(unsigned int status)
+{
+#define PMSR_STATUS(x) case NL80211_PMSR_STATUS_##x: return #x
+       switch (status) {
+       PMSR_STATUS(SUCCESS);
+       PMSR_STATUS(REFUSED);
+       PMSR_STATUS(TIMEOUT);
+       PMSR_STATUS(FAILURE);
+       default:
+               return "unknown";
+       }
+#undef PMSR_STATUS
+}
+
+static void parse_pmsr_peer(struct nlattr *peer)
+{
+       struct nlattr *tb[NL80211_PMSR_PEER_ATTR_MAX + 1];
+       struct nlattr *resp[NL80211_PMSR_RESP_ATTR_MAX + 1];
+       struct nlattr *data[NL80211_PMSR_TYPE_MAX + 1];
+       char macbuf[6*3];
+       int err;
+
+       err = nla_parse_nested(tb, NL80211_PMSR_PEER_ATTR_MAX, peer, NULL);
+       if (err) {
+               printf("  Peer: failed to parse!\n");
+               return;
+       }
+
+       if (!tb[NL80211_PMSR_PEER_ATTR_ADDR]) {
+               printf("  Peer: no MAC address\n");
+               return;
+       }
+
+       mac_addr_n2a(macbuf, nla_data(tb[NL80211_PMSR_PEER_ATTR_ADDR]));
+       printf("  Peer %s:", macbuf);
+
+       if (!tb[NL80211_PMSR_PEER_ATTR_RESP]) {
+               printf(" no response!\n");
+               return;
+       }
+
+       err = nla_parse_nested(resp, NL80211_PMSR_RESP_ATTR_MAX,
+                              tb[NL80211_PMSR_PEER_ATTR_RESP], NULL);
+       if (err) {
+               printf(" failed to parse response!\n");
+               return;
+       }
+
+       if (resp[NL80211_PMSR_RESP_ATTR_STATUS])
+               printf(" status=%d (%s)",
+                      nla_get_u32(resp[NL80211_PMSR_RESP_ATTR_STATUS]),
+                      pmsr_status(nla_get_u32(resp[NL80211_PMSR_RESP_ATTR_STATUS])));
+       if (resp[NL80211_PMSR_RESP_ATTR_HOST_TIME])
+               printf(" @%llu",
+                      (unsigned long long)nla_get_u64(resp[NL80211_PMSR_RESP_ATTR_HOST_TIME]));
+       if (resp[NL80211_PMSR_RESP_ATTR_AP_TSF])
+               printf(" tsf=%llu",
+                      (unsigned long long)nla_get_u64(resp[NL80211_PMSR_RESP_ATTR_AP_TSF]));
+       if (resp[NL80211_PMSR_RESP_ATTR_FINAL])
+               printf(" (final)");
+
+       if (!resp[NL80211_PMSR_RESP_ATTR_DATA]) {
+               printf(" - no data!\n");
+               return;
+       }
+
+       printf("\n");
+
+       nla_parse_nested(data, NL80211_PMSR_TYPE_MAX,
+                        resp[NL80211_PMSR_RESP_ATTR_DATA], NULL);
+
+       if (data[NL80211_PMSR_TYPE_FTM])
+               parse_pmsr_ftm_data(data[NL80211_PMSR_TYPE_FTM]);
+}
+
+static void parse_pmsr_result(struct nlattr **tb,
+                             struct print_event_args *pargs)
+{
+       struct nlattr *pmsr[NL80211_PMSR_ATTR_MAX + 1];
+       struct nlattr *peer;
+       unsigned long long cookie;
+       int err, i;
+
+       if (!tb[NL80211_ATTR_COOKIE]) {
+               printf("Peer measurements: no cookie!\n");
+               return;
+       }
+       cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
+
+       if (!tb[NL80211_ATTR_PEER_MEASUREMENTS]) {
+               printf("Peer measurements: no measurement data!\n");
+               return;
+       }
+
+       err = nla_parse_nested(pmsr, NL80211_PMSR_ATTR_MAX,
+                              tb[NL80211_ATTR_PEER_MEASUREMENTS], NULL);
+       if (err) {
+               printf("Peer measurements: failed to parse measurement data!\n");
+               return;
+       }
+
+       if (!pmsr[NL80211_PMSR_ATTR_PEERS]) {
+               printf("Peer measurements: no peer data!\n");
+               return;
+       }
+
+       printf("Peer measurements (cookie %llu):\n", cookie);
+
+       nla_for_each_nested(peer, pmsr[NL80211_PMSR_ATTR_PEERS], i)
+               parse_pmsr_peer(peer);
+}
+
 static void parse_nan_match(struct nlattr **attrs)
 {
        char macbuf[6*3];
@@ -777,6 +976,12 @@ static int print_event(struct nl_msg *msg, void *arg)
        case NL80211_CMD_DEL_WIPHY:
                printf("delete wiphy\n");
                break;
+       case NL80211_CMD_PEER_MEASUREMENT_RESULT:
+               parse_pmsr_result(tb, args);
+               break;
+       case NL80211_CMD_PEER_MEASUREMENT_COMPLETE:
+               printf("peer measurement complete\n");
+               break;
        case NL80211_CMD_DEL_NAN_FUNCTION:
                parse_nan_term(tb);
                break;
@@ -795,8 +1000,9 @@ static int print_event(struct nl_msg *msg, void *arg)
 }
 
 struct wait_event {
-       int n_cmds;
+       int n_cmds, n_prints;
        const __u32 *cmds;
+       const __u32 *prints;
        __u32 cmd;
        struct print_event_args *pargs;
 };
@@ -807,14 +1013,18 @@ static int wait_event(struct nl_msg *msg, void *arg)
        struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
        int i;
 
-       for (i = 0; i < wait->n_cmds; i++) {
-               if (gnlh->cmd == wait->cmds[i]) {
-                       wait->cmd = gnlh->cmd;
-                       if (wait->pargs)
+       if (wait->pargs) {
+               for (i = 0; i < wait->n_prints; i++) {
+                       if (gnlh->cmd == wait->prints[i])
                                print_event(msg, wait->pargs);
                }
        }
 
+       for (i = 0; i < wait->n_cmds; i++) {
+               if (gnlh->cmd == wait->cmds[i])
+                       wait->cmd = gnlh->cmd;
+       }
+
        return NL_SKIP;
 }
 
@@ -874,6 +1084,7 @@ int __prepare_listen_events(struct nl80211_state *state)
 
 __u32 __do_listen_events(struct nl80211_state *state,
                         const int n_waits, const __u32 *waits,
+                        const int n_prints, const __u32 *prints,
                         struct print_event_args *args)
 {
        struct nl_cb *cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
@@ -891,6 +1102,8 @@ __u32 __do_listen_events(struct nl80211_state *state,
        if (n_waits && waits) {
                wait_ev.cmds = waits;
                wait_ev.n_cmds = n_waits;
+               wait_ev.prints = prints;
+               wait_ev.n_prints = n_prints;
                wait_ev.pargs = args;
                register_handler(wait_event, &wait_ev);
        } else
@@ -915,7 +1128,7 @@ __u32 listen_events(struct nl80211_state *state,
        if (ret)
                return ret;
 
-       return __do_listen_events(state, n_waits, waits, NULL);
+       return __do_listen_events(state, n_waits, waits, 0, NULL, NULL);
 }
 
 static int print_events(struct nl80211_state *state,
@@ -954,7 +1167,7 @@ static int print_events(struct nl80211_state *state,
        if (ret)
                return ret;
 
-       return __do_listen_events(state, 0, NULL, &args);
+       return __do_listen_events(state, 0, NULL, 0, NULL, &args);
 }
 TOPLEVEL(event, "[-t|-r] [-f]", 0, 0, CIB_NONE, print_events,
        "Monitor events from the kernel.\n"