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;
__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),
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;
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 {
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");
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);
__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,
int argc, char **argv)
{
struct print_event_args args;
+ int ret;
memset(&args, 0, sizeof(args));
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.");