#include <stdbool.h>
#include <net/if.h>
#include <errno.h>
+#include <inttypes.h>
#include "iw.h"
static int no_seq_check(struct nl_msg *msg, void *arg)
{
uint8_t *frame;
size_t len;
- int i;
+ unsigned int i;
char macbuf[6*3];
uint16_t tmp;
- if (!attr)
+ if (!attr) {
printf(" [no frame]");
+ return;
+ }
frame = nla_data(attr);
len = nla_len(attr);
if (!found_one)
printf("Unknown event type: %i\n", rssi_event);
- } 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
+ } else if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) {
+ if (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("PKT-LOSS-EVENT did not have MAC attribute!\n");
+ }
+ } else if (cqm[NL80211_ATTR_CQM_BEACON_LOSS_EVENT]) {
+ printf("beacon loss\n");
+ } else {
printf("unknown event\n");
+ }
}
static const char * key_type_str(enum nl80211_key_type key_type)
nla_for_each_nested(match,
tb[NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS],
rem_nst) {
- nla_parse(tb_match, NUM_NL80211_ATTR, nla_data(match),
- nla_len(match),
- NULL);
+ nla_parse_nested(tb_match, NL80211_ATTR_MAX, match,
+ NULL);
printf("\t\tSSID: \"");
print_ssid_escaped(nla_len(tb_match[NL80211_ATTR_SSID]),
nla_data(tb_match[NL80211_ATTR_SSID]));
printf("\t* TCP connection ran out of tokens\n");
}
+static void parse_nan_term(struct nlattr **attrs)
+{
+ struct nlattr *func[NL80211_NAN_FUNC_ATTR_MAX + 1];
+
+ static struct nla_policy
+ nan_func_policy[NL80211_NAN_FUNC_ATTR_MAX + 1] = {
+ [NL80211_NAN_FUNC_TYPE] = { .type = NLA_U8 },
+ [NL80211_NAN_FUNC_SERVICE_ID] = { },
+ [NL80211_NAN_FUNC_PUBLISH_TYPE] = { .type = NLA_U8 },
+ [NL80211_NAN_FUNC_PUBLISH_BCAST] = { .type = NLA_FLAG },
+ [NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE] = { .type = NLA_FLAG },
+ [NL80211_NAN_FUNC_FOLLOW_UP_ID] = { .type = NLA_U8 },
+ [NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] = { .type = NLA_U8 },
+ [NL80211_NAN_FUNC_FOLLOW_UP_DEST] = { },
+ [NL80211_NAN_FUNC_CLOSE_RANGE] = { .type = NLA_FLAG },
+ [NL80211_NAN_FUNC_TTL] = { .type = NLA_U32 },
+ [NL80211_NAN_FUNC_SERVICE_INFO] = { },
+ [NL80211_NAN_FUNC_SRF] = { .type = NLA_NESTED },
+ [NL80211_NAN_FUNC_RX_MATCH_FILTER] = { .type = NLA_NESTED },
+ [NL80211_NAN_FUNC_TX_MATCH_FILTER] = { .type = NLA_NESTED },
+ [NL80211_NAN_FUNC_INSTANCE_ID] = { .type = NLA_U8},
+ };
+
+ if (!attrs[NL80211_ATTR_COOKIE]) {
+ printf("Bad NAN func termination format - cookie is missing\n");
+ return;
+ }
+
+ if (nla_parse_nested(func, NL80211_NAN_FUNC_ATTR_MAX,
+ attrs[NL80211_ATTR_NAN_FUNC],
+ nan_func_policy)) {
+ printf("NAN: failed to parse nan func\n");
+ return;
+ }
+
+ if (!func[NL80211_NAN_FUNC_INSTANCE_ID]) {
+ printf("Bad NAN func termination format-instance id missing\n");
+ return;
+ }
+
+ if (!func[NL80211_NAN_FUNC_TERM_REASON]) {
+ printf("Bad NAN func termination format - reason is missing\n");
+ return;
+ }
+ printf("NAN(cookie=0x%llx): Termination event: id = %d, reason = ",
+ (long long int)nla_get_u64(attrs[NL80211_ATTR_COOKIE]),
+ nla_get_u8(func[NL80211_NAN_FUNC_INSTANCE_ID]));
+ switch (nla_get_u8(func[NL80211_NAN_FUNC_TERM_REASON])) {
+ case NL80211_NAN_FUNC_TERM_REASON_USER_REQUEST:
+ printf("user request\n");
+ break;
+ case NL80211_NAN_FUNC_TERM_REASON_TTL_EXPIRED:
+ printf("expired\n");
+ break;
+ case NL80211_NAN_FUNC_TERM_REASON_ERROR:
+ printf("error\n");
+ break;
+ default:
+ printf("unknown\n");
+ }
+}
+
+static void parse_nan_match(struct nlattr **attrs)
+{
+ char macbuf[6*3];
+ __u64 cookie;
+ struct nlattr *match[NL80211_NAN_MATCH_ATTR_MAX + 1];
+ struct nlattr *local_func[NL80211_NAN_FUNC_ATTR_MAX + 1];
+ struct nlattr *peer_func[NL80211_NAN_FUNC_ATTR_MAX + 1];
+
+ static struct nla_policy
+ nan_match_policy[NL80211_NAN_MATCH_ATTR_MAX + 1] = {
+ [NL80211_NAN_MATCH_FUNC_LOCAL] = { .type = NLA_NESTED },
+ [NL80211_NAN_MATCH_FUNC_PEER] = { .type = NLA_NESTED },
+ };
+
+ static struct nla_policy
+ nan_func_policy[NL80211_NAN_FUNC_ATTR_MAX + 1] = {
+ [NL80211_NAN_FUNC_TYPE] = { .type = NLA_U8 },
+ [NL80211_NAN_FUNC_SERVICE_ID] = { },
+ [NL80211_NAN_FUNC_PUBLISH_TYPE] = { .type = NLA_U8 },
+ [NL80211_NAN_FUNC_PUBLISH_BCAST] = { .type = NLA_FLAG },
+ [NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE] = { .type = NLA_FLAG },
+ [NL80211_NAN_FUNC_FOLLOW_UP_ID] = { .type = NLA_U8 },
+ [NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] = { .type = NLA_U8 },
+ [NL80211_NAN_FUNC_FOLLOW_UP_DEST] = { },
+ [NL80211_NAN_FUNC_CLOSE_RANGE] = { .type = NLA_FLAG },
+ [NL80211_NAN_FUNC_TTL] = { .type = NLA_U32 },
+ [NL80211_NAN_FUNC_SERVICE_INFO] = { },
+ [NL80211_NAN_FUNC_SRF] = { .type = NLA_NESTED },
+ [NL80211_NAN_FUNC_RX_MATCH_FILTER] = { .type = NLA_NESTED },
+ [NL80211_NAN_FUNC_TX_MATCH_FILTER] = { .type = NLA_NESTED },
+ [NL80211_NAN_FUNC_INSTANCE_ID] = { .type = NLA_U8},
+ };
+
+ cookie = nla_get_u64(attrs[NL80211_ATTR_COOKIE]);
+ mac_addr_n2a(macbuf, nla_data(attrs[NL80211_ATTR_MAC]));
+
+ if (nla_parse_nested(match, NL80211_NAN_MATCH_ATTR_MAX,
+ attrs[NL80211_ATTR_NAN_MATCH],
+ nan_match_policy)) {
+ printf("NAN: failed to parse nan match event\n");
+ return;
+ }
+
+ if (nla_parse_nested(local_func, NL80211_NAN_FUNC_ATTR_MAX,
+ match[NL80211_NAN_MATCH_FUNC_LOCAL],
+ nan_func_policy)) {
+ printf("NAN: failed to parse nan local func\n");
+ return;
+ }
+
+ if (nla_parse_nested(peer_func, NL80211_NAN_FUNC_ATTR_MAX,
+ match[NL80211_NAN_MATCH_FUNC_PEER],
+ nan_func_policy)) {
+ printf("NAN: failed to parse nan local func\n");
+ return;
+ }
+
+ if (nla_get_u8(peer_func[NL80211_NAN_FUNC_TYPE]) ==
+ NL80211_NAN_FUNC_PUBLISH) {
+ printf(
+ "NAN(cookie=0x%llx): DiscoveryResult, peer_id=%d, local_id=%d, peer_mac=%s",
+ cookie,
+ nla_get_u8(peer_func[NL80211_NAN_FUNC_INSTANCE_ID]),
+ nla_get_u8(local_func[NL80211_NAN_FUNC_INSTANCE_ID]),
+ macbuf);
+ if (peer_func[NL80211_NAN_FUNC_SERVICE_INFO])
+ printf(", info=%.*s",
+ nla_len(peer_func[NL80211_NAN_FUNC_SERVICE_INFO]),
+ (char *)nla_data(peer_func[NL80211_NAN_FUNC_SERVICE_INFO]));
+ } else if (nla_get_u8(peer_func[NL80211_NAN_FUNC_TYPE]) ==
+ NL80211_NAN_FUNC_SUBSCRIBE) {
+ printf(
+ "NAN(cookie=0x%llx): Replied, peer_id=%d, local_id=%d, peer_mac=%s",
+ cookie,
+ nla_get_u8(peer_func[NL80211_NAN_FUNC_INSTANCE_ID]),
+ nla_get_u8(local_func[NL80211_NAN_FUNC_INSTANCE_ID]),
+ macbuf);
+ } else if (nla_get_u8(peer_func[NL80211_NAN_FUNC_TYPE]) ==
+ NL80211_NAN_FUNC_FOLLOW_UP) {
+ printf(
+ "NAN(cookie=0x%llx): FollowUpReceive, peer_id=%d, local_id=%d, peer_mac=%s",
+ cookie,
+ nla_get_u8(peer_func[NL80211_NAN_FUNC_INSTANCE_ID]),
+ nla_get_u8(local_func[NL80211_NAN_FUNC_INSTANCE_ID]),
+ macbuf);
+ if (peer_func[NL80211_NAN_FUNC_SERVICE_INFO])
+ printf(", info=%.*s",
+ nla_len(peer_func[NL80211_NAN_FUNC_SERVICE_INFO]),
+ (char *)nla_data(peer_func[NL80211_NAN_FUNC_SERVICE_INFO]));
+ } else {
+ printf("NaN: Malformed event");
+ }
+
+ printf("\n");
+}
+
static int print_event(struct nl_msg *msg, void *arg)
{
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
break;
case NL80211_CMD_NEW_SCAN_RESULTS:
printf("scan finished:");
+ /* fall through */
case NL80211_CMD_SCAN_ABORTED:
if (gnlh->cmd == NL80211_CMD_SCAN_ABORTED)
printf("scan aborted:");
break;
case NL80211_CMD_CONNECT:
status = 0;
- if (!tb[NL80211_ATTR_STATUS_CODE])
+ if (tb[NL80211_ATTR_TIMED_OUT])
+ printf("timed out");
+ else if (!tb[NL80211_ATTR_STATUS_CODE])
printf("unknown connect status");
else if (nla_get_u16(tb[NL80211_ATTR_STATUS_CODE]) == 0)
printf("connected");
nla_data(tb[NL80211_ATTR_VENDOR_DATA]),
nla_len(tb[NL80211_ATTR_VENDOR_DATA]));
break;
- case NL80211_CMD_RADAR_DETECT:
- printf("radar event ");
- if (tb[NL80211_ATTR_RADAR_EVENT]) {
- switch (nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT])) {
- case NL80211_RADAR_DETECTED:
- printf("(radar detected)");
- break;
- case NL80211_RADAR_CAC_FINISHED:
- printf("(cac finished)");
- break;
- case NL80211_RADAR_CAC_ABORTED:
- printf("(cac aborted)");
- break;
- case NL80211_RADAR_NOP_FINISHED:
- printf("(nop finished)");
- break;
- default:
- printf("(unknown)");
- break;
- };
- } else {
- printf("(unknown)");
+ case NL80211_CMD_RADAR_DETECT: {
+ enum nl80211_radar_event event_type;
+ uint32_t freq;
+
+ if (!tb[NL80211_ATTR_RADAR_EVENT] ||
+ !tb[NL80211_ATTR_WIPHY_FREQ]) {
+ printf("BAD radar event\n");
+ break;
}
- printf("\n");
+
+ freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+ event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
+
+ switch (event_type) {
+ case NL80211_RADAR_DETECTED:
+ printf("%d MHz: radar detected\n", freq);
+ break;
+ case NL80211_RADAR_CAC_FINISHED:
+ printf("%d MHz: CAC finished\n", freq);
+ break;
+ case NL80211_RADAR_CAC_ABORTED:
+ printf("%d MHz: CAC was aborted\n", freq);
+ break;
+ case NL80211_RADAR_NOP_FINISHED:
+ printf("%d MHz: NOP finished\n", freq);
+ break;
+ default:
+ printf("%d MHz: unknown radar event\n", freq);
+ }
+ }
+ break;
+ case NL80211_CMD_DEL_WIPHY:
+ printf("delete wiphy\n");
break;
+ case NL80211_CMD_DEL_NAN_FUNCTION:
+ parse_nan_term(tb);
+ break;
+ case NL80211_CMD_NAN_MATCH: {
+ parse_nan_match(tb);
+ break;
+ }
default:
printf("unknown event %d (%s)\n",
gnlh->cmd, command_name(gnlh->cmd));
return ret;
}
+ mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "nan");
+ if (mcid >= 0) {
+ ret = nl_socket_add_membership(state->nl_sock, mcid);
+ if (ret)
+ return ret;
+ }
+
return 0;
}
/* no sequence checking for multicast messages */
nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, NULL);
if (n_waits && waits) {
wait_ev.cmds = waits;
wait_ev.n_cmds = n_waits;
wait_ev.pargs = args;
- nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, wait_event, &wait_ev);
+ register_handler(wait_event, &wait_ev);
} else
- nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_event, args);
+ register_handler(print_event, args);
wait_ev.cmd = 0;
}
static int print_events(struct nl80211_state *state,
- struct nl_cb *cb,
struct nl_msg *msg,
int argc, char **argv,
enum id_input id)
return __do_listen_events(state, 0, NULL, &args);
}
-TOPLEVEL(event, "[-t] [-r] [-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"