+static void parse_wowlan_wake_event(struct nlattr **attrs)
+{
+ struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG],
+ *tb_match[NUM_NL80211_ATTR];
+
+ printf("WoWLAN wakeup\n");
+ if (!attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) {
+ printf("\twakeup not due to WoWLAN\n");
+ return;
+ }
+
+ nla_parse(tb, MAX_NL80211_WOWLAN_TRIG,
+ nla_data(attrs[NL80211_ATTR_WOWLAN_TRIGGERS]),
+ nla_len(attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), NULL);
+
+ if (tb[NL80211_WOWLAN_TRIG_DISCONNECT])
+ printf("\t* was disconnected\n");
+ if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT])
+ printf("\t* magic packet received\n");
+ if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN])
+ printf("\t* pattern index: %u\n",
+ nla_get_u32(tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]));
+ if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE])
+ printf("\t* GTK rekey failure\n");
+ if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST])
+ printf("\t* EAP identity request\n");
+ if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE])
+ printf("\t* 4-way handshake\n");
+ if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE])
+ printf("\t* RF-kill released\n");
+ if (tb[NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS]) {
+ struct nlattr *match, *freq;
+ int rem_nst, rem_nst2;
+
+ printf("\t* network detected\n");
+ nla_for_each_nested(match,
+ tb[NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS],
+ rem_nst) {
+ 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("\"");
+ if (tb_match[NL80211_ATTR_SCAN_FREQUENCIES]) {
+ printf(" freq(s):");
+ nla_for_each_nested(freq,
+ tb_match[NL80211_ATTR_SCAN_FREQUENCIES],
+ rem_nst2)
+ printf(" %d", nla_get_u32(freq));
+ }
+ printf("\n");
+ }
+ }
+ if (tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211]) {
+ uint8_t *d = nla_data(tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211]);
+ int l = nla_len(tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211]);
+ int i;
+ printf("\t* packet (might be truncated): ");
+ for (i = 0; i < l; i++) {
+ if (i > 0)
+ printf(":");
+ printf("%.2x", d[i]);
+ }
+ printf("\n");
+ }
+ if (tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023]) {
+ uint8_t *d = nla_data(tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023]);
+ int l = nla_len(tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023]);
+ int i;
+ printf("\t* packet (might be truncated): ");
+ for (i = 0; i < l; i++) {
+ if (i > 0)
+ printf(":");
+ printf("%.2x", d[i]);
+ }
+ printf("\n");
+ }
+ if (tb[NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH])
+ printf("\t* TCP connection wakeup received\n");
+ if (tb[NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST])
+ printf("\t* TCP connection lost\n");
+ if (tb[NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS])
+ printf("\t* TCP connection ran out of tokens\n");
+}
+
+extern struct vendor_event *__start_vendor_event[];
+extern struct vendor_event *__stop_vendor_event;
+
+// Dummy to force the section to exist
+VENDOR_EVENT(0xffffffff, 0xffffffff, NULL);
+
+static void parse_vendor_event(struct nlattr **attrs, bool dump)
+{
+ __u32 vendor_id, subcmd;
+ unsigned int i;
+
+ if (!attrs[NL80211_ATTR_VENDOR_ID] ||
+ !attrs[NL80211_ATTR_VENDOR_SUBCMD])
+ return;
+
+ vendor_id = nla_get_u32(attrs[NL80211_ATTR_VENDOR_ID]);
+ subcmd = nla_get_u32(attrs[NL80211_ATTR_VENDOR_SUBCMD]);
+
+ printf("vendor event %.6x:%d", vendor_id, subcmd);
+
+ for (i = 0; i < &__stop_vendor_event - __start_vendor_event; i++) {
+ struct vendor_event *ev = __start_vendor_event[i];
+
+ if (!ev)
+ continue;
+
+ if (ev->vendor_id != vendor_id)
+ continue;
+ if (ev->subcmd != subcmd)
+ continue;
+ if (!ev->callback)
+ continue;
+
+ ev->callback(vendor_id, subcmd, attrs[NL80211_ATTR_VENDOR_DATA]);
+ goto out;
+ }
+
+ if (dump && attrs[NL80211_ATTR_VENDOR_DATA])
+ iw_hexdump("vendor event",
+ nla_data(attrs[NL80211_ATTR_VENDOR_DATA]),
+ nla_len(attrs[NL80211_ATTR_VENDOR_DATA]));
+out:
+ printf("\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 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];
+ __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);
+}