]> git.ipfire.org Git - thirdparty/iw.git/blobdiff - event.c
parse NL80211_ATTR_CQM_PKT_LOSS_EVENT
[thirdparty/iw.git] / event.c
diff --git a/event.c b/event.c
index 445db5f9ddb99ddb804d979ef05e294ab7adb19f..b3210db738d550f9db2a5ce1c5e6edaceb841e78 100644 (file)
--- a/event.c
+++ b/event.c
@@ -100,14 +100,46 @@ static void print_frame(struct print_event_args *args, struct nlattr *attr)
        printf("]");
 }
 
+static void parse_cqm_event(struct nlattr **attrs)
+{
+       static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
+               [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
+               [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
+               [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
+       };
+       struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
+       struct nlattr *cqm_attr = attrs[NL80211_ATTR_CQM];
+
+       printf("connection quality monitor event: ");
+
+       if (!cqm_attr ||
+           nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, cqm_attr, cqm_policy)) {
+               printf("missing data!\n");
+               return;
+       }
+
+       if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]) {
+               enum nl80211_cqm_rssi_threshold_event rssi_event;
+               rssi_event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
+               if (rssi_event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH)
+                       printf("RSSI went above threshold\n");
+               else
+                       printf("RSSI went below threshold\n");
+       } else if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT] &&
+                  attrs[NL80211_ATTR_MAC]) {
+               uint32_t frames;
+               char buf[3*6];
+
+               frames = nla_get_u32(cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]);
+               mac_addr_n2a(buf, nla_data(attrs[NL80211_ATTR_MAC]));
+               printf("peer %s didn't ACK %d packets\n", buf, frames);
+       } else
+               printf("unknown event\n");
+}
+
+
 static int print_event(struct nl_msg *msg, void *arg)
 {
-#define PARSE_BEACON_CHAN(_attr, _chan) do { \
-       r = parse_beacon_hint_chan(tb[_attr], \
-                                  &_chan); \
-       if (r) \
-               return NL_SKIP; \
-} while (0)
        struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
        struct nlattr *tb[NL80211_ATTR_MAX + 1], *nst;
        struct print_event_args *args = arg;
@@ -116,14 +148,23 @@ static int print_event(struct nl_msg *msg, void *arg)
        __u8 reg_type;
        struct ieee80211_beacon_channel chan_before_beacon,  chan_after_beacon;
        __u32 wiphy_idx = 0;
-       int r;
        int rem_nst;
        __u16 status;
 
-       if (args->time) {
-               struct timeval tv;
-               gettimeofday(&tv, NULL);
-               printf("%ld.%06u: ", (long) tv.tv_sec, (unsigned int) tv.tv_usec);
+       if (args->time || args->reltime) {
+               unsigned long long usecs, previous;
+
+               previous = 1000000ULL * args->ts.tv_sec + args->ts.tv_usec;
+               gettimeofday(&args->ts, NULL);
+               usecs = 1000000ULL * args->ts.tv_sec + args->ts.tv_usec;
+               if (args->reltime) {
+                       if (!args->have_ts) {
+                               usecs = 0;
+                               args->have_ts = true;
+                       } else
+                               usecs -= previous;
+               }
+               printf("%llu.%06llu: ", usecs/1000000, usecs % 1000000);
        }
 
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
@@ -207,8 +248,12 @@ static int print_event(struct nl_msg *msg, void *arg)
                memset(&chan_before_beacon, 0, sizeof(chan_before_beacon));
                memset(&chan_after_beacon, 0, sizeof(chan_after_beacon));
 
-               PARSE_BEACON_CHAN(NL80211_ATTR_FREQ_BEFORE, chan_before_beacon);
-               PARSE_BEACON_CHAN(NL80211_ATTR_FREQ_AFTER, chan_after_beacon);
+               if (parse_beacon_hint_chan(tb[NL80211_ATTR_FREQ_BEFORE],
+                                          &chan_before_beacon))
+                       break;
+               if (parse_beacon_hint_chan(tb[NL80211_ATTR_FREQ_AFTER],
+                                          &chan_after_beacon))
+                       break;
 
                if (chan_before_beacon.center_freq != chan_after_beacon.center_freq)
                        break;
@@ -302,13 +347,27 @@ static int print_event(struct nl_msg *msg, void *arg)
                                get_reason_str(nla_get_u16(tb[NL80211_ATTR_REASON_CODE])));
                printf("\n");
                break;
+       case NL80211_CMD_REMAIN_ON_CHANNEL:
+               printf("remain on freq %d (%dms, cookie %llx)\n",
+                       nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]),
+                       nla_get_u32(tb[NL80211_ATTR_DURATION]),
+                       (unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE]));
+               break;
+       case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL:
+               printf("done with remain on freq %d (cookie %llx)\n",
+                       nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]),
+                       (unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE]));
+               break;
+       case NL80211_CMD_NOTIFY_CQM:
+               parse_cqm_event(tb);
+               break;
        default:
                printf("unknown event %d\n", gnlh->cmd);
                break;
        }
 
+       fflush(stdout);
        return NL_SKIP;
-#undef PARSE_BEACON_CHAN
 }
 
 struct wait_event {
@@ -327,26 +386,17 @@ static int wait_event(struct nl_msg *msg, void *arg)
        for (i = 0; i < wait->n_cmds; i++) {
                if (gnlh->cmd == wait->cmds[i]) {
                        wait->cmd = gnlh->cmd;
-               if (wait->pargs)
-                       print_event(msg, wait->pargs);
+                       if (wait->pargs)
+                               print_event(msg, wait->pargs);
                }
        }
 
        return NL_SKIP;
 }
 
-__u32 __listen_events(struct nl80211_state *state,
-                     const int n_waits, const __u32 *waits,
-                     struct print_event_args *args)
+int __prepare_listen_events(struct nl80211_state *state)
 {
        int mcid, ret;
-       struct nl_cb *cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
-       struct wait_event wait_ev;
-
-       if (!cb) {
-               fprintf(stderr, "failed to allocate netlink callbacks\n");
-               return -ENOMEM;
-       }
 
        /* Configuration multicast group */
        mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "config");
@@ -381,6 +431,21 @@ __u32 __listen_events(struct nl80211_state *state,
                        return ret;
        }
 
+       return 0;
+}
+
+__u32 __do_listen_events(struct nl80211_state *state,
+                        const int n_waits, const __u32 *waits,
+                        struct print_event_args *args)
+{
+       struct nl_cb *cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
+       struct wait_event wait_ev;
+
+       if (!cb) {
+               fprintf(stderr, "failed to allocate netlink callbacks\n");
+               return -ENOMEM;
+       }
+
        /* no sequence checking for multicast messages */
        nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
 
@@ -405,7 +470,13 @@ __u32 __listen_events(struct nl80211_state *state,
 __u32 listen_events(struct nl80211_state *state,
                    const int n_waits, const __u32 *waits)
 {
-       return __listen_events(state, n_waits, waits, NULL);
+       int ret;
+
+       ret = __prepare_listen_events(state);
+       if (ret)
+               return ret;
+
+       return __do_listen_events(state, n_waits, waits, NULL);
 }
 
 static int print_events(struct nl80211_state *state,
@@ -414,6 +485,7 @@ static int print_events(struct nl80211_state *state,
                        int argc, char **argv)
 {
        struct print_event_args args;
+       int ret;
 
        memset(&args, 0, sizeof(args));
 
@@ -425,18 +497,28 @@ static int print_events(struct nl80211_state *state,
                        args.frame = true;
                else if (strcmp(argv[0], "-t") == 0)
                        args.time = true;
+               else if (strcmp(argv[0], "-r") == 0)
+                       args.reltime = true;
                else
                        return 1;
                argc--;
                argv++;
        }
 
+       if (args.time && args.reltime)
+               return 1;
+
        if (argc)
                return 1;
 
-       return __listen_events(state, 0, NULL, &args);
+       ret = __prepare_listen_events(state);
+       if (ret)
+               return ret;
+
+       return __do_listen_events(state, 0, NULL, &args);
 }
-TOPLEVEL(event, "[-t] [-f]", 0, 0, CIB_NONE, print_events,
+TOPLEVEL(event, "[-t] [-r] [-f]", 0, 0, CIB_NONE, print_events,
        "Monitor events from the kernel.\n"
        "-t - print timestamp\n"
+       "-r - print relative timstamp\n"
        "-f - print full frame for auth/assoc etc.");