xref: /aosp_15_r20/external/iw/event.c (revision 92022041c981f431db0b590d0c3272306d0ea2a2)
1*92022041SSam Saccone #include <stdint.h>
2*92022041SSam Saccone #include <stdbool.h>
3*92022041SSam Saccone #include <net/if.h>
4*92022041SSam Saccone #include <errno.h>
5*92022041SSam Saccone #include <inttypes.h>
6*92022041SSam Saccone #include <time.h>
7*92022041SSam Saccone #include "iw.h"
8*92022041SSam Saccone 
no_seq_check(struct nl_msg * msg,void * arg)9*92022041SSam Saccone static int no_seq_check(struct nl_msg *msg, void *arg)
10*92022041SSam Saccone {
11*92022041SSam Saccone 	return NL_OK;
12*92022041SSam Saccone }
13*92022041SSam Saccone 
14*92022041SSam Saccone struct ieee80211_beacon_channel {
15*92022041SSam Saccone 	__u16 center_freq;
16*92022041SSam Saccone 	bool no_ir;
17*92022041SSam Saccone 	bool no_ibss;
18*92022041SSam Saccone };
19*92022041SSam Saccone 
parse_beacon_hint_chan(struct nlattr * tb,struct ieee80211_beacon_channel * chan)20*92022041SSam Saccone static int parse_beacon_hint_chan(struct nlattr *tb,
21*92022041SSam Saccone 				  struct ieee80211_beacon_channel *chan)
22*92022041SSam Saccone {
23*92022041SSam Saccone 	struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
24*92022041SSam Saccone 	static struct nla_policy beacon_freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
25*92022041SSam Saccone 		[NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
26*92022041SSam Saccone 		[NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG },
27*92022041SSam Saccone 		[__NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
28*92022041SSam Saccone 	};
29*92022041SSam Saccone 
30*92022041SSam Saccone 	if (nla_parse_nested(tb_freq,
31*92022041SSam Saccone 			     NL80211_FREQUENCY_ATTR_MAX,
32*92022041SSam Saccone 			     tb,
33*92022041SSam Saccone 			     beacon_freq_policy))
34*92022041SSam Saccone 		return -EINVAL;
35*92022041SSam Saccone 
36*92022041SSam Saccone 	chan->center_freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
37*92022041SSam Saccone 
38*92022041SSam Saccone 	if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR])
39*92022041SSam Saccone 		chan->no_ir = true;
40*92022041SSam Saccone 	if (tb_freq[__NL80211_FREQUENCY_ATTR_NO_IBSS])
41*92022041SSam Saccone 		chan->no_ibss = true;
42*92022041SSam Saccone 
43*92022041SSam Saccone 	return 0;
44*92022041SSam Saccone }
45*92022041SSam Saccone 
print_frame(struct print_event_args * args,struct nlattr * attr)46*92022041SSam Saccone static void print_frame(struct print_event_args *args, struct nlattr *attr)
47*92022041SSam Saccone {
48*92022041SSam Saccone 	uint8_t *frame;
49*92022041SSam Saccone 	size_t len;
50*92022041SSam Saccone 	unsigned int i;
51*92022041SSam Saccone 	char macbuf[6*3];
52*92022041SSam Saccone 	uint16_t tmp;
53*92022041SSam Saccone 
54*92022041SSam Saccone 	if (!attr) {
55*92022041SSam Saccone 		printf(" [no frame]");
56*92022041SSam Saccone 		return;
57*92022041SSam Saccone 	}
58*92022041SSam Saccone 
59*92022041SSam Saccone 	frame = nla_data(attr);
60*92022041SSam Saccone 	len = nla_len(attr);
61*92022041SSam Saccone 
62*92022041SSam Saccone 	if (len < 26) {
63*92022041SSam Saccone 		printf(" [invalid frame: ");
64*92022041SSam Saccone 		goto print_frame;
65*92022041SSam Saccone 	}
66*92022041SSam Saccone 
67*92022041SSam Saccone 	mac_addr_n2a(macbuf, frame + 10);
68*92022041SSam Saccone 	printf(" %s -> ", macbuf);
69*92022041SSam Saccone 	mac_addr_n2a(macbuf, frame + 4);
70*92022041SSam Saccone 	printf("%s", macbuf);
71*92022041SSam Saccone 
72*92022041SSam Saccone 	switch (frame[0] & 0xfc) {
73*92022041SSam Saccone 	case 0x10: /* assoc resp */
74*92022041SSam Saccone 	case 0x30: /* reassoc resp */
75*92022041SSam Saccone 		/* status */
76*92022041SSam Saccone 		tmp = (frame[27] << 8) + frame[26];
77*92022041SSam Saccone 		printf(" status: %d: %s", tmp, get_status_str(tmp));
78*92022041SSam Saccone 		break;
79*92022041SSam Saccone 	case 0x00: /* assoc req */
80*92022041SSam Saccone 	case 0x20: /* reassoc req */
81*92022041SSam Saccone 		break;
82*92022041SSam Saccone 	case 0xb0: /* auth */
83*92022041SSam Saccone 		/* status */
84*92022041SSam Saccone 		tmp = (frame[29] << 8) + frame[28];
85*92022041SSam Saccone 		printf(" status: %d: %s", tmp, get_status_str(tmp));
86*92022041SSam Saccone 		break;
87*92022041SSam Saccone 	case 0xa0: /* disassoc */
88*92022041SSam Saccone 	case 0xc0: /* deauth */
89*92022041SSam Saccone 		/* reason */
90*92022041SSam Saccone 		tmp = (frame[25] << 8) + frame[24];
91*92022041SSam Saccone 		printf(" reason %d: %s", tmp, get_reason_str(tmp));
92*92022041SSam Saccone 		break;
93*92022041SSam Saccone 	}
94*92022041SSam Saccone 
95*92022041SSam Saccone 	if (!args->frame)
96*92022041SSam Saccone 		return;
97*92022041SSam Saccone 
98*92022041SSam Saccone 	printf(" [frame:");
99*92022041SSam Saccone 
100*92022041SSam Saccone  print_frame:
101*92022041SSam Saccone 	for (i = 0; i < len; i++)
102*92022041SSam Saccone 		printf(" %.02x", frame[i]);
103*92022041SSam Saccone 	printf("]");
104*92022041SSam Saccone }
105*92022041SSam Saccone 
parse_cqm_event(struct nlattr ** attrs)106*92022041SSam Saccone static void parse_cqm_event(struct nlattr **attrs)
107*92022041SSam Saccone {
108*92022041SSam Saccone 	static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
109*92022041SSam Saccone 		[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
110*92022041SSam Saccone 		[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
111*92022041SSam Saccone 		[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
112*92022041SSam Saccone 	};
113*92022041SSam Saccone 	struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
114*92022041SSam Saccone 	struct nlattr *cqm_attr = attrs[NL80211_ATTR_CQM];
115*92022041SSam Saccone 
116*92022041SSam Saccone 	printf("CQM event: ");
117*92022041SSam Saccone 
118*92022041SSam Saccone 	if (!cqm_attr ||
119*92022041SSam Saccone 	    nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, cqm_attr, cqm_policy)) {
120*92022041SSam Saccone 		printf("missing data!\n");
121*92022041SSam Saccone 		return;
122*92022041SSam Saccone 	}
123*92022041SSam Saccone 
124*92022041SSam Saccone 	if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]) {
125*92022041SSam Saccone 		enum nl80211_cqm_rssi_threshold_event rssi_event;
126*92022041SSam Saccone 		int32_t rssi_level = -1;
127*92022041SSam Saccone 		bool found_one = false;
128*92022041SSam Saccone 
129*92022041SSam Saccone 		rssi_event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
130*92022041SSam Saccone 		if (cqm[NL80211_ATTR_CQM_RSSI_LEVEL])
131*92022041SSam Saccone 			rssi_level = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_LEVEL]);
132*92022041SSam Saccone 
133*92022041SSam Saccone 		switch (rssi_event) {
134*92022041SSam Saccone 		case NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH:
135*92022041SSam Saccone 			printf("RSSI (%i dBm) went above threshold\n", rssi_level);
136*92022041SSam Saccone 			found_one = true;
137*92022041SSam Saccone 			break;
138*92022041SSam Saccone 		case NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW:
139*92022041SSam Saccone 			printf("RSSI (%i dBm) went below threshold\n", rssi_level);
140*92022041SSam Saccone 			found_one = true;
141*92022041SSam Saccone 			break;
142*92022041SSam Saccone 		case NL80211_CQM_RSSI_BEACON_LOSS_EVENT:
143*92022041SSam Saccone 			printf("Beacon loss detected\n");
144*92022041SSam Saccone 			found_one = true;
145*92022041SSam Saccone 			break;
146*92022041SSam Saccone 		}
147*92022041SSam Saccone 
148*92022041SSam Saccone 		if (!found_one)
149*92022041SSam Saccone 			printf("Unknown event type: %i\n", rssi_event);
150*92022041SSam Saccone 	} else if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) {
151*92022041SSam Saccone 		if (attrs[NL80211_ATTR_MAC]) {
152*92022041SSam Saccone 			uint32_t frames;
153*92022041SSam Saccone 			char buf[3*6];
154*92022041SSam Saccone 
155*92022041SSam Saccone 			frames = nla_get_u32(cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]);
156*92022041SSam Saccone 			mac_addr_n2a(buf, nla_data(attrs[NL80211_ATTR_MAC]));
157*92022041SSam Saccone 			printf("peer %s didn't ACK %d packets\n", buf, frames);
158*92022041SSam Saccone 		} else {
159*92022041SSam Saccone 			printf("PKT-LOSS-EVENT did not have MAC attribute!\n");
160*92022041SSam Saccone 		}
161*92022041SSam Saccone 	} else if (cqm[NL80211_ATTR_CQM_BEACON_LOSS_EVENT]) {
162*92022041SSam Saccone 		printf("beacon loss\n");
163*92022041SSam Saccone 	} else {
164*92022041SSam Saccone 		printf("unknown event\n");
165*92022041SSam Saccone 	}
166*92022041SSam Saccone }
167*92022041SSam Saccone 
key_type_str(enum nl80211_key_type key_type)168*92022041SSam Saccone static const char * key_type_str(enum nl80211_key_type key_type)
169*92022041SSam Saccone {
170*92022041SSam Saccone 	static char buf[30];
171*92022041SSam Saccone 	switch (key_type) {
172*92022041SSam Saccone 	case NL80211_KEYTYPE_GROUP:
173*92022041SSam Saccone 		return "Group";
174*92022041SSam Saccone 	case NL80211_KEYTYPE_PAIRWISE:
175*92022041SSam Saccone 		return "Pairwise";
176*92022041SSam Saccone 	case NL80211_KEYTYPE_PEERKEY:
177*92022041SSam Saccone 		return "PeerKey";
178*92022041SSam Saccone 	default:
179*92022041SSam Saccone 		snprintf(buf, sizeof(buf), "unknown(%d)", key_type);
180*92022041SSam Saccone 		return buf;
181*92022041SSam Saccone 	}
182*92022041SSam Saccone }
183*92022041SSam Saccone 
parse_mic_failure(struct nlattr ** attrs)184*92022041SSam Saccone static void parse_mic_failure(struct nlattr **attrs)
185*92022041SSam Saccone {
186*92022041SSam Saccone 	printf("Michael MIC failure event:");
187*92022041SSam Saccone 
188*92022041SSam Saccone 	if (attrs[NL80211_ATTR_MAC]) {
189*92022041SSam Saccone 		char addr[3 * ETH_ALEN];
190*92022041SSam Saccone 		mac_addr_n2a(addr, nla_data(attrs[NL80211_ATTR_MAC]));
191*92022041SSam Saccone 		printf(" source MAC address %s", addr);
192*92022041SSam Saccone 	}
193*92022041SSam Saccone 
194*92022041SSam Saccone 	if (attrs[NL80211_ATTR_KEY_SEQ] &&
195*92022041SSam Saccone 	    nla_len(attrs[NL80211_ATTR_KEY_SEQ]) == 6) {
196*92022041SSam Saccone 		unsigned char *seq = nla_data(attrs[NL80211_ATTR_KEY_SEQ]);
197*92022041SSam Saccone 		printf(" seq=%02x%02x%02x%02x%02x%02x",
198*92022041SSam Saccone 		       seq[0], seq[1], seq[2], seq[3], seq[4], seq[5]);
199*92022041SSam Saccone 	}
200*92022041SSam Saccone 	if (attrs[NL80211_ATTR_KEY_TYPE]) {
201*92022041SSam Saccone 		enum nl80211_key_type key_type =
202*92022041SSam Saccone 			nla_get_u32(attrs[NL80211_ATTR_KEY_TYPE]);
203*92022041SSam Saccone 		printf(" Key Type %s", key_type_str(key_type));
204*92022041SSam Saccone 	}
205*92022041SSam Saccone 
206*92022041SSam Saccone 	if (attrs[NL80211_ATTR_KEY_IDX]) {
207*92022041SSam Saccone 		__u8 key_id = nla_get_u8(attrs[NL80211_ATTR_KEY_IDX]);
208*92022041SSam Saccone 		printf(" Key Id %d", key_id);
209*92022041SSam Saccone 	}
210*92022041SSam Saccone 
211*92022041SSam Saccone 	printf("\n");
212*92022041SSam Saccone }
213*92022041SSam Saccone 
parse_wowlan_wake_event(struct nlattr ** attrs)214*92022041SSam Saccone static void parse_wowlan_wake_event(struct nlattr **attrs)
215*92022041SSam Saccone {
216*92022041SSam Saccone 	struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG],
217*92022041SSam Saccone 		*tb_match[NUM_NL80211_ATTR];
218*92022041SSam Saccone 
219*92022041SSam Saccone 	printf("WoWLAN wakeup\n");
220*92022041SSam Saccone 	if (!attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) {
221*92022041SSam Saccone 		printf("\twakeup not due to WoWLAN\n");
222*92022041SSam Saccone 		return;
223*92022041SSam Saccone 	}
224*92022041SSam Saccone 
225*92022041SSam Saccone 	nla_parse(tb, MAX_NL80211_WOWLAN_TRIG,
226*92022041SSam Saccone 		  nla_data(attrs[NL80211_ATTR_WOWLAN_TRIGGERS]),
227*92022041SSam Saccone 		  nla_len(attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), NULL);
228*92022041SSam Saccone 
229*92022041SSam Saccone 	if (tb[NL80211_WOWLAN_TRIG_DISCONNECT])
230*92022041SSam Saccone 		printf("\t* was disconnected\n");
231*92022041SSam Saccone 	if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT])
232*92022041SSam Saccone 		printf("\t* magic packet received\n");
233*92022041SSam Saccone 	if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN])
234*92022041SSam Saccone 		printf("\t* pattern index: %u\n",
235*92022041SSam Saccone 		       nla_get_u32(tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]));
236*92022041SSam Saccone 	if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE])
237*92022041SSam Saccone 		printf("\t* GTK rekey failure\n");
238*92022041SSam Saccone 	if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST])
239*92022041SSam Saccone 		printf("\t* EAP identity request\n");
240*92022041SSam Saccone 	if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE])
241*92022041SSam Saccone 		printf("\t* 4-way handshake\n");
242*92022041SSam Saccone 	if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE])
243*92022041SSam Saccone 		printf("\t* RF-kill released\n");
244*92022041SSam Saccone 	if (tb[NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS]) {
245*92022041SSam Saccone 		struct nlattr *match, *freq;
246*92022041SSam Saccone 		int rem_nst, rem_nst2;
247*92022041SSam Saccone 
248*92022041SSam Saccone 		printf("\t* network detected\n");
249*92022041SSam Saccone 		nla_for_each_nested(match,
250*92022041SSam Saccone 				    tb[NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS],
251*92022041SSam Saccone 				    rem_nst) {
252*92022041SSam Saccone 			nla_parse_nested(tb_match, NL80211_ATTR_MAX, match,
253*92022041SSam Saccone 					 NULL);
254*92022041SSam Saccone 			printf("\t\tSSID: \"");
255*92022041SSam Saccone 			print_ssid_escaped(nla_len(tb_match[NL80211_ATTR_SSID]),
256*92022041SSam Saccone 					   nla_data(tb_match[NL80211_ATTR_SSID]));
257*92022041SSam Saccone 			printf("\"");
258*92022041SSam Saccone 			if (tb_match[NL80211_ATTR_SCAN_FREQUENCIES]) {
259*92022041SSam Saccone 				printf(" freq(s):");
260*92022041SSam Saccone 				nla_for_each_nested(freq,
261*92022041SSam Saccone 						    tb_match[NL80211_ATTR_SCAN_FREQUENCIES],
262*92022041SSam Saccone 						    rem_nst2)
263*92022041SSam Saccone 					printf(" %d", nla_get_u32(freq));
264*92022041SSam Saccone 			}
265*92022041SSam Saccone 			printf("\n");
266*92022041SSam Saccone 		}
267*92022041SSam Saccone 	}
268*92022041SSam Saccone 	if (tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211]) {
269*92022041SSam Saccone 		uint8_t *d = nla_data(tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211]);
270*92022041SSam Saccone 		int l = nla_len(tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211]);
271*92022041SSam Saccone 		int i;
272*92022041SSam Saccone 		printf("\t* packet (might be truncated): ");
273*92022041SSam Saccone 		for (i = 0; i < l; i++) {
274*92022041SSam Saccone 			if (i > 0)
275*92022041SSam Saccone 				printf(":");
276*92022041SSam Saccone 			printf("%.2x", d[i]);
277*92022041SSam Saccone 		}
278*92022041SSam Saccone 		printf("\n");
279*92022041SSam Saccone 	}
280*92022041SSam Saccone 	if (tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023]) {
281*92022041SSam Saccone 		uint8_t *d = nla_data(tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023]);
282*92022041SSam Saccone 		int l = nla_len(tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023]);
283*92022041SSam Saccone 		int i;
284*92022041SSam Saccone 		printf("\t* packet (might be truncated): ");
285*92022041SSam Saccone 		for (i = 0; i < l; i++) {
286*92022041SSam Saccone 			if (i > 0)
287*92022041SSam Saccone 				printf(":");
288*92022041SSam Saccone 			printf("%.2x", d[i]);
289*92022041SSam Saccone 		}
290*92022041SSam Saccone 		printf("\n");
291*92022041SSam Saccone 	}
292*92022041SSam Saccone 	if (tb[NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH])
293*92022041SSam Saccone 		printf("\t* TCP connection wakeup received\n");
294*92022041SSam Saccone 	if (tb[NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST])
295*92022041SSam Saccone 		printf("\t* TCP connection lost\n");
296*92022041SSam Saccone 	if (tb[NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS])
297*92022041SSam Saccone 		printf("\t* TCP connection ran out of tokens\n");
298*92022041SSam Saccone }
299*92022041SSam Saccone 
300*92022041SSam Saccone extern struct vendor_event *__start_vendor_event[];
301*92022041SSam Saccone extern struct vendor_event *__stop_vendor_event;
302*92022041SSam Saccone 
303*92022041SSam Saccone // Dummy to force the section to exist
304*92022041SSam Saccone VENDOR_EVENT(0xffffffff, 0xffffffff, NULL);
305*92022041SSam Saccone 
parse_vendor_event(struct nlattr ** attrs,bool dump)306*92022041SSam Saccone static void parse_vendor_event(struct nlattr **attrs, bool dump)
307*92022041SSam Saccone {
308*92022041SSam Saccone 	__u32 vendor_id, subcmd;
309*92022041SSam Saccone 	unsigned int i;
310*92022041SSam Saccone 
311*92022041SSam Saccone 	if (!attrs[NL80211_ATTR_VENDOR_ID] ||
312*92022041SSam Saccone 	    !attrs[NL80211_ATTR_VENDOR_SUBCMD])
313*92022041SSam Saccone 		return;
314*92022041SSam Saccone 
315*92022041SSam Saccone 	vendor_id = nla_get_u32(attrs[NL80211_ATTR_VENDOR_ID]);
316*92022041SSam Saccone 	subcmd = nla_get_u32(attrs[NL80211_ATTR_VENDOR_SUBCMD]);
317*92022041SSam Saccone 
318*92022041SSam Saccone 	printf("vendor event %.6x:%d", vendor_id, subcmd);
319*92022041SSam Saccone 
320*92022041SSam Saccone 	for (i = 0; i < &__stop_vendor_event - __start_vendor_event; i++) {
321*92022041SSam Saccone 		struct vendor_event *ev = __start_vendor_event[i];
322*92022041SSam Saccone 
323*92022041SSam Saccone 		if (!ev)
324*92022041SSam Saccone 			continue;
325*92022041SSam Saccone 
326*92022041SSam Saccone 		if (ev->vendor_id != vendor_id)
327*92022041SSam Saccone 			continue;
328*92022041SSam Saccone 		if (ev->subcmd != subcmd)
329*92022041SSam Saccone 			continue;
330*92022041SSam Saccone 		if (!ev->callback)
331*92022041SSam Saccone 			continue;
332*92022041SSam Saccone 
333*92022041SSam Saccone 		ev->callback(vendor_id, subcmd, attrs[NL80211_ATTR_VENDOR_DATA]);
334*92022041SSam Saccone 		goto out;
335*92022041SSam Saccone 	}
336*92022041SSam Saccone 
337*92022041SSam Saccone 	if (dump && attrs[NL80211_ATTR_VENDOR_DATA])
338*92022041SSam Saccone 		iw_hexdump("vendor event",
339*92022041SSam Saccone 			   nla_data(attrs[NL80211_ATTR_VENDOR_DATA]),
340*92022041SSam Saccone 			   nla_len(attrs[NL80211_ATTR_VENDOR_DATA]));
341*92022041SSam Saccone out:
342*92022041SSam Saccone 	printf("\n");
343*92022041SSam Saccone }
344*92022041SSam Saccone 
parse_nan_term(struct nlattr ** attrs)345*92022041SSam Saccone static void parse_nan_term(struct nlattr **attrs)
346*92022041SSam Saccone {
347*92022041SSam Saccone 	struct nlattr *func[NL80211_NAN_FUNC_ATTR_MAX + 1];
348*92022041SSam Saccone 
349*92022041SSam Saccone 	static struct nla_policy
350*92022041SSam Saccone 		nan_func_policy[NL80211_NAN_FUNC_ATTR_MAX + 1] = {
351*92022041SSam Saccone 		[NL80211_NAN_FUNC_TYPE] = { .type = NLA_U8 },
352*92022041SSam Saccone 		[NL80211_NAN_FUNC_SERVICE_ID] = { },
353*92022041SSam Saccone 		[NL80211_NAN_FUNC_PUBLISH_TYPE] = { .type = NLA_U8 },
354*92022041SSam Saccone 		[NL80211_NAN_FUNC_PUBLISH_BCAST] = { .type = NLA_FLAG },
355*92022041SSam Saccone 		[NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE] = { .type = NLA_FLAG },
356*92022041SSam Saccone 		[NL80211_NAN_FUNC_FOLLOW_UP_ID] = { .type = NLA_U8 },
357*92022041SSam Saccone 		[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] = { .type = NLA_U8 },
358*92022041SSam Saccone 		[NL80211_NAN_FUNC_FOLLOW_UP_DEST] = { },
359*92022041SSam Saccone 		[NL80211_NAN_FUNC_CLOSE_RANGE] = { .type = NLA_FLAG },
360*92022041SSam Saccone 		[NL80211_NAN_FUNC_TTL] = { .type = NLA_U32 },
361*92022041SSam Saccone 		[NL80211_NAN_FUNC_SERVICE_INFO] = { },
362*92022041SSam Saccone 		[NL80211_NAN_FUNC_SRF] = { .type = NLA_NESTED },
363*92022041SSam Saccone 		[NL80211_NAN_FUNC_RX_MATCH_FILTER] = { .type = NLA_NESTED },
364*92022041SSam Saccone 		[NL80211_NAN_FUNC_TX_MATCH_FILTER] = { .type = NLA_NESTED },
365*92022041SSam Saccone 		[NL80211_NAN_FUNC_INSTANCE_ID] = { .type = NLA_U8},
366*92022041SSam Saccone 	};
367*92022041SSam Saccone 
368*92022041SSam Saccone 	if (!attrs[NL80211_ATTR_COOKIE]) {
369*92022041SSam Saccone 		printf("Bad NAN func termination format - cookie is missing\n");
370*92022041SSam Saccone 		return;
371*92022041SSam Saccone 	}
372*92022041SSam Saccone 
373*92022041SSam Saccone 	if (nla_parse_nested(func, NL80211_NAN_FUNC_ATTR_MAX,
374*92022041SSam Saccone 			     attrs[NL80211_ATTR_NAN_FUNC],
375*92022041SSam Saccone 			     nan_func_policy)) {
376*92022041SSam Saccone 		printf("NAN: failed to parse nan func\n");
377*92022041SSam Saccone 		return;
378*92022041SSam Saccone 	}
379*92022041SSam Saccone 
380*92022041SSam Saccone 	if (!func[NL80211_NAN_FUNC_INSTANCE_ID]) {
381*92022041SSam Saccone 		printf("Bad NAN func termination format-instance id missing\n");
382*92022041SSam Saccone 		return;
383*92022041SSam Saccone 	}
384*92022041SSam Saccone 
385*92022041SSam Saccone 	if (!func[NL80211_NAN_FUNC_TERM_REASON]) {
386*92022041SSam Saccone 		printf("Bad NAN func termination format - reason is missing\n");
387*92022041SSam Saccone 		return;
388*92022041SSam Saccone 	}
389*92022041SSam Saccone 	printf("NAN(cookie=0x%llx): Termination event: id = %d, reason = ",
390*92022041SSam Saccone 	       (long long int)nla_get_u64(attrs[NL80211_ATTR_COOKIE]),
391*92022041SSam Saccone 	       nla_get_u8(func[NL80211_NAN_FUNC_INSTANCE_ID]));
392*92022041SSam Saccone 	switch (nla_get_u8(func[NL80211_NAN_FUNC_TERM_REASON])) {
393*92022041SSam Saccone 	case NL80211_NAN_FUNC_TERM_REASON_USER_REQUEST:
394*92022041SSam Saccone 		printf("user request\n");
395*92022041SSam Saccone 		break;
396*92022041SSam Saccone 	case NL80211_NAN_FUNC_TERM_REASON_TTL_EXPIRED:
397*92022041SSam Saccone 		printf("expired\n");
398*92022041SSam Saccone 		break;
399*92022041SSam Saccone 	case NL80211_NAN_FUNC_TERM_REASON_ERROR:
400*92022041SSam Saccone 		printf("error\n");
401*92022041SSam Saccone 		break;
402*92022041SSam Saccone 	default:
403*92022041SSam Saccone 		printf("unknown\n");
404*92022041SSam Saccone 	}
405*92022041SSam Saccone }
406*92022041SSam Saccone 
ftm_fail_reason(unsigned int reason)407*92022041SSam Saccone static const char *ftm_fail_reason(unsigned int reason)
408*92022041SSam Saccone {
409*92022041SSam Saccone #define FTM_FAIL_REASON(x) case NL80211_PMSR_FTM_FAILURE_##x: return #x
410*92022041SSam Saccone 	switch (reason) {
411*92022041SSam Saccone 	FTM_FAIL_REASON(UNSPECIFIED);
412*92022041SSam Saccone 	FTM_FAIL_REASON(NO_RESPONSE);
413*92022041SSam Saccone 	FTM_FAIL_REASON(REJECTED);
414*92022041SSam Saccone 	FTM_FAIL_REASON(WRONG_CHANNEL);
415*92022041SSam Saccone 	FTM_FAIL_REASON(PEER_NOT_CAPABLE);
416*92022041SSam Saccone 	FTM_FAIL_REASON(INVALID_TIMESTAMP);
417*92022041SSam Saccone 	FTM_FAIL_REASON(PEER_BUSY);
418*92022041SSam Saccone 	FTM_FAIL_REASON(BAD_CHANGED_PARAMS);
419*92022041SSam Saccone 	default:
420*92022041SSam Saccone 		return "unknown";
421*92022041SSam Saccone 	}
422*92022041SSam Saccone }
423*92022041SSam Saccone 
parse_pmsr_ftm_data(struct nlattr * data)424*92022041SSam Saccone static void parse_pmsr_ftm_data(struct nlattr *data)
425*92022041SSam Saccone {
426*92022041SSam Saccone 	struct nlattr *ftm[NL80211_PMSR_FTM_RESP_ATTR_MAX + 1];
427*92022041SSam Saccone 
428*92022041SSam Saccone 	printf("    FTM");
429*92022041SSam Saccone 	nla_parse_nested(ftm, NL80211_PMSR_FTM_RESP_ATTR_MAX, data, NULL);
430*92022041SSam Saccone 
431*92022041SSam Saccone 	if (ftm[NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON]) {
432*92022041SSam Saccone 		printf(" failed: %s (%d)",
433*92022041SSam Saccone 		       ftm_fail_reason(nla_get_u32(ftm[NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON])),
434*92022041SSam Saccone 		       nla_get_u32(ftm[NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON]));
435*92022041SSam Saccone 		if (ftm[NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME])
436*92022041SSam Saccone 			printf(" retry after %us",
437*92022041SSam Saccone 			       nla_get_u32(ftm[NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME]));
438*92022041SSam Saccone 		printf("\n");
439*92022041SSam Saccone 		return;
440*92022041SSam Saccone 	}
441*92022041SSam Saccone 
442*92022041SSam Saccone 	printf("\n");
443*92022041SSam Saccone 
444*92022041SSam Saccone #define PFTM(tp, attr, sign)							\
445*92022041SSam Saccone 	do {									\
446*92022041SSam Saccone 		if (ftm[NL80211_PMSR_FTM_RESP_ATTR_##attr])			\
447*92022041SSam Saccone 			printf("      " #attr ": %lld\n",			\
448*92022041SSam Saccone 			       (sign long long)nla_get_##tp(			\
449*92022041SSam Saccone 				ftm[NL80211_PMSR_FTM_RESP_ATTR_##attr]));	\
450*92022041SSam Saccone 	} while (0)
451*92022041SSam Saccone 
452*92022041SSam Saccone 	PFTM(u32, BURST_INDEX, unsigned);
453*92022041SSam Saccone 	PFTM(u32, NUM_FTMR_ATTEMPTS, unsigned);
454*92022041SSam Saccone 	PFTM(u32, NUM_FTMR_SUCCESSES, unsigned);
455*92022041SSam Saccone 	PFTM(u8, NUM_BURSTS_EXP, unsigned);
456*92022041SSam Saccone 	PFTM(u8, BURST_DURATION, unsigned);
457*92022041SSam Saccone 	PFTM(u8, FTMS_PER_BURST, unsigned);
458*92022041SSam Saccone 	PFTM(u32, RSSI_AVG, signed);
459*92022041SSam Saccone 	PFTM(u32, RSSI_SPREAD, unsigned);
460*92022041SSam Saccone 	PFTM(u64, RTT_AVG, signed);
461*92022041SSam Saccone 	PFTM(u64, RTT_VARIANCE, unsigned);
462*92022041SSam Saccone 	PFTM(u64, RTT_SPREAD, unsigned);
463*92022041SSam Saccone 	PFTM(u64, DIST_AVG, signed);
464*92022041SSam Saccone 	PFTM(u64, DIST_VARIANCE, unsigned);
465*92022041SSam Saccone 	PFTM(u64, DIST_SPREAD, unsigned);
466*92022041SSam Saccone 
467*92022041SSam Saccone 	if (ftm[NL80211_PMSR_FTM_RESP_ATTR_TX_RATE]) {
468*92022041SSam Saccone 		char buf[100];
469*92022041SSam Saccone 
470*92022041SSam Saccone 		parse_bitrate(ftm[NL80211_PMSR_FTM_RESP_ATTR_TX_RATE],
471*92022041SSam Saccone 			      buf, sizeof(buf));
472*92022041SSam Saccone 		printf("      TX bitrate: %s\n", buf);
473*92022041SSam Saccone 	}
474*92022041SSam Saccone 
475*92022041SSam Saccone 	if (ftm[NL80211_PMSR_FTM_RESP_ATTR_RX_RATE]) {
476*92022041SSam Saccone 		char buf[100];
477*92022041SSam Saccone 
478*92022041SSam Saccone 		parse_bitrate(ftm[NL80211_PMSR_FTM_RESP_ATTR_RX_RATE],
479*92022041SSam Saccone 			      buf, sizeof(buf));
480*92022041SSam Saccone 		printf("      RX bitrate: %s\n", buf);
481*92022041SSam Saccone 	}
482*92022041SSam Saccone 
483*92022041SSam Saccone 	if (ftm[NL80211_PMSR_FTM_RESP_ATTR_LCI])
484*92022041SSam Saccone 		iw_hexdump("      LCI",
485*92022041SSam Saccone 			   nla_data(ftm[NL80211_PMSR_FTM_RESP_ATTR_LCI]),
486*92022041SSam Saccone 			   nla_len(ftm[NL80211_PMSR_FTM_RESP_ATTR_LCI]));
487*92022041SSam Saccone 
488*92022041SSam Saccone 	if (ftm[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC])
489*92022041SSam Saccone 		iw_hexdump("      civic location",
490*92022041SSam Saccone 			   nla_data(ftm[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC]),
491*92022041SSam Saccone 			   nla_len(ftm[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC]));
492*92022041SSam Saccone }
493*92022041SSam Saccone 
pmsr_status(unsigned int status)494*92022041SSam Saccone static const char *pmsr_status(unsigned int status)
495*92022041SSam Saccone {
496*92022041SSam Saccone #define PMSR_STATUS(x) case NL80211_PMSR_STATUS_##x: return #x
497*92022041SSam Saccone 	switch (status) {
498*92022041SSam Saccone 	PMSR_STATUS(SUCCESS);
499*92022041SSam Saccone 	PMSR_STATUS(REFUSED);
500*92022041SSam Saccone 	PMSR_STATUS(TIMEOUT);
501*92022041SSam Saccone 	PMSR_STATUS(FAILURE);
502*92022041SSam Saccone 	default:
503*92022041SSam Saccone 		return "unknown";
504*92022041SSam Saccone 	}
505*92022041SSam Saccone #undef PMSR_STATUS
506*92022041SSam Saccone }
507*92022041SSam Saccone 
parse_pmsr_peer(struct nlattr * peer)508*92022041SSam Saccone static void parse_pmsr_peer(struct nlattr *peer)
509*92022041SSam Saccone {
510*92022041SSam Saccone 	struct nlattr *tb[NL80211_PMSR_PEER_ATTR_MAX + 1];
511*92022041SSam Saccone 	struct nlattr *resp[NL80211_PMSR_RESP_ATTR_MAX + 1];
512*92022041SSam Saccone 	struct nlattr *data[NL80211_PMSR_TYPE_MAX + 1];
513*92022041SSam Saccone 	char macbuf[6*3];
514*92022041SSam Saccone 	int err;
515*92022041SSam Saccone 
516*92022041SSam Saccone 	err = nla_parse_nested(tb, NL80211_PMSR_PEER_ATTR_MAX, peer, NULL);
517*92022041SSam Saccone 	if (err) {
518*92022041SSam Saccone 		printf("  Peer: failed to parse!\n");
519*92022041SSam Saccone 		return;
520*92022041SSam Saccone 	}
521*92022041SSam Saccone 
522*92022041SSam Saccone 	if (!tb[NL80211_PMSR_PEER_ATTR_ADDR]) {
523*92022041SSam Saccone 		printf("  Peer: no MAC address\n");
524*92022041SSam Saccone 		return;
525*92022041SSam Saccone 	}
526*92022041SSam Saccone 
527*92022041SSam Saccone 	mac_addr_n2a(macbuf, nla_data(tb[NL80211_PMSR_PEER_ATTR_ADDR]));
528*92022041SSam Saccone 	printf("  Peer %s:", macbuf);
529*92022041SSam Saccone 
530*92022041SSam Saccone 	if (!tb[NL80211_PMSR_PEER_ATTR_RESP]) {
531*92022041SSam Saccone 		printf(" no response!\n");
532*92022041SSam Saccone 		return;
533*92022041SSam Saccone 	}
534*92022041SSam Saccone 
535*92022041SSam Saccone 	err = nla_parse_nested(resp, NL80211_PMSR_RESP_ATTR_MAX,
536*92022041SSam Saccone 			       tb[NL80211_PMSR_PEER_ATTR_RESP], NULL);
537*92022041SSam Saccone 	if (err) {
538*92022041SSam Saccone 		printf(" failed to parse response!\n");
539*92022041SSam Saccone 		return;
540*92022041SSam Saccone 	}
541*92022041SSam Saccone 
542*92022041SSam Saccone 	if (resp[NL80211_PMSR_RESP_ATTR_STATUS])
543*92022041SSam Saccone 		printf(" status=%d (%s)",
544*92022041SSam Saccone 		       nla_get_u32(resp[NL80211_PMSR_RESP_ATTR_STATUS]),
545*92022041SSam Saccone 		       pmsr_status(nla_get_u32(resp[NL80211_PMSR_RESP_ATTR_STATUS])));
546*92022041SSam Saccone 	if (resp[NL80211_PMSR_RESP_ATTR_HOST_TIME])
547*92022041SSam Saccone 		printf(" @%llu",
548*92022041SSam Saccone 		       (unsigned long long)nla_get_u64(resp[NL80211_PMSR_RESP_ATTR_HOST_TIME]));
549*92022041SSam Saccone 	if (resp[NL80211_PMSR_RESP_ATTR_AP_TSF])
550*92022041SSam Saccone 		printf(" tsf=%llu",
551*92022041SSam Saccone 		       (unsigned long long)nla_get_u64(resp[NL80211_PMSR_RESP_ATTR_AP_TSF]));
552*92022041SSam Saccone 	if (resp[NL80211_PMSR_RESP_ATTR_FINAL])
553*92022041SSam Saccone 		printf(" (final)");
554*92022041SSam Saccone 
555*92022041SSam Saccone 	if (!resp[NL80211_PMSR_RESP_ATTR_DATA]) {
556*92022041SSam Saccone 		printf(" - no data!\n");
557*92022041SSam Saccone 		return;
558*92022041SSam Saccone 	}
559*92022041SSam Saccone 
560*92022041SSam Saccone 	printf("\n");
561*92022041SSam Saccone 
562*92022041SSam Saccone 	nla_parse_nested(data, NL80211_PMSR_TYPE_MAX,
563*92022041SSam Saccone 			 resp[NL80211_PMSR_RESP_ATTR_DATA], NULL);
564*92022041SSam Saccone 
565*92022041SSam Saccone 	if (data[NL80211_PMSR_TYPE_FTM])
566*92022041SSam Saccone 		parse_pmsr_ftm_data(data[NL80211_PMSR_TYPE_FTM]);
567*92022041SSam Saccone }
568*92022041SSam Saccone 
parse_pmsr_result(struct nlattr ** tb,struct print_event_args * pargs)569*92022041SSam Saccone static void parse_pmsr_result(struct nlattr **tb,
570*92022041SSam Saccone 			      struct print_event_args *pargs)
571*92022041SSam Saccone {
572*92022041SSam Saccone 	struct nlattr *pmsr[NL80211_PMSR_ATTR_MAX + 1];
573*92022041SSam Saccone 	struct nlattr *peer;
574*92022041SSam Saccone 	unsigned long long cookie;
575*92022041SSam Saccone 	int err, i;
576*92022041SSam Saccone 
577*92022041SSam Saccone 	if (!tb[NL80211_ATTR_COOKIE]) {
578*92022041SSam Saccone 		printf("Peer measurements: no cookie!\n");
579*92022041SSam Saccone 		return;
580*92022041SSam Saccone 	}
581*92022041SSam Saccone 	cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
582*92022041SSam Saccone 
583*92022041SSam Saccone 	if (!tb[NL80211_ATTR_PEER_MEASUREMENTS]) {
584*92022041SSam Saccone 		printf("Peer measurements: no measurement data!\n");
585*92022041SSam Saccone 		return;
586*92022041SSam Saccone 	}
587*92022041SSam Saccone 
588*92022041SSam Saccone 	err = nla_parse_nested(pmsr, NL80211_PMSR_ATTR_MAX,
589*92022041SSam Saccone 			       tb[NL80211_ATTR_PEER_MEASUREMENTS], NULL);
590*92022041SSam Saccone 	if (err) {
591*92022041SSam Saccone 		printf("Peer measurements: failed to parse measurement data!\n");
592*92022041SSam Saccone 		return;
593*92022041SSam Saccone 	}
594*92022041SSam Saccone 
595*92022041SSam Saccone 	if (!pmsr[NL80211_PMSR_ATTR_PEERS]) {
596*92022041SSam Saccone 		printf("Peer measurements: no peer data!\n");
597*92022041SSam Saccone 		return;
598*92022041SSam Saccone 	}
599*92022041SSam Saccone 
600*92022041SSam Saccone 	printf("Peer measurements (cookie %llu):\n", cookie);
601*92022041SSam Saccone 
602*92022041SSam Saccone 	nla_for_each_nested(peer, pmsr[NL80211_PMSR_ATTR_PEERS], i)
603*92022041SSam Saccone 		parse_pmsr_peer(peer);
604*92022041SSam Saccone }
605*92022041SSam Saccone 
parse_nan_match(struct nlattr ** attrs)606*92022041SSam Saccone static void parse_nan_match(struct nlattr **attrs)
607*92022041SSam Saccone {
608*92022041SSam Saccone 	char macbuf[6*3];
609*92022041SSam Saccone 	__u64 cookie;
610*92022041SSam Saccone 	struct nlattr *match[NL80211_NAN_MATCH_ATTR_MAX + 1];
611*92022041SSam Saccone 	struct nlattr *local_func[NL80211_NAN_FUNC_ATTR_MAX + 1];
612*92022041SSam Saccone 	struct nlattr *peer_func[NL80211_NAN_FUNC_ATTR_MAX + 1];
613*92022041SSam Saccone 
614*92022041SSam Saccone 	static struct nla_policy
615*92022041SSam Saccone 		nan_match_policy[NL80211_NAN_MATCH_ATTR_MAX + 1] = {
616*92022041SSam Saccone 		[NL80211_NAN_MATCH_FUNC_LOCAL] = { .type = NLA_NESTED },
617*92022041SSam Saccone 		[NL80211_NAN_MATCH_FUNC_PEER] = { .type = NLA_NESTED },
618*92022041SSam Saccone 	};
619*92022041SSam Saccone 
620*92022041SSam Saccone 	static struct nla_policy
621*92022041SSam Saccone 		nan_func_policy[NL80211_NAN_FUNC_ATTR_MAX + 1] = {
622*92022041SSam Saccone 		[NL80211_NAN_FUNC_TYPE] = { .type = NLA_U8 },
623*92022041SSam Saccone 		[NL80211_NAN_FUNC_SERVICE_ID] = { },
624*92022041SSam Saccone 		[NL80211_NAN_FUNC_PUBLISH_TYPE] = { .type = NLA_U8 },
625*92022041SSam Saccone 		[NL80211_NAN_FUNC_PUBLISH_BCAST] = { .type = NLA_FLAG },
626*92022041SSam Saccone 		[NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE] = { .type = NLA_FLAG },
627*92022041SSam Saccone 		[NL80211_NAN_FUNC_FOLLOW_UP_ID] = { .type = NLA_U8 },
628*92022041SSam Saccone 		[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] = { .type = NLA_U8 },
629*92022041SSam Saccone 		[NL80211_NAN_FUNC_FOLLOW_UP_DEST] = { },
630*92022041SSam Saccone 		[NL80211_NAN_FUNC_CLOSE_RANGE] = { .type = NLA_FLAG },
631*92022041SSam Saccone 		[NL80211_NAN_FUNC_TTL] = { .type = NLA_U32 },
632*92022041SSam Saccone 		[NL80211_NAN_FUNC_SERVICE_INFO] = { },
633*92022041SSam Saccone 		[NL80211_NAN_FUNC_SRF] = { .type = NLA_NESTED },
634*92022041SSam Saccone 		[NL80211_NAN_FUNC_RX_MATCH_FILTER] = { .type = NLA_NESTED },
635*92022041SSam Saccone 		[NL80211_NAN_FUNC_TX_MATCH_FILTER] = { .type = NLA_NESTED },
636*92022041SSam Saccone 		[NL80211_NAN_FUNC_INSTANCE_ID] = { .type = NLA_U8},
637*92022041SSam Saccone 	};
638*92022041SSam Saccone 
639*92022041SSam Saccone 	cookie = nla_get_u64(attrs[NL80211_ATTR_COOKIE]);
640*92022041SSam Saccone 	mac_addr_n2a(macbuf, nla_data(attrs[NL80211_ATTR_MAC]));
641*92022041SSam Saccone 
642*92022041SSam Saccone 	if (nla_parse_nested(match, NL80211_NAN_MATCH_ATTR_MAX,
643*92022041SSam Saccone 			     attrs[NL80211_ATTR_NAN_MATCH],
644*92022041SSam Saccone 			     nan_match_policy)) {
645*92022041SSam Saccone 		printf("NAN: failed to parse nan match event\n");
646*92022041SSam Saccone 		return;
647*92022041SSam Saccone 	}
648*92022041SSam Saccone 
649*92022041SSam Saccone 	if (nla_parse_nested(local_func, NL80211_NAN_FUNC_ATTR_MAX,
650*92022041SSam Saccone 			     match[NL80211_NAN_MATCH_FUNC_LOCAL],
651*92022041SSam Saccone 			     nan_func_policy)) {
652*92022041SSam Saccone 		printf("NAN: failed to parse nan local func\n");
653*92022041SSam Saccone 		return;
654*92022041SSam Saccone 	}
655*92022041SSam Saccone 
656*92022041SSam Saccone 	if (nla_parse_nested(peer_func, NL80211_NAN_FUNC_ATTR_MAX,
657*92022041SSam Saccone 			      match[NL80211_NAN_MATCH_FUNC_PEER],
658*92022041SSam Saccone 			      nan_func_policy)) {
659*92022041SSam Saccone 		printf("NAN: failed to parse nan local func\n");
660*92022041SSam Saccone 		return;
661*92022041SSam Saccone 	}
662*92022041SSam Saccone 
663*92022041SSam Saccone 	if (nla_get_u8(peer_func[NL80211_NAN_FUNC_TYPE]) ==
664*92022041SSam Saccone 	    NL80211_NAN_FUNC_PUBLISH) {
665*92022041SSam Saccone 		printf(
666*92022041SSam Saccone 		       "NAN(cookie=0x%llx): DiscoveryResult, peer_id=%d, local_id=%d, peer_mac=%s",
667*92022041SSam Saccone 		       cookie,
668*92022041SSam Saccone 		       nla_get_u8(peer_func[NL80211_NAN_FUNC_INSTANCE_ID]),
669*92022041SSam Saccone 		       nla_get_u8(local_func[NL80211_NAN_FUNC_INSTANCE_ID]),
670*92022041SSam Saccone 		       macbuf);
671*92022041SSam Saccone 		if (peer_func[NL80211_NAN_FUNC_SERVICE_INFO])
672*92022041SSam Saccone 			printf(", info=%.*s",
673*92022041SSam Saccone 				   nla_len(peer_func[NL80211_NAN_FUNC_SERVICE_INFO]),
674*92022041SSam Saccone 			       (char *)nla_data(peer_func[NL80211_NAN_FUNC_SERVICE_INFO]));
675*92022041SSam Saccone 	} else if (nla_get_u8(peer_func[NL80211_NAN_FUNC_TYPE]) ==
676*92022041SSam Saccone 		   NL80211_NAN_FUNC_SUBSCRIBE) {
677*92022041SSam Saccone 		printf(
678*92022041SSam Saccone 		       "NAN(cookie=0x%llx): Replied, peer_id=%d, local_id=%d, peer_mac=%s",
679*92022041SSam Saccone 		       cookie,
680*92022041SSam Saccone 		       nla_get_u8(peer_func[NL80211_NAN_FUNC_INSTANCE_ID]),
681*92022041SSam Saccone 		       nla_get_u8(local_func[NL80211_NAN_FUNC_INSTANCE_ID]),
682*92022041SSam Saccone 		       macbuf);
683*92022041SSam Saccone 	} else if (nla_get_u8(peer_func[NL80211_NAN_FUNC_TYPE]) ==
684*92022041SSam Saccone 		   NL80211_NAN_FUNC_FOLLOW_UP) {
685*92022041SSam Saccone 		printf(
686*92022041SSam Saccone 		       "NAN(cookie=0x%llx): FollowUpReceive, peer_id=%d, local_id=%d, peer_mac=%s",
687*92022041SSam Saccone 		       cookie,
688*92022041SSam Saccone 		       nla_get_u8(peer_func[NL80211_NAN_FUNC_INSTANCE_ID]),
689*92022041SSam Saccone 		       nla_get_u8(local_func[NL80211_NAN_FUNC_INSTANCE_ID]),
690*92022041SSam Saccone 		       macbuf);
691*92022041SSam Saccone 		if (peer_func[NL80211_NAN_FUNC_SERVICE_INFO])
692*92022041SSam Saccone 			printf(", info=%.*s",
693*92022041SSam Saccone 			       nla_len(peer_func[NL80211_NAN_FUNC_SERVICE_INFO]),
694*92022041SSam Saccone 			       (char *)nla_data(peer_func[NL80211_NAN_FUNC_SERVICE_INFO]));
695*92022041SSam Saccone 	} else {
696*92022041SSam Saccone 		printf("NaN: Malformed event");
697*92022041SSam Saccone 	}
698*92022041SSam Saccone 
699*92022041SSam Saccone 	printf("\n");
700*92022041SSam Saccone }
701*92022041SSam Saccone 
parse_new_peer_candidate(struct nlattr ** attrs)702*92022041SSam Saccone static void parse_new_peer_candidate(struct nlattr **attrs)
703*92022041SSam Saccone {
704*92022041SSam Saccone 	char macbuf[ETH_ALEN * 3];
705*92022041SSam Saccone 	int32_t sig_dbm;
706*92022041SSam Saccone 
707*92022041SSam Saccone 	printf("new peer candidate");
708*92022041SSam Saccone 	if (attrs[NL80211_ATTR_MAC]) {
709*92022041SSam Saccone 		mac_addr_n2a(macbuf, nla_data(attrs[NL80211_ATTR_MAC]));
710*92022041SSam Saccone 		printf(" %s", macbuf);
711*92022041SSam Saccone 	}
712*92022041SSam Saccone 	if (attrs[NL80211_ATTR_RX_SIGNAL_DBM]) {
713*92022041SSam Saccone 		sig_dbm = nla_get_u32(attrs[NL80211_ATTR_RX_SIGNAL_DBM]);
714*92022041SSam Saccone 		printf(" %d dBm", sig_dbm);
715*92022041SSam Saccone 	}
716*92022041SSam Saccone 
717*92022041SSam Saccone 	printf("\n");
718*92022041SSam Saccone }
719*92022041SSam Saccone 
parse_recv_interface(struct nlattr ** attrs,int command)720*92022041SSam Saccone static void parse_recv_interface(struct nlattr **attrs, int command)
721*92022041SSam Saccone {
722*92022041SSam Saccone 	switch (command) {
723*92022041SSam Saccone 	case NL80211_CMD_NEW_INTERFACE:
724*92022041SSam Saccone 		printf("new interface");
725*92022041SSam Saccone 		break;
726*92022041SSam Saccone 	case NL80211_CMD_DEL_INTERFACE:
727*92022041SSam Saccone 		printf("del interface");
728*92022041SSam Saccone 		break;
729*92022041SSam Saccone 	case NL80211_CMD_SET_INTERFACE:
730*92022041SSam Saccone 		printf("set interface");
731*92022041SSam Saccone 		break;
732*92022041SSam Saccone 	default:
733*92022041SSam Saccone 		printf("unknown interface command (%i) received\n", command);
734*92022041SSam Saccone 		return;
735*92022041SSam Saccone 	}
736*92022041SSam Saccone 
737*92022041SSam Saccone 	if (attrs[NL80211_ATTR_IFTYPE]) {
738*92022041SSam Saccone 		printf(" type ");
739*92022041SSam Saccone 		switch (nla_get_u32(attrs[NL80211_ATTR_IFTYPE])) {
740*92022041SSam Saccone 		case NL80211_IFTYPE_STATION:
741*92022041SSam Saccone 			printf("station");
742*92022041SSam Saccone 			break;
743*92022041SSam Saccone 		case NL80211_IFTYPE_AP:
744*92022041SSam Saccone 			printf("access point");
745*92022041SSam Saccone 			break;
746*92022041SSam Saccone 		case NL80211_IFTYPE_MESH_POINT:
747*92022041SSam Saccone 			printf("mesh point");
748*92022041SSam Saccone 			break;
749*92022041SSam Saccone 		case NL80211_IFTYPE_ADHOC:
750*92022041SSam Saccone 			printf("IBSS");
751*92022041SSam Saccone 			break;
752*92022041SSam Saccone 		case NL80211_IFTYPE_MONITOR:
753*92022041SSam Saccone 			printf("monitor");
754*92022041SSam Saccone 			break;
755*92022041SSam Saccone 		case NL80211_IFTYPE_AP_VLAN:
756*92022041SSam Saccone 			printf("AP-VLAN");
757*92022041SSam Saccone 			break;
758*92022041SSam Saccone 		case NL80211_IFTYPE_WDS:
759*92022041SSam Saccone 			printf("WDS");
760*92022041SSam Saccone 			break;
761*92022041SSam Saccone 		case NL80211_IFTYPE_P2P_CLIENT:
762*92022041SSam Saccone 			printf("P2P-client");
763*92022041SSam Saccone 			break;
764*92022041SSam Saccone 		case NL80211_IFTYPE_P2P_GO:
765*92022041SSam Saccone 			printf("P2P-GO");
766*92022041SSam Saccone 			break;
767*92022041SSam Saccone 		case NL80211_IFTYPE_P2P_DEVICE:
768*92022041SSam Saccone 			printf("P2P-Device");
769*92022041SSam Saccone 			break;
770*92022041SSam Saccone 		case NL80211_IFTYPE_OCB:
771*92022041SSam Saccone 			printf("OCB");
772*92022041SSam Saccone 			break;
773*92022041SSam Saccone 		case NL80211_IFTYPE_NAN:
774*92022041SSam Saccone 			printf("NAN");
775*92022041SSam Saccone 			break;
776*92022041SSam Saccone 		default:
777*92022041SSam Saccone 			printf("unknown (%d)",
778*92022041SSam Saccone 			       nla_get_u32(attrs[NL80211_ATTR_IFTYPE]));
779*92022041SSam Saccone 			break;
780*92022041SSam Saccone 		}
781*92022041SSam Saccone 	}
782*92022041SSam Saccone 
783*92022041SSam Saccone 	if (attrs[NL80211_ATTR_MESH_ID]) {
784*92022041SSam Saccone 		printf(" meshid ");
785*92022041SSam Saccone 		print_ssid_escaped(nla_len(attrs[NL80211_ATTR_MESH_ID]),
786*92022041SSam Saccone 				   nla_data(attrs[NL80211_ATTR_MESH_ID]));
787*92022041SSam Saccone 	}
788*92022041SSam Saccone 
789*92022041SSam Saccone 	if (attrs[NL80211_ATTR_4ADDR]) {
790*92022041SSam Saccone 		printf(" use 4addr %d", nla_get_u8(attrs[NL80211_ATTR_4ADDR]));
791*92022041SSam Saccone 	}
792*92022041SSam Saccone 
793*92022041SSam Saccone 	printf("\n");
794*92022041SSam Saccone }
795*92022041SSam Saccone 
parse_sta_opmode_changed(struct nlattr ** attrs)796*92022041SSam Saccone static void parse_sta_opmode_changed(struct nlattr **attrs)
797*92022041SSam Saccone {
798*92022041SSam Saccone 	char macbuf[ETH_ALEN*3];
799*92022041SSam Saccone 
800*92022041SSam Saccone 	printf("sta opmode changed");
801*92022041SSam Saccone 
802*92022041SSam Saccone 	if (attrs[NL80211_ATTR_MAC]) {
803*92022041SSam Saccone 		mac_addr_n2a(macbuf, nla_data(attrs[NL80211_ATTR_MAC]));
804*92022041SSam Saccone 		printf(" %s", macbuf);
805*92022041SSam Saccone 	}
806*92022041SSam Saccone 
807*92022041SSam Saccone 	if (attrs[NL80211_ATTR_SMPS_MODE])
808*92022041SSam Saccone 		printf(" smps mode %d", nla_get_u8(attrs[NL80211_ATTR_SMPS_MODE]));
809*92022041SSam Saccone 
810*92022041SSam Saccone 	if (attrs[NL80211_ATTR_CHANNEL_WIDTH])
811*92022041SSam Saccone 		printf(" chan width %d", nla_get_u8(attrs[NL80211_ATTR_CHANNEL_WIDTH]));
812*92022041SSam Saccone 
813*92022041SSam Saccone 	if (attrs[NL80211_ATTR_NSS])
814*92022041SSam Saccone 		printf(" nss %d", nla_get_u8(attrs[NL80211_ATTR_NSS]));
815*92022041SSam Saccone 
816*92022041SSam Saccone 	printf("\n");
817*92022041SSam Saccone }
818*92022041SSam Saccone 
parse_ch_switch_notify(struct nlattr ** attrs,int command)819*92022041SSam Saccone static void parse_ch_switch_notify(struct nlattr **attrs, int command)
820*92022041SSam Saccone {
821*92022041SSam Saccone 	switch (command) {
822*92022041SSam Saccone 	case NL80211_CMD_CH_SWITCH_STARTED_NOTIFY:
823*92022041SSam Saccone 		printf("channel switch started");
824*92022041SSam Saccone 		break;
825*92022041SSam Saccone 	case NL80211_CMD_CH_SWITCH_NOTIFY:
826*92022041SSam Saccone 		printf("channel switch");
827*92022041SSam Saccone 		break;
828*92022041SSam Saccone 	default:
829*92022041SSam Saccone 		printf("unknown channel switch command (%i) received\n", command);
830*92022041SSam Saccone 		return;
831*92022041SSam Saccone 	}
832*92022041SSam Saccone 
833*92022041SSam Saccone 	if (attrs[NL80211_ATTR_CH_SWITCH_COUNT])
834*92022041SSam Saccone 		printf(" (count=%d)", nla_get_u32(attrs[NL80211_ATTR_CH_SWITCH_COUNT]));
835*92022041SSam Saccone 
836*92022041SSam Saccone 	if (attrs[NL80211_ATTR_WIPHY_FREQ])
837*92022041SSam Saccone 		printf(" freq=%d", nla_get_u32(attrs[NL80211_ATTR_WIPHY_FREQ]));
838*92022041SSam Saccone 
839*92022041SSam Saccone 	if (attrs[NL80211_ATTR_CHANNEL_WIDTH]) {
840*92022041SSam Saccone 		printf(" width=");
841*92022041SSam Saccone 		switch(nla_get_u32(attrs[NL80211_ATTR_CHANNEL_WIDTH])) {
842*92022041SSam Saccone 		case NL80211_CHAN_WIDTH_20_NOHT:
843*92022041SSam Saccone 		case NL80211_CHAN_WIDTH_20:
844*92022041SSam Saccone 			printf("\"20 MHz\"");
845*92022041SSam Saccone 			break;
846*92022041SSam Saccone 		case NL80211_CHAN_WIDTH_40:
847*92022041SSam Saccone 			printf("\"40 MHz\"");
848*92022041SSam Saccone 			break;
849*92022041SSam Saccone 		case NL80211_CHAN_WIDTH_80:
850*92022041SSam Saccone 			printf("\"80 MHz\"");
851*92022041SSam Saccone 			break;
852*92022041SSam Saccone 		case NL80211_CHAN_WIDTH_80P80:
853*92022041SSam Saccone 			printf("\"80+80 MHz\"");
854*92022041SSam Saccone 			break;
855*92022041SSam Saccone 		case NL80211_CHAN_WIDTH_160:
856*92022041SSam Saccone 			printf("\"160 MHz\"");
857*92022041SSam Saccone 			break;
858*92022041SSam Saccone 		case NL80211_CHAN_WIDTH_5:
859*92022041SSam Saccone 			printf("\"5 MHz\"");
860*92022041SSam Saccone 			break;
861*92022041SSam Saccone 		case NL80211_CHAN_WIDTH_10:
862*92022041SSam Saccone 			printf("\"10 MHz\"");
863*92022041SSam Saccone 			break;
864*92022041SSam Saccone 		default:
865*92022041SSam Saccone 			printf("\"unknown\"");
866*92022041SSam Saccone 		}
867*92022041SSam Saccone 	}
868*92022041SSam Saccone 
869*92022041SSam Saccone 	if (attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
870*92022041SSam Saccone 		printf(" type=");
871*92022041SSam Saccone 		switch(nla_get_u32(attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
872*92022041SSam Saccone 		case NL80211_CHAN_NO_HT:
873*92022041SSam Saccone 			printf("\"No HT\"");
874*92022041SSam Saccone 			break;
875*92022041SSam Saccone 		case NL80211_CHAN_HT20:
876*92022041SSam Saccone 			printf("\"HT20\"");
877*92022041SSam Saccone 			break;
878*92022041SSam Saccone 		case NL80211_CHAN_HT40MINUS:
879*92022041SSam Saccone 			printf("\"HT40-\"");
880*92022041SSam Saccone 			break;
881*92022041SSam Saccone 		case NL80211_CHAN_HT40PLUS:
882*92022041SSam Saccone 			printf("\"HT40+\"");
883*92022041SSam Saccone 			break;
884*92022041SSam Saccone 		}
885*92022041SSam Saccone 	}
886*92022041SSam Saccone 
887*92022041SSam Saccone 	if (attrs[NL80211_ATTR_CENTER_FREQ1])
888*92022041SSam Saccone 		printf(" freq1=%d", nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ1]));
889*92022041SSam Saccone 
890*92022041SSam Saccone 	if (attrs[NL80211_ATTR_CENTER_FREQ2])
891*92022041SSam Saccone 		printf(" freq2=%d", nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ2]));
892*92022041SSam Saccone 
893*92022041SSam Saccone 	printf("\n");
894*92022041SSam Saccone }
895*92022041SSam Saccone 
parse_assoc_comeback(struct nlattr ** attrs,int command)896*92022041SSam Saccone static void parse_assoc_comeback(struct nlattr **attrs, int command)
897*92022041SSam Saccone {
898*92022041SSam Saccone 	__u32 timeout = 0;
899*92022041SSam Saccone 	char macbuf[6 * 3] = "<unset>";
900*92022041SSam Saccone 
901*92022041SSam Saccone 	if (attrs[NL80211_ATTR_MAC])
902*92022041SSam Saccone 		mac_addr_n2a(macbuf, nla_data(attrs[NL80211_ATTR_MAC]));
903*92022041SSam Saccone 
904*92022041SSam Saccone 	if (attrs[NL80211_ATTR_TIMEOUT])
905*92022041SSam Saccone 		timeout = nla_get_u32(attrs[NL80211_ATTR_TIMEOUT]);
906*92022041SSam Saccone 
907*92022041SSam Saccone 	printf("assoc comeback bssid %s timeout %d\n",
908*92022041SSam Saccone 	       macbuf, timeout);
909*92022041SSam Saccone }
910*92022041SSam Saccone 
print_event(struct nl_msg * msg,void * arg)911*92022041SSam Saccone static int print_event(struct nl_msg *msg, void *arg)
912*92022041SSam Saccone {
913*92022041SSam Saccone 	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
914*92022041SSam Saccone 	struct nlattr *tb[NL80211_ATTR_MAX + 1], *nst;
915*92022041SSam Saccone 	struct print_event_args *args = arg;
916*92022041SSam Saccone 	char ifname[100];
917*92022041SSam Saccone 	char macbuf[6*3];
918*92022041SSam Saccone 	__u8 reg_type;
919*92022041SSam Saccone 	struct ieee80211_beacon_channel chan_before_beacon,  chan_after_beacon;
920*92022041SSam Saccone 	__u32 wiphy_idx = 0;
921*92022041SSam Saccone 	int rem_nst;
922*92022041SSam Saccone 	__u16 status;
923*92022041SSam Saccone 
924*92022041SSam Saccone 	if (args->time || args->reltime || args->ctime) {
925*92022041SSam Saccone 		unsigned long long usecs, previous;
926*92022041SSam Saccone 
927*92022041SSam Saccone 		previous = 1000000ULL * args->ts.tv_sec + args->ts.tv_usec;
928*92022041SSam Saccone 		gettimeofday(&args->ts, NULL);
929*92022041SSam Saccone 		usecs = 1000000ULL * args->ts.tv_sec + args->ts.tv_usec;
930*92022041SSam Saccone 
931*92022041SSam Saccone 		if (args->reltime) {
932*92022041SSam Saccone 			if (!args->have_ts) {
933*92022041SSam Saccone 				usecs = 0;
934*92022041SSam Saccone 				args->have_ts = true;
935*92022041SSam Saccone 			} else
936*92022041SSam Saccone 				usecs -= previous;
937*92022041SSam Saccone 		}
938*92022041SSam Saccone 
939*92022041SSam Saccone 		if (args->ctime) {
940*92022041SSam Saccone 			struct tm *tm = localtime(&args->ts.tv_sec);
941*92022041SSam Saccone 			char buf[255];
942*92022041SSam Saccone 
943*92022041SSam Saccone 			memset(buf, 0, 255);
944*92022041SSam Saccone 			strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm);
945*92022041SSam Saccone 			printf("[%s.%06lu]: ", buf, args->ts.tv_usec);
946*92022041SSam Saccone 		} else {
947*92022041SSam Saccone 			printf("%llu.%06llu: ", usecs/1000000, usecs % 1000000);
948*92022041SSam Saccone 		}
949*92022041SSam Saccone 	}
950*92022041SSam Saccone 
951*92022041SSam Saccone 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
952*92022041SSam Saccone 		  genlmsg_attrlen(gnlh, 0), NULL);
953*92022041SSam Saccone 
954*92022041SSam Saccone 	if (tb[NL80211_ATTR_IFINDEX] && tb[NL80211_ATTR_WIPHY]) {
955*92022041SSam Saccone 		/* if_indextoname may fails on delete interface/wiphy event */
956*92022041SSam Saccone 		if (if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname))
957*92022041SSam Saccone 			printf("%s (phy #%d): ", ifname, nla_get_u32(tb[NL80211_ATTR_WIPHY]));
958*92022041SSam Saccone 		else
959*92022041SSam Saccone 			printf("phy #%d: ", nla_get_u32(tb[NL80211_ATTR_WIPHY]));
960*92022041SSam Saccone 	} else if (tb[NL80211_ATTR_WDEV] && tb[NL80211_ATTR_WIPHY]) {
961*92022041SSam Saccone 		printf("wdev 0x%llx (phy #%d): ",
962*92022041SSam Saccone 			(unsigned long long)nla_get_u64(tb[NL80211_ATTR_WDEV]),
963*92022041SSam Saccone 			nla_get_u32(tb[NL80211_ATTR_WIPHY]));
964*92022041SSam Saccone 	} else if (tb[NL80211_ATTR_IFINDEX]) {
965*92022041SSam Saccone 		if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
966*92022041SSam Saccone 		printf("%s: ", ifname);
967*92022041SSam Saccone 	} else if (tb[NL80211_ATTR_WDEV]) {
968*92022041SSam Saccone 		printf("wdev 0x%llx: ", (unsigned long long)nla_get_u64(tb[NL80211_ATTR_WDEV]));
969*92022041SSam Saccone 	} else if (tb[NL80211_ATTR_WIPHY]) {
970*92022041SSam Saccone 		printf("phy #%d: ", nla_get_u32(tb[NL80211_ATTR_WIPHY]));
971*92022041SSam Saccone 	}
972*92022041SSam Saccone 
973*92022041SSam Saccone 	switch (gnlh->cmd) {
974*92022041SSam Saccone 	case NL80211_CMD_NEW_WIPHY:
975*92022041SSam Saccone 		printf("renamed to %s\n", nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]));
976*92022041SSam Saccone 		break;
977*92022041SSam Saccone 	case NL80211_CMD_TRIGGER_SCAN:
978*92022041SSam Saccone 		printf("scan started\n");
979*92022041SSam Saccone 		break;
980*92022041SSam Saccone 	case NL80211_CMD_NEW_SCAN_RESULTS:
981*92022041SSam Saccone 		printf("scan finished:");
982*92022041SSam Saccone 		/* fall through */
983*92022041SSam Saccone 	case NL80211_CMD_SCAN_ABORTED:
984*92022041SSam Saccone 		if (gnlh->cmd == NL80211_CMD_SCAN_ABORTED)
985*92022041SSam Saccone 			printf("scan aborted:");
986*92022041SSam Saccone 		if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
987*92022041SSam Saccone 			nla_for_each_nested(nst, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem_nst)
988*92022041SSam Saccone 				printf(" %d", nla_get_u32(nst));
989*92022041SSam Saccone 			printf(",");
990*92022041SSam Saccone 		}
991*92022041SSam Saccone 		if (tb[NL80211_ATTR_SCAN_SSIDS]) {
992*92022041SSam Saccone 			nla_for_each_nested(nst, tb[NL80211_ATTR_SCAN_SSIDS], rem_nst) {
993*92022041SSam Saccone 				printf(" \"");
994*92022041SSam Saccone 				print_ssid_escaped(nla_len(nst), nla_data(nst));
995*92022041SSam Saccone 				printf("\"");
996*92022041SSam Saccone 			}
997*92022041SSam Saccone 		}
998*92022041SSam Saccone 		printf("\n");
999*92022041SSam Saccone 		break;
1000*92022041SSam Saccone 	case NL80211_CMD_START_SCHED_SCAN:
1001*92022041SSam Saccone 		printf("scheduled scan started\n");
1002*92022041SSam Saccone 		break;
1003*92022041SSam Saccone 	case NL80211_CMD_SCHED_SCAN_STOPPED:
1004*92022041SSam Saccone 		printf("sched scan stopped\n");
1005*92022041SSam Saccone 		break;
1006*92022041SSam Saccone 	case NL80211_CMD_SCHED_SCAN_RESULTS:
1007*92022041SSam Saccone 		printf("got scheduled scan results\n");
1008*92022041SSam Saccone 		break;
1009*92022041SSam Saccone 	case NL80211_CMD_WIPHY_REG_CHANGE:
1010*92022041SSam Saccone 	case NL80211_CMD_REG_CHANGE:
1011*92022041SSam Saccone 		if (gnlh->cmd == NL80211_CMD_WIPHY_REG_CHANGE)
1012*92022041SSam Saccone 			printf("regulatory domain change (phy): ");
1013*92022041SSam Saccone 		else
1014*92022041SSam Saccone 			printf("regulatory domain change: ");
1015*92022041SSam Saccone 
1016*92022041SSam Saccone 		reg_type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]);
1017*92022041SSam Saccone 
1018*92022041SSam Saccone 		switch (reg_type) {
1019*92022041SSam Saccone 		case NL80211_REGDOM_TYPE_COUNTRY:
1020*92022041SSam Saccone 			printf("set to %s by %s request",
1021*92022041SSam Saccone 			       nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]),
1022*92022041SSam Saccone 			       reg_initiator_to_string(nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])));
1023*92022041SSam Saccone 			if (tb[NL80211_ATTR_WIPHY])
1024*92022041SSam Saccone 				printf(" on phy%d", nla_get_u32(tb[NL80211_ATTR_WIPHY]));
1025*92022041SSam Saccone 			break;
1026*92022041SSam Saccone 		case NL80211_REGDOM_TYPE_WORLD:
1027*92022041SSam Saccone 			printf("set to world roaming by %s request",
1028*92022041SSam Saccone 			       reg_initiator_to_string(nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])));
1029*92022041SSam Saccone 			break;
1030*92022041SSam Saccone 		case NL80211_REGDOM_TYPE_CUSTOM_WORLD:
1031*92022041SSam Saccone 			printf("custom world roaming rules in place on phy%d by %s request",
1032*92022041SSam Saccone 			       nla_get_u32(tb[NL80211_ATTR_WIPHY]),
1033*92022041SSam Saccone 			       reg_initiator_to_string(nla_get_u32(tb[NL80211_ATTR_REG_INITIATOR])));
1034*92022041SSam Saccone 			break;
1035*92022041SSam Saccone 		case NL80211_REGDOM_TYPE_INTERSECTION:
1036*92022041SSam Saccone 			printf("intersection used due to a request made by %s",
1037*92022041SSam Saccone 			       reg_initiator_to_string(nla_get_u32(tb[NL80211_ATTR_REG_INITIATOR])));
1038*92022041SSam Saccone 			if (tb[NL80211_ATTR_WIPHY])
1039*92022041SSam Saccone 				printf(" on phy%d", nla_get_u32(tb[NL80211_ATTR_WIPHY]));
1040*92022041SSam Saccone 			break;
1041*92022041SSam Saccone 		default:
1042*92022041SSam Saccone 			printf("unknown source (upgrade this utility)");
1043*92022041SSam Saccone 			break;
1044*92022041SSam Saccone 		}
1045*92022041SSam Saccone 
1046*92022041SSam Saccone 		printf("\n");
1047*92022041SSam Saccone 		break;
1048*92022041SSam Saccone 	case NL80211_CMD_REG_BEACON_HINT:
1049*92022041SSam Saccone 
1050*92022041SSam Saccone 		wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
1051*92022041SSam Saccone 
1052*92022041SSam Saccone 		memset(&chan_before_beacon, 0, sizeof(chan_before_beacon));
1053*92022041SSam Saccone 		memset(&chan_after_beacon, 0, sizeof(chan_after_beacon));
1054*92022041SSam Saccone 
1055*92022041SSam Saccone 		if (parse_beacon_hint_chan(tb[NL80211_ATTR_FREQ_BEFORE],
1056*92022041SSam Saccone 					   &chan_before_beacon))
1057*92022041SSam Saccone 			break;
1058*92022041SSam Saccone 		if (parse_beacon_hint_chan(tb[NL80211_ATTR_FREQ_AFTER],
1059*92022041SSam Saccone 					   &chan_after_beacon))
1060*92022041SSam Saccone 			break;
1061*92022041SSam Saccone 
1062*92022041SSam Saccone 		if (chan_before_beacon.center_freq != chan_after_beacon.center_freq)
1063*92022041SSam Saccone 			break;
1064*92022041SSam Saccone 
1065*92022041SSam Saccone 		/* A beacon hint is sent _only_ if something _did_ change */
1066*92022041SSam Saccone 		printf("beacon hint:\n");
1067*92022041SSam Saccone 
1068*92022041SSam Saccone 		printf("phy%d %d MHz [%d]:\n",
1069*92022041SSam Saccone 		       wiphy_idx,
1070*92022041SSam Saccone 		       chan_before_beacon.center_freq,
1071*92022041SSam Saccone 		       ieee80211_frequency_to_channel(chan_before_beacon.center_freq));
1072*92022041SSam Saccone 
1073*92022041SSam Saccone 		if (chan_before_beacon.no_ir && !chan_after_beacon.no_ir) {
1074*92022041SSam Saccone 			if (chan_before_beacon.no_ibss && !chan_after_beacon.no_ibss)
1075*92022041SSam Saccone 				printf("\to Initiating radiation enabled\n");
1076*92022041SSam Saccone 			else
1077*92022041SSam Saccone 				printf("\to active scan enabled\n");
1078*92022041SSam Saccone 		} else if (chan_before_beacon.no_ibss && !chan_after_beacon.no_ibss) {
1079*92022041SSam Saccone 			printf("\to ibss enabled\n");
1080*92022041SSam Saccone 		}
1081*92022041SSam Saccone 
1082*92022041SSam Saccone 		break;
1083*92022041SSam Saccone 	case NL80211_CMD_NEW_STATION:
1084*92022041SSam Saccone 		mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1085*92022041SSam Saccone 		printf("new station %s\n", macbuf);
1086*92022041SSam Saccone 		break;
1087*92022041SSam Saccone 	case NL80211_CMD_DEL_STATION:
1088*92022041SSam Saccone 		mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1089*92022041SSam Saccone 		printf("del station %s\n", macbuf);
1090*92022041SSam Saccone 		break;
1091*92022041SSam Saccone 	case NL80211_CMD_JOIN_IBSS:
1092*92022041SSam Saccone 		mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1093*92022041SSam Saccone 		printf("IBSS %s joined\n", macbuf);
1094*92022041SSam Saccone 		break;
1095*92022041SSam Saccone 	case NL80211_CMD_AUTHENTICATE:
1096*92022041SSam Saccone 		printf("auth");
1097*92022041SSam Saccone 		if (tb[NL80211_ATTR_FRAME])
1098*92022041SSam Saccone 			print_frame(args, tb[NL80211_ATTR_FRAME]);
1099*92022041SSam Saccone 		else if (tb[NL80211_ATTR_TIMED_OUT])
1100*92022041SSam Saccone 			printf(": timed out");
1101*92022041SSam Saccone 		else
1102*92022041SSam Saccone 			printf(": unknown event");
1103*92022041SSam Saccone 		printf("\n");
1104*92022041SSam Saccone 		break;
1105*92022041SSam Saccone 	case NL80211_CMD_ASSOCIATE:
1106*92022041SSam Saccone 		printf("assoc");
1107*92022041SSam Saccone 		if (tb[NL80211_ATTR_FRAME])
1108*92022041SSam Saccone 			print_frame(args, tb[NL80211_ATTR_FRAME]);
1109*92022041SSam Saccone 		else if (tb[NL80211_ATTR_TIMED_OUT])
1110*92022041SSam Saccone 			printf(": timed out");
1111*92022041SSam Saccone 		else
1112*92022041SSam Saccone 			printf(": unknown event");
1113*92022041SSam Saccone 		printf("\n");
1114*92022041SSam Saccone 		break;
1115*92022041SSam Saccone 	case NL80211_CMD_DEAUTHENTICATE:
1116*92022041SSam Saccone 		printf("deauth");
1117*92022041SSam Saccone 		print_frame(args, tb[NL80211_ATTR_FRAME]);
1118*92022041SSam Saccone 		printf("\n");
1119*92022041SSam Saccone 		break;
1120*92022041SSam Saccone 	case NL80211_CMD_DISASSOCIATE:
1121*92022041SSam Saccone 		printf("disassoc");
1122*92022041SSam Saccone 		print_frame(args, tb[NL80211_ATTR_FRAME]);
1123*92022041SSam Saccone 		printf("\n");
1124*92022041SSam Saccone 		break;
1125*92022041SSam Saccone 	case NL80211_CMD_UNPROT_DEAUTHENTICATE:
1126*92022041SSam Saccone 		printf("unprotected deauth");
1127*92022041SSam Saccone 		print_frame(args, tb[NL80211_ATTR_FRAME]);
1128*92022041SSam Saccone 		printf("\n");
1129*92022041SSam Saccone 		break;
1130*92022041SSam Saccone 	case NL80211_CMD_UNPROT_DISASSOCIATE:
1131*92022041SSam Saccone 		printf("unprotected disassoc");
1132*92022041SSam Saccone 		print_frame(args, tb[NL80211_ATTR_FRAME]);
1133*92022041SSam Saccone 		printf("\n");
1134*92022041SSam Saccone 		break;
1135*92022041SSam Saccone 	case NL80211_CMD_CONNECT:
1136*92022041SSam Saccone 		status = 0;
1137*92022041SSam Saccone 		if (tb[NL80211_ATTR_TIMED_OUT])
1138*92022041SSam Saccone 			printf("timed out");
1139*92022041SSam Saccone 		else if (!tb[NL80211_ATTR_STATUS_CODE])
1140*92022041SSam Saccone 			printf("unknown connect status");
1141*92022041SSam Saccone 		else if (nla_get_u16(tb[NL80211_ATTR_STATUS_CODE]) == 0)
1142*92022041SSam Saccone 			printf("connected");
1143*92022041SSam Saccone 		else {
1144*92022041SSam Saccone 			status = nla_get_u16(tb[NL80211_ATTR_STATUS_CODE]);
1145*92022041SSam Saccone 			printf("failed to connect");
1146*92022041SSam Saccone 		}
1147*92022041SSam Saccone 		if (tb[NL80211_ATTR_MAC]) {
1148*92022041SSam Saccone 			mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1149*92022041SSam Saccone 			printf(" to %s", macbuf);
1150*92022041SSam Saccone 		}
1151*92022041SSam Saccone 		if (status)
1152*92022041SSam Saccone 			printf(", status: %d: %s", status, get_status_str(status));
1153*92022041SSam Saccone 		printf("\n");
1154*92022041SSam Saccone 		break;
1155*92022041SSam Saccone 	case NL80211_CMD_ROAM:
1156*92022041SSam Saccone 		printf("roamed");
1157*92022041SSam Saccone 		if (tb[NL80211_ATTR_MAC]) {
1158*92022041SSam Saccone 			mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1159*92022041SSam Saccone 			printf(" to %s", macbuf);
1160*92022041SSam Saccone 		}
1161*92022041SSam Saccone 		printf("\n");
1162*92022041SSam Saccone 		break;
1163*92022041SSam Saccone 	case NL80211_CMD_DISCONNECT:
1164*92022041SSam Saccone 		printf("disconnected");
1165*92022041SSam Saccone 		if (tb[NL80211_ATTR_DISCONNECTED_BY_AP])
1166*92022041SSam Saccone 			printf(" (by AP)");
1167*92022041SSam Saccone 		else
1168*92022041SSam Saccone 			printf(" (local request)");
1169*92022041SSam Saccone 		if (tb[NL80211_ATTR_REASON_CODE])
1170*92022041SSam Saccone 			printf(" reason: %d: %s", nla_get_u16(tb[NL80211_ATTR_REASON_CODE]),
1171*92022041SSam Saccone 				get_reason_str(nla_get_u16(tb[NL80211_ATTR_REASON_CODE])));
1172*92022041SSam Saccone 		printf("\n");
1173*92022041SSam Saccone 		break;
1174*92022041SSam Saccone 	case NL80211_CMD_REMAIN_ON_CHANNEL:
1175*92022041SSam Saccone 		printf("remain on freq %d (%dms, cookie %llx)\n",
1176*92022041SSam Saccone 			nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]),
1177*92022041SSam Saccone 			nla_get_u32(tb[NL80211_ATTR_DURATION]),
1178*92022041SSam Saccone 			(unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE]));
1179*92022041SSam Saccone 		break;
1180*92022041SSam Saccone 	case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL:
1181*92022041SSam Saccone 		printf("done with remain on freq %d (cookie %llx)\n",
1182*92022041SSam Saccone 			nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]),
1183*92022041SSam Saccone 			(unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE]));
1184*92022041SSam Saccone 		break;
1185*92022041SSam Saccone 	case NL80211_CMD_FRAME_WAIT_CANCEL:
1186*92022041SSam Saccone 		printf("frame wait cancel on freq %d (cookie %llx)\n",
1187*92022041SSam Saccone 			nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]),
1188*92022041SSam Saccone 			(unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE]));
1189*92022041SSam Saccone 		break;
1190*92022041SSam Saccone 	case NL80211_CMD_NOTIFY_CQM:
1191*92022041SSam Saccone 		parse_cqm_event(tb);
1192*92022041SSam Saccone 		break;
1193*92022041SSam Saccone 	case NL80211_CMD_MICHAEL_MIC_FAILURE:
1194*92022041SSam Saccone 		parse_mic_failure(tb);
1195*92022041SSam Saccone 		break;
1196*92022041SSam Saccone 	case NL80211_CMD_FRAME_TX_STATUS:
1197*92022041SSam Saccone 		printf("mgmt TX status (cookie %llx): %s\n",
1198*92022041SSam Saccone 			(unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE]),
1199*92022041SSam Saccone 			tb[NL80211_ATTR_ACK] ? "acked" : "no ack");
1200*92022041SSam Saccone 		break;
1201*92022041SSam Saccone 	case NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS:
1202*92022041SSam Saccone 		printf("ctrl. port TX status (cookie %llx): %s\n",
1203*92022041SSam Saccone 			(unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE]),
1204*92022041SSam Saccone 			tb[NL80211_ATTR_ACK] ? "acked" : "no ack");
1205*92022041SSam Saccone 		break;
1206*92022041SSam Saccone 	case NL80211_CMD_PMKSA_CANDIDATE:
1207*92022041SSam Saccone 		printf("PMKSA candidate found\n");
1208*92022041SSam Saccone 		break;
1209*92022041SSam Saccone 	case NL80211_CMD_SET_WOWLAN:
1210*92022041SSam Saccone 		parse_wowlan_wake_event(tb);
1211*92022041SSam Saccone 		break;
1212*92022041SSam Saccone 	case NL80211_CMD_PROBE_CLIENT:
1213*92022041SSam Saccone 		if (tb[NL80211_ATTR_MAC])
1214*92022041SSam Saccone 			mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
1215*92022041SSam Saccone 		else
1216*92022041SSam Saccone 			strcpy(macbuf, "??");
1217*92022041SSam Saccone 		printf("probe client %s (cookie %llx): %s\n",
1218*92022041SSam Saccone 		       macbuf,
1219*92022041SSam Saccone 		       (unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE]),
1220*92022041SSam Saccone 		       tb[NL80211_ATTR_ACK] ? "acked" : "no ack");
1221*92022041SSam Saccone 		break;
1222*92022041SSam Saccone 	case NL80211_CMD_VENDOR:
1223*92022041SSam Saccone 		parse_vendor_event(tb, args->frame);
1224*92022041SSam Saccone 		break;
1225*92022041SSam Saccone 	case NL80211_CMD_RADAR_DETECT: {
1226*92022041SSam Saccone 		enum nl80211_radar_event event_type;
1227*92022041SSam Saccone 		uint32_t freq;
1228*92022041SSam Saccone 
1229*92022041SSam Saccone 		if (!tb[NL80211_ATTR_RADAR_EVENT] ||
1230*92022041SSam Saccone 		    !tb[NL80211_ATTR_WIPHY_FREQ]) {
1231*92022041SSam Saccone 			printf("BAD radar event\n");
1232*92022041SSam Saccone 			break;
1233*92022041SSam Saccone 		}
1234*92022041SSam Saccone 
1235*92022041SSam Saccone 		freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
1236*92022041SSam Saccone 		event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
1237*92022041SSam Saccone 
1238*92022041SSam Saccone 		switch (event_type) {
1239*92022041SSam Saccone 		case NL80211_RADAR_DETECTED:
1240*92022041SSam Saccone 			printf("%d MHz: radar detected\n", freq);
1241*92022041SSam Saccone 			break;
1242*92022041SSam Saccone 		case NL80211_RADAR_CAC_FINISHED:
1243*92022041SSam Saccone 			printf("%d MHz: CAC finished\n", freq);
1244*92022041SSam Saccone 			break;
1245*92022041SSam Saccone 		case NL80211_RADAR_CAC_ABORTED:
1246*92022041SSam Saccone 			printf("%d MHz: CAC was aborted\n", freq);
1247*92022041SSam Saccone 			break;
1248*92022041SSam Saccone 		case NL80211_RADAR_NOP_FINISHED:
1249*92022041SSam Saccone 			printf("%d MHz: NOP finished\n", freq);
1250*92022041SSam Saccone 			break;
1251*92022041SSam Saccone 		case NL80211_RADAR_PRE_CAC_EXPIRED:
1252*92022041SSam Saccone 			printf("%d MHz: PRE-CAC expired\n", freq);
1253*92022041SSam Saccone 			break;
1254*92022041SSam Saccone 		case NL80211_RADAR_CAC_STARTED:
1255*92022041SSam Saccone 			printf("%d MHz: CAC started\n", freq);
1256*92022041SSam Saccone 			break;
1257*92022041SSam Saccone 		default:
1258*92022041SSam Saccone 			printf("%d MHz: unknown radar event\n", freq);
1259*92022041SSam Saccone 		}
1260*92022041SSam Saccone 		}
1261*92022041SSam Saccone 		break;
1262*92022041SSam Saccone 	case NL80211_CMD_DEL_WIPHY:
1263*92022041SSam Saccone 		printf("delete wiphy\n");
1264*92022041SSam Saccone 		break;
1265*92022041SSam Saccone 	case NL80211_CMD_PEER_MEASUREMENT_RESULT:
1266*92022041SSam Saccone 		parse_pmsr_result(tb, args);
1267*92022041SSam Saccone 		break;
1268*92022041SSam Saccone 	case NL80211_CMD_PEER_MEASUREMENT_COMPLETE:
1269*92022041SSam Saccone 		printf("peer measurement complete\n");
1270*92022041SSam Saccone 		break;
1271*92022041SSam Saccone 	case NL80211_CMD_DEL_NAN_FUNCTION:
1272*92022041SSam Saccone 		parse_nan_term(tb);
1273*92022041SSam Saccone 		break;
1274*92022041SSam Saccone 	case NL80211_CMD_NAN_MATCH:
1275*92022041SSam Saccone 		parse_nan_match(tb);
1276*92022041SSam Saccone 		break;
1277*92022041SSam Saccone 	case NL80211_CMD_NEW_PEER_CANDIDATE:
1278*92022041SSam Saccone 		parse_new_peer_candidate(tb);
1279*92022041SSam Saccone 		break;
1280*92022041SSam Saccone 	case NL80211_CMD_NEW_INTERFACE:
1281*92022041SSam Saccone 	case NL80211_CMD_SET_INTERFACE:
1282*92022041SSam Saccone 	case NL80211_CMD_DEL_INTERFACE:
1283*92022041SSam Saccone 		parse_recv_interface(tb, gnlh->cmd);
1284*92022041SSam Saccone 		break;
1285*92022041SSam Saccone 	case NL80211_CMD_STA_OPMODE_CHANGED:
1286*92022041SSam Saccone 		parse_sta_opmode_changed(tb);
1287*92022041SSam Saccone 		break;
1288*92022041SSam Saccone 	case NL80211_CMD_STOP_AP:
1289*92022041SSam Saccone 		printf("stop ap\n");
1290*92022041SSam Saccone 		break;
1291*92022041SSam Saccone 	case NL80211_CMD_CH_SWITCH_STARTED_NOTIFY:
1292*92022041SSam Saccone 	case NL80211_CMD_CH_SWITCH_NOTIFY:
1293*92022041SSam Saccone 		parse_ch_switch_notify(tb, gnlh->cmd);
1294*92022041SSam Saccone 		break;
1295*92022041SSam Saccone 	case NL80211_CMD_ASSOC_COMEBACK: /* 147 */
1296*92022041SSam Saccone 		parse_assoc_comeback(tb, gnlh->cmd);
1297*92022041SSam Saccone 		break;
1298*92022041SSam Saccone 	default:
1299*92022041SSam Saccone 		printf("unknown event %d (%s)\n",
1300*92022041SSam Saccone 		       gnlh->cmd, command_name(gnlh->cmd));
1301*92022041SSam Saccone 		break;
1302*92022041SSam Saccone 	}
1303*92022041SSam Saccone 
1304*92022041SSam Saccone 	fflush(stdout);
1305*92022041SSam Saccone 	return NL_SKIP;
1306*92022041SSam Saccone }
1307*92022041SSam Saccone 
1308*92022041SSam Saccone struct wait_event {
1309*92022041SSam Saccone 	int n_cmds, n_prints;
1310*92022041SSam Saccone 	const __u32 *cmds;
1311*92022041SSam Saccone 	const __u32 *prints;
1312*92022041SSam Saccone 	__u32 cmd;
1313*92022041SSam Saccone 	struct print_event_args *pargs;
1314*92022041SSam Saccone };
1315*92022041SSam Saccone 
wait_event(struct nl_msg * msg,void * arg)1316*92022041SSam Saccone static int wait_event(struct nl_msg *msg, void *arg)
1317*92022041SSam Saccone {
1318*92022041SSam Saccone 	struct wait_event *wait = arg;
1319*92022041SSam Saccone 	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1320*92022041SSam Saccone 	int i;
1321*92022041SSam Saccone 
1322*92022041SSam Saccone 	if (wait->pargs) {
1323*92022041SSam Saccone 		for (i = 0; i < wait->n_prints; i++) {
1324*92022041SSam Saccone 			if (gnlh->cmd == wait->prints[i])
1325*92022041SSam Saccone 				print_event(msg, wait->pargs);
1326*92022041SSam Saccone 		}
1327*92022041SSam Saccone 	}
1328*92022041SSam Saccone 
1329*92022041SSam Saccone 	for (i = 0; i < wait->n_cmds; i++) {
1330*92022041SSam Saccone 		if (gnlh->cmd == wait->cmds[i])
1331*92022041SSam Saccone 			wait->cmd = gnlh->cmd;
1332*92022041SSam Saccone 	}
1333*92022041SSam Saccone 
1334*92022041SSam Saccone 	return NL_SKIP;
1335*92022041SSam Saccone }
1336*92022041SSam Saccone 
__prepare_listen_events(struct nl80211_state * state)1337*92022041SSam Saccone int __prepare_listen_events(struct nl80211_state *state)
1338*92022041SSam Saccone {
1339*92022041SSam Saccone 	int mcid, ret;
1340*92022041SSam Saccone 
1341*92022041SSam Saccone 	/* Configuration multicast group */
1342*92022041SSam Saccone 	mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "config");
1343*92022041SSam Saccone 	if (mcid < 0)
1344*92022041SSam Saccone 		return mcid;
1345*92022041SSam Saccone 
1346*92022041SSam Saccone 	ret = nl_socket_add_membership(state->nl_sock, mcid);
1347*92022041SSam Saccone 	if (ret)
1348*92022041SSam Saccone 		return ret;
1349*92022041SSam Saccone 
1350*92022041SSam Saccone 	/* Scan multicast group */
1351*92022041SSam Saccone 	mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "scan");
1352*92022041SSam Saccone 	if (mcid >= 0) {
1353*92022041SSam Saccone 		ret = nl_socket_add_membership(state->nl_sock, mcid);
1354*92022041SSam Saccone 		if (ret)
1355*92022041SSam Saccone 			return ret;
1356*92022041SSam Saccone 	}
1357*92022041SSam Saccone 
1358*92022041SSam Saccone 	/* Regulatory multicast group */
1359*92022041SSam Saccone 	mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "regulatory");
1360*92022041SSam Saccone 	if (mcid >= 0) {
1361*92022041SSam Saccone 		ret = nl_socket_add_membership(state->nl_sock, mcid);
1362*92022041SSam Saccone 		if (ret)
1363*92022041SSam Saccone 			return ret;
1364*92022041SSam Saccone 	}
1365*92022041SSam Saccone 
1366*92022041SSam Saccone 	/* MLME multicast group */
1367*92022041SSam Saccone 	mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "mlme");
1368*92022041SSam Saccone 	if (mcid >= 0) {
1369*92022041SSam Saccone 		ret = nl_socket_add_membership(state->nl_sock, mcid);
1370*92022041SSam Saccone 		if (ret)
1371*92022041SSam Saccone 			return ret;
1372*92022041SSam Saccone 	}
1373*92022041SSam Saccone 
1374*92022041SSam Saccone 	mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "vendor");
1375*92022041SSam Saccone 	if (mcid >= 0) {
1376*92022041SSam Saccone 		ret = nl_socket_add_membership(state->nl_sock, mcid);
1377*92022041SSam Saccone 		if (ret)
1378*92022041SSam Saccone 			return ret;
1379*92022041SSam Saccone 	}
1380*92022041SSam Saccone 
1381*92022041SSam Saccone 	mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "nan");
1382*92022041SSam Saccone 	if (mcid >= 0) {
1383*92022041SSam Saccone 		ret = nl_socket_add_membership(state->nl_sock, mcid);
1384*92022041SSam Saccone 		if (ret)
1385*92022041SSam Saccone 			return ret;
1386*92022041SSam Saccone 	}
1387*92022041SSam Saccone 
1388*92022041SSam Saccone 	return 0;
1389*92022041SSam Saccone }
1390*92022041SSam Saccone 
__do_listen_events(struct nl80211_state * state,const int n_waits,const __u32 * waits,const int n_prints,const __u32 * prints,struct print_event_args * args)1391*92022041SSam Saccone __u32 __do_listen_events(struct nl80211_state *state,
1392*92022041SSam Saccone 			 const int n_waits, const __u32 *waits,
1393*92022041SSam Saccone 			 const int n_prints, const __u32 *prints,
1394*92022041SSam Saccone 			 struct print_event_args *args)
1395*92022041SSam Saccone {
1396*92022041SSam Saccone 	struct nl_cb *cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
1397*92022041SSam Saccone 	struct wait_event wait_ev;
1398*92022041SSam Saccone 
1399*92022041SSam Saccone 	if (!cb) {
1400*92022041SSam Saccone 		fprintf(stderr, "failed to allocate netlink callbacks\n");
1401*92022041SSam Saccone 		return -ENOMEM;
1402*92022041SSam Saccone 	}
1403*92022041SSam Saccone 
1404*92022041SSam Saccone 	/* no sequence checking for multicast messages */
1405*92022041SSam Saccone 	nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
1406*92022041SSam Saccone 	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, NULL);
1407*92022041SSam Saccone 
1408*92022041SSam Saccone 	if (n_waits && waits) {
1409*92022041SSam Saccone 		wait_ev.cmds = waits;
1410*92022041SSam Saccone 		wait_ev.n_cmds = n_waits;
1411*92022041SSam Saccone 		wait_ev.prints = prints;
1412*92022041SSam Saccone 		wait_ev.n_prints = n_prints;
1413*92022041SSam Saccone 		wait_ev.pargs = args;
1414*92022041SSam Saccone 		register_handler(wait_event, &wait_ev);
1415*92022041SSam Saccone 	} else
1416*92022041SSam Saccone 		register_handler(print_event, args);
1417*92022041SSam Saccone 
1418*92022041SSam Saccone 	wait_ev.cmd = 0;
1419*92022041SSam Saccone 
1420*92022041SSam Saccone 	while (!wait_ev.cmd)
1421*92022041SSam Saccone 		nl_recvmsgs(state->nl_sock, cb);
1422*92022041SSam Saccone 
1423*92022041SSam Saccone 	nl_cb_put(cb);
1424*92022041SSam Saccone 
1425*92022041SSam Saccone 	return wait_ev.cmd;
1426*92022041SSam Saccone }
1427*92022041SSam Saccone 
listen_events(struct nl80211_state * state,const int n_waits,const __u32 * waits)1428*92022041SSam Saccone __u32 listen_events(struct nl80211_state *state,
1429*92022041SSam Saccone 		    const int n_waits, const __u32 *waits)
1430*92022041SSam Saccone {
1431*92022041SSam Saccone 	int ret;
1432*92022041SSam Saccone 
1433*92022041SSam Saccone 	ret = __prepare_listen_events(state);
1434*92022041SSam Saccone 	if (ret)
1435*92022041SSam Saccone 		return ret;
1436*92022041SSam Saccone 
1437*92022041SSam Saccone 	return __do_listen_events(state, n_waits, waits, 0, NULL, NULL);
1438*92022041SSam Saccone }
1439*92022041SSam Saccone 
print_events(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)1440*92022041SSam Saccone static int print_events(struct nl80211_state *state,
1441*92022041SSam Saccone 			struct nl_msg *msg,
1442*92022041SSam Saccone 			int argc, char **argv,
1443*92022041SSam Saccone 			enum id_input id)
1444*92022041SSam Saccone {
1445*92022041SSam Saccone 	struct print_event_args args;
1446*92022041SSam Saccone 	int num_time_formats = 0;
1447*92022041SSam Saccone 	int ret;
1448*92022041SSam Saccone 
1449*92022041SSam Saccone 	memset(&args, 0, sizeof(args));
1450*92022041SSam Saccone 
1451*92022041SSam Saccone 	argc--;
1452*92022041SSam Saccone 	argv++;
1453*92022041SSam Saccone 
1454*92022041SSam Saccone 	while (argc > 0) {
1455*92022041SSam Saccone 		if (strcmp(argv[0], "-f") == 0)
1456*92022041SSam Saccone 			args.frame = true;
1457*92022041SSam Saccone 		else if (strcmp(argv[0], "-t") == 0) {
1458*92022041SSam Saccone 			num_time_formats++;
1459*92022041SSam Saccone 			args.time = true;
1460*92022041SSam Saccone 		} else if (strcmp(argv[0], "-T") == 0) {
1461*92022041SSam Saccone 			num_time_formats++;
1462*92022041SSam Saccone 			args.ctime = true;
1463*92022041SSam Saccone 		} else if (strcmp(argv[0], "-r") == 0) {
1464*92022041SSam Saccone 			num_time_formats++;
1465*92022041SSam Saccone 			args.reltime = true;
1466*92022041SSam Saccone 		} else
1467*92022041SSam Saccone 			return 1;
1468*92022041SSam Saccone 		argc--;
1469*92022041SSam Saccone 		argv++;
1470*92022041SSam Saccone 	}
1471*92022041SSam Saccone 
1472*92022041SSam Saccone 	if (num_time_formats > 1)
1473*92022041SSam Saccone 		return 1;
1474*92022041SSam Saccone 
1475*92022041SSam Saccone 	if (argc)
1476*92022041SSam Saccone 		return 1;
1477*92022041SSam Saccone 
1478*92022041SSam Saccone 	ret = __prepare_listen_events(state);
1479*92022041SSam Saccone 	if (ret)
1480*92022041SSam Saccone 		return ret;
1481*92022041SSam Saccone 
1482*92022041SSam Saccone 	return __do_listen_events(state, 0, NULL, 0, NULL, &args);
1483*92022041SSam Saccone }
1484*92022041SSam Saccone TOPLEVEL(event, "[-t|-T|-r] [-f]", 0, 0, CIB_NONE, print_events,
1485*92022041SSam Saccone 	"Monitor events from the kernel.\n"
1486*92022041SSam Saccone 	"-t - print timestamp\n"
1487*92022041SSam Saccone 	"-T - print absolute, human-readable timestamp\n"
1488*92022041SSam Saccone 	"-r - print relative timestamp\n"
1489*92022041SSam Saccone 	"-f - print full frame for auth/assoc etc.");
1490