+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("CQM 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;
+ bool found_one = false;
+
+ rssi_event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
+
+ switch (rssi_event) {
+ case NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH:
+ printf("RSSI went above threshold\n");
+ found_one = true;
+ break;
+ case NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW:
+ printf("RSSI went below threshold\n");
+ found_one = true;
+ break;
+ case NL80211_CQM_RSSI_BEACON_LOSS_EVENT:
+ printf("Beacon loss detected\n");
+ found_one = true;
+ break;
+ }
+
+ if (!found_one)
+ printf("Unknown event type: %i\n", rssi_event);
+ } 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)
+{
+ static char buf[30];
+ switch (key_type) {
+ case NL80211_KEYTYPE_GROUP:
+ return "Group";
+ case NL80211_KEYTYPE_PAIRWISE:
+ return "Pairwise";
+ case NL80211_KEYTYPE_PEERKEY:
+ return "PeerKey";
+ default:
+ snprintf(buf, sizeof(buf), "unknown(%d)", key_type);
+ return buf;
+ }
+}
+
+static void parse_mic_failure(struct nlattr **attrs)
+{
+ printf("Michael MIC failure event:");
+
+ if (attrs[NL80211_ATTR_MAC]) {
+ char addr[3 * ETH_ALEN];
+ mac_addr_n2a(addr, nla_data(attrs[NL80211_ATTR_MAC]));
+ printf(" source MAC address %s", addr);
+ }
+
+ if (attrs[NL80211_ATTR_KEY_SEQ] &&
+ nla_len(attrs[NL80211_ATTR_KEY_SEQ]) == 6) {
+ unsigned char *seq = nla_data(attrs[NL80211_ATTR_KEY_SEQ]);
+ printf(" seq=%02x%02x%02x%02x%02x%02x",
+ seq[0], seq[1], seq[2], seq[3], seq[4], seq[5]);
+ }
+ if (attrs[NL80211_ATTR_KEY_TYPE]) {
+ enum nl80211_key_type key_type =
+ nla_get_u32(attrs[NL80211_ATTR_KEY_TYPE]);
+ printf(" Key Type %s", key_type_str(key_type));
+ }
+
+ if (attrs[NL80211_ATTR_KEY_IDX]) {
+ __u8 key_id = nla_get_u8(attrs[NL80211_ATTR_KEY_IDX]);
+ printf(" Key Id %d", key_id);
+ }
+
+ printf("\n");
+}
+
+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(tb_match, NUM_NL80211_ATTR, nla_data(match),
+ nla_len(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");
+}
+