+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];
+ __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 void parse_new_peer_candidate(struct nlattr **attrs)
+{
+ char macbuf[ETH_ALEN * 3];
+ int32_t sig_dbm;
+
+ printf("new peer candidate");
+ if (attrs[NL80211_ATTR_MAC]) {
+ mac_addr_n2a(macbuf, nla_data(attrs[NL80211_ATTR_MAC]));
+ printf(" %s", macbuf);
+ }
+ if (attrs[NL80211_ATTR_RX_SIGNAL_DBM]) {
+ sig_dbm = nla_get_u32(attrs[NL80211_ATTR_RX_SIGNAL_DBM]);
+ printf(" %d dBm", sig_dbm);
+ }
+
+ printf("\n");
+}
+
+static void parse_recv_interface(struct nlattr **attrs, int command)
+{
+ switch (command) {
+ case NL80211_CMD_NEW_INTERFACE:
+ printf("new interface");
+ break;
+ case NL80211_CMD_DEL_INTERFACE:
+ printf("del interface");
+ break;
+ case NL80211_CMD_SET_INTERFACE:
+ printf("set interface");
+ break;
+ default:
+ printf("unknown interface command (%i) received\n", command);
+ return;
+ }
+
+ if (attrs[NL80211_ATTR_IFTYPE]) {
+ printf(" type ");
+ switch (nla_get_u32(attrs[NL80211_ATTR_IFTYPE])) {
+ case NL80211_IFTYPE_STATION:
+ printf("station");
+ break;
+ case NL80211_IFTYPE_AP:
+ printf("access point");
+ break;
+ case NL80211_IFTYPE_MESH_POINT:
+ printf("mesh point");
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ printf("IBSS");
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ printf("monitor");
+ break;
+ case NL80211_IFTYPE_AP_VLAN:
+ printf("AP-VLAN");
+ break;
+ case NL80211_IFTYPE_WDS:
+ printf("WDS");
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ printf("P2P-client");
+ break;
+ case NL80211_IFTYPE_P2P_GO:
+ printf("P2P-GO");
+ break;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ printf("P2P-Device");
+ break;
+ case NL80211_IFTYPE_OCB:
+ printf("OCB");
+ break;
+ case NL80211_IFTYPE_NAN:
+ printf("NAN");
+ break;
+ default:
+ printf("unknown (%d)",
+ nla_get_u32(attrs[NL80211_ATTR_IFTYPE]));
+ break;
+ }
+ }
+
+ if (attrs[NL80211_ATTR_MESH_ID]) {
+ printf(" meshid ");
+ print_ssid_escaped(nla_len(attrs[NL80211_ATTR_MESH_ID]),
+ nla_data(attrs[NL80211_ATTR_MESH_ID]));
+ }
+
+ if (attrs[NL80211_ATTR_4ADDR]) {
+ printf(" use 4addr %d", nla_get_u8(attrs[NL80211_ATTR_4ADDR]));
+ }
+
+ printf("\n");
+}
+
+static void parse_sta_opmode_changed(struct nlattr **attrs)
+{
+ char macbuf[ETH_ALEN*3];
+
+ printf("sta opmode changed");
+
+ if (attrs[NL80211_ATTR_MAC]) {
+ mac_addr_n2a(macbuf, nla_data(attrs[NL80211_ATTR_MAC]));
+ printf(" %s", macbuf);
+ }
+
+ if (attrs[NL80211_ATTR_SMPS_MODE])
+ printf(" smps mode %d", nla_get_u8(attrs[NL80211_ATTR_SMPS_MODE]));
+
+ if (attrs[NL80211_ATTR_CHANNEL_WIDTH])
+ printf(" chan width %d", nla_get_u8(attrs[NL80211_ATTR_CHANNEL_WIDTH]));
+
+ if (attrs[NL80211_ATTR_NSS])
+ printf(" nss %d", nla_get_u8(attrs[NL80211_ATTR_NSS]));
+
+ printf("\n");
+}
+
+static void parse_ch_switch_notify(struct nlattr **attrs, int command)
+{
+ switch (command) {
+ case NL80211_CMD_CH_SWITCH_STARTED_NOTIFY:
+ printf("channel switch started");
+ break;
+ case NL80211_CMD_CH_SWITCH_NOTIFY:
+ printf("channel switch");
+ break;
+ default:
+ printf("unknown channel switch command (%i) received\n", command);
+ return;
+ }
+
+ if (attrs[NL80211_ATTR_CH_SWITCH_COUNT])
+ printf(" (count=%d)", nla_get_u32(attrs[NL80211_ATTR_CH_SWITCH_COUNT]));
+
+ if (attrs[NL80211_ATTR_WIPHY_FREQ])
+ printf(" freq=%d", nla_get_u32(attrs[NL80211_ATTR_WIPHY_FREQ]));
+
+ if (attrs[NL80211_ATTR_CHANNEL_WIDTH]) {
+ printf(" width=");
+ switch(nla_get_u32(attrs[NL80211_ATTR_CHANNEL_WIDTH])) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ case NL80211_CHAN_WIDTH_20:
+ printf("\"20 MHz\"");
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ printf("\"40 MHz\"");
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ printf("\"80 MHz\"");
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ printf("\"80+80 MHz\"");
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ printf("\"160 MHz\"");
+ break;
+ case NL80211_CHAN_WIDTH_5:
+ printf("\"5 MHz\"");
+ break;
+ case NL80211_CHAN_WIDTH_10:
+ printf("\"10 MHz\"");
+ break;
+ default:
+ printf("\"unknown\"");
+ }
+ }
+
+ if (attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+ printf(" type=");
+ switch(nla_get_u32(attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
+ case NL80211_CHAN_NO_HT:
+ printf("\"No HT\"");
+ break;
+ case NL80211_CHAN_HT20:
+ printf("\"HT20\"");
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ printf("\"HT40-\"");
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ printf("\"HT40+\"");
+ break;
+ }
+ }
+
+ if (attrs[NL80211_ATTR_CENTER_FREQ1])
+ printf(" freq1=%d", nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ1]));
+
+ if (attrs[NL80211_ATTR_CENTER_FREQ2])
+ printf(" freq2=%d", nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ2]));
+
+ printf("\n");
+}
+
+static void parse_assoc_comeback(struct nlattr **attrs, int command)
+{
+ __u32 timeout = 0;
+ char macbuf[6 * 3] = "<unset>";
+
+ if (attrs[NL80211_ATTR_MAC])
+ mac_addr_n2a(macbuf, nla_data(attrs[NL80211_ATTR_MAC]));
+
+ if (attrs[NL80211_ATTR_TIMEOUT])
+ timeout = nla_get_u32(attrs[NL80211_ATTR_TIMEOUT]);
+
+ printf("assoc comeback bssid %s timeout %d\n",
+ macbuf, timeout);
+}