1 #include <stdint.h>
2 #include <stdbool.h>
3 #include <net/if.h>
4 #include <errno.h>
5 #include "iw.h"
6 
no_seq_check(struct nl_msg * msg,void * arg)7 static int no_seq_check(struct nl_msg *msg, void *arg)
8 {
9 	return NL_OK;
10 }
11 
12 struct ieee80211_beacon_channel {
13 	__u16 center_freq;
14 	bool no_ir;
15 	bool no_ibss;
16 };
17 
parse_beacon_hint_chan(struct nlattr * tb,struct ieee80211_beacon_channel * chan)18 static int parse_beacon_hint_chan(struct nlattr *tb,
19 				  struct ieee80211_beacon_channel *chan)
20 {
21 	struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
22 	static struct nla_policy beacon_freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
23 		[NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
24 		[NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG },
25 		[__NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
26 	};
27 
28 	if (nla_parse_nested(tb_freq,
29 			     NL80211_FREQUENCY_ATTR_MAX,
30 			     tb,
31 			     beacon_freq_policy))
32 		return -EINVAL;
33 
34 	chan->center_freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
35 
36 	if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR])
37 		chan->no_ir = true;
38 	if (tb_freq[__NL80211_FREQUENCY_ATTR_NO_IBSS])
39 		chan->no_ibss = true;
40 
41 	return 0;
42 }
43 
print_frame(struct print_event_args * args,struct nlattr * attr)44 static void print_frame(struct print_event_args *args, struct nlattr *attr)
45 {
46 	uint8_t *frame;
47 	size_t len;
48 	int i;
49 	char macbuf[6*3];
50 	uint16_t tmp;
51 
52 	if (!attr)
53 		printf(" [no frame]");
54 
55 	frame = nla_data(attr);
56 	len = nla_len(attr);
57 
58 	if (len < 26) {
59 		printf(" [invalid frame: ");
60 		goto print_frame;
61 	}
62 
63 	mac_addr_n2a(macbuf, frame + 10);
64 	printf(" %s -> ", macbuf);
65 	mac_addr_n2a(macbuf, frame + 4);
66 	printf("%s", macbuf);
67 
68 	switch (frame[0] & 0xfc) {
69 	case 0x10: /* assoc resp */
70 	case 0x30: /* reassoc resp */
71 		/* status */
72 		tmp = (frame[27] << 8) + frame[26];
73 		printf(" status: %d: %s", tmp, get_status_str(tmp));
74 		break;
75 	case 0x00: /* assoc req */
76 	case 0x20: /* reassoc req */
77 		break;
78 	case 0xb0: /* auth */
79 		/* status */
80 		tmp = (frame[29] << 8) + frame[28];
81 		printf(" status: %d: %s", tmp, get_status_str(tmp));
82 		break;
83 	case 0xa0: /* disassoc */
84 	case 0xc0: /* deauth */
85 		/* reason */
86 		tmp = (frame[25] << 8) + frame[24];
87 		printf(" reason %d: %s", tmp, get_reason_str(tmp));
88 		break;
89 	}
90 
91 	if (!args->frame)
92 		return;
93 
94 	printf(" [frame:");
95 
96  print_frame:
97 	for (i = 0; i < len; i++)
98 		printf(" %.02x", frame[i]);
99 	printf("]");
100 }
101 
parse_cqm_event(struct nlattr ** attrs)102 static void parse_cqm_event(struct nlattr **attrs)
103 {
104 	static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
105 		[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
106 		[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
107 		[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
108 	};
109 	struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
110 	struct nlattr *cqm_attr = attrs[NL80211_ATTR_CQM];
111 
112 	printf("CQM event: ");
113 
114 	if (!cqm_attr ||
115 	    nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, cqm_attr, cqm_policy)) {
116 		printf("missing data!\n");
117 		return;
118 	}
119 
120 	if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]) {
121 		enum nl80211_cqm_rssi_threshold_event rssi_event;
122 		bool found_one = false;
123 
124 		rssi_event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
125 
126 		switch (rssi_event) {
127 		case NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH:
128 			printf("RSSI went above threshold\n");
129 			found_one = true;
130 			break;
131 		case NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW:
132 			printf("RSSI went below threshold\n");
133 			found_one = true;
134 			break;
135 		case NL80211_CQM_RSSI_BEACON_LOSS_EVENT:
136 			printf("Beacon loss detected\n");
137 			found_one = true;
138 			break;
139 		}
140 
141 		if (!found_one)
142 			printf("Unknown event type: %i\n", rssi_event);
143 	} else if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) {
144 		if (attrs[NL80211_ATTR_MAC]) {
145 			uint32_t frames;
146 			char buf[3*6];
147 
148 			frames = nla_get_u32(cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]);
149 			mac_addr_n2a(buf, nla_data(attrs[NL80211_ATTR_MAC]));
150 			printf("peer %s didn't ACK %d packets\n", buf, frames);
151 		} else {
152 			printf("PKT-LOSS-EVENT did not have MAC attribute!\n");
153 		}
154 	} else if (cqm[NL80211_ATTR_CQM_BEACON_LOSS_EVENT]) {
155 		printf("beacon loss\n");
156 	} else {
157 		printf("unknown event\n");
158 	}
159 }
160 
key_type_str(enum nl80211_key_type key_type)161 static const char * key_type_str(enum nl80211_key_type key_type)
162 {
163 	static char buf[30];
164 	switch (key_type) {
165 	case NL80211_KEYTYPE_GROUP:
166 		return "Group";
167 	case NL80211_KEYTYPE_PAIRWISE:
168 		return "Pairwise";
169 	case NL80211_KEYTYPE_PEERKEY:
170 		return "PeerKey";
171 	default:
172 		snprintf(buf, sizeof(buf), "unknown(%d)", key_type);
173 		return buf;
174 	}
175 }
176 
parse_mic_failure(struct nlattr ** attrs)177 static void parse_mic_failure(struct nlattr **attrs)
178 {
179 	printf("Michael MIC failure event:");
180 
181 	if (attrs[NL80211_ATTR_MAC]) {
182 		char addr[3 * ETH_ALEN];
183 		mac_addr_n2a(addr, nla_data(attrs[NL80211_ATTR_MAC]));
184 		printf(" source MAC address %s", addr);
185 	}
186 
187 	if (attrs[NL80211_ATTR_KEY_SEQ] &&
188 	    nla_len(attrs[NL80211_ATTR_KEY_SEQ]) == 6) {
189 		unsigned char *seq = nla_data(attrs[NL80211_ATTR_KEY_SEQ]);
190 		printf(" seq=%02x%02x%02x%02x%02x%02x",
191 		       seq[0], seq[1], seq[2], seq[3], seq[4], seq[5]);
192 	}
193 	if (attrs[NL80211_ATTR_KEY_TYPE]) {
194 		enum nl80211_key_type key_type =
195 			nla_get_u32(attrs[NL80211_ATTR_KEY_TYPE]);
196 		printf(" Key Type %s", key_type_str(key_type));
197 	}
198 
199 	if (attrs[NL80211_ATTR_KEY_IDX]) {
200 		__u8 key_id = nla_get_u8(attrs[NL80211_ATTR_KEY_IDX]);
201 		printf(" Key Id %d", key_id);
202 	}
203 
204 	printf("\n");
205 }
206 
parse_wowlan_wake_event(struct nlattr ** attrs)207 static void parse_wowlan_wake_event(struct nlattr **attrs)
208 {
209 	struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG],
210 		*tb_match[NUM_NL80211_ATTR];
211 
212 	printf("WoWLAN wakeup\n");
213 	if (!attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) {
214 		printf("\twakeup not due to WoWLAN\n");
215 		return;
216 	}
217 
218 	nla_parse(tb, MAX_NL80211_WOWLAN_TRIG,
219 		  nla_data(attrs[NL80211_ATTR_WOWLAN_TRIGGERS]),
220 		  nla_len(attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), NULL);
221 
222 	if (tb[NL80211_WOWLAN_TRIG_DISCONNECT])
223 		printf("\t* was disconnected\n");
224 	if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT])
225 		printf("\t* magic packet received\n");
226 	if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN])
227 		printf("\t* pattern index: %u\n",
228 		       nla_get_u32(tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]));
229 	if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE])
230 		printf("\t* GTK rekey failure\n");
231 	if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST])
232 		printf("\t* EAP identity request\n");
233 	if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE])
234 		printf("\t* 4-way handshake\n");
235 	if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE])
236 		printf("\t* RF-kill released\n");
237 	if (tb[NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS]) {
238 		struct nlattr *match, *freq;
239 		int rem_nst, rem_nst2;
240 
241 		printf("\t* network detected\n");
242 		nla_for_each_nested(match,
243 				    tb[NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS],
244 				    rem_nst) {
245 			nla_parse(tb_match, NUM_NL80211_ATTR, nla_data(match),
246 				  nla_len(match),
247 				  NULL);
248 			printf("\t\tSSID: \"");
249 			print_ssid_escaped(nla_len(tb_match[NL80211_ATTR_SSID]),
250 					   nla_data(tb_match[NL80211_ATTR_SSID]));
251 			printf("\"");
252 			if (tb_match[NL80211_ATTR_SCAN_FREQUENCIES]) {
253 				printf(" freq(s):");
254 				nla_for_each_nested(freq,
255 						    tb_match[NL80211_ATTR_SCAN_FREQUENCIES],
256 						    rem_nst2)
257 					printf(" %d", nla_get_u32(freq));
258 			}
259 			printf("\n");
260 		}
261 	}
262 	if (tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211]) {
263 		uint8_t *d = nla_data(tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211]);
264 		int l = nla_len(tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211]);
265 		int i;
266 		printf("\t* packet (might be truncated): ");
267 		for (i = 0; i < l; i++) {
268 			if (i > 0)
269 				printf(":");
270 			printf("%.2x", d[i]);
271 		}
272 		printf("\n");
273 	}
274 	if (tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023]) {
275 		uint8_t *d = nla_data(tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023]);
276 		int l = nla_len(tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023]);
277 		int i;
278 		printf("\t* packet (might be truncated): ");
279 		for (i = 0; i < l; i++) {
280 			if (i > 0)
281 				printf(":");
282 			printf("%.2x", d[i]);
283 		}
284 		printf("\n");
285 	}
286 	if (tb[NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH])
287 		printf("\t* TCP connection wakeup received\n");
288 	if (tb[NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST])
289 		printf("\t* TCP connection lost\n");
290 	if (tb[NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS])
291 		printf("\t* TCP connection ran out of tokens\n");
292 }
293 
print_event(struct nl_msg * msg,void * arg)294 static int print_event(struct nl_msg *msg, void *arg)
295 {
296 	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
297 	struct nlattr *tb[NL80211_ATTR_MAX + 1], *nst;
298 	struct print_event_args *args = arg;
299 	char ifname[100];
300 	char macbuf[6*3];
301 	__u8 reg_type;
302 	struct ieee80211_beacon_channel chan_before_beacon,  chan_after_beacon;
303 	__u32 wiphy_idx = 0;
304 	int rem_nst;
305 	__u16 status;
306 
307 	if (args->time || args->reltime) {
308 		unsigned long long usecs, previous;
309 
310 		previous = 1000000ULL * args->ts.tv_sec + args->ts.tv_usec;
311 		gettimeofday(&args->ts, NULL);
312 		usecs = 1000000ULL * args->ts.tv_sec + args->ts.tv_usec;
313 		if (args->reltime) {
314 			if (!args->have_ts) {
315 				usecs = 0;
316 				args->have_ts = true;
317 			} else
318 				usecs -= previous;
319 		}
320 		printf("%llu.%06llu: ", usecs/1000000, usecs % 1000000);
321 	}
322 
323 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
324 		  genlmsg_attrlen(gnlh, 0), NULL);
325 
326 	if (tb[NL80211_ATTR_IFINDEX] && tb[NL80211_ATTR_WIPHY]) {
327 		if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
328 		printf("%s (phy #%d): ", ifname, nla_get_u32(tb[NL80211_ATTR_WIPHY]));
329 	} else if (tb[NL80211_ATTR_WDEV] && tb[NL80211_ATTR_WIPHY]) {
330 		printf("wdev 0x%llx (phy #%d): ",
331 			(unsigned long long)nla_get_u64(tb[NL80211_ATTR_WDEV]),
332 			nla_get_u32(tb[NL80211_ATTR_WIPHY]));
333 	} else if (tb[NL80211_ATTR_IFINDEX]) {
334 		if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
335 		printf("%s: ", ifname);
336 	} else if (tb[NL80211_ATTR_WDEV]) {
337 		printf("wdev 0x%llx: ", (unsigned long long)nla_get_u64(tb[NL80211_ATTR_WDEV]));
338 	} else if (tb[NL80211_ATTR_WIPHY]) {
339 		printf("phy #%d: ", nla_get_u32(tb[NL80211_ATTR_WIPHY]));
340 	}
341 
342 	switch (gnlh->cmd) {
343 	case NL80211_CMD_NEW_WIPHY:
344 		printf("renamed to %s\n", nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]));
345 		break;
346 	case NL80211_CMD_TRIGGER_SCAN:
347 		printf("scan started\n");
348 		break;
349 	case NL80211_CMD_NEW_SCAN_RESULTS:
350 		printf("scan finished:");
351 	case NL80211_CMD_SCAN_ABORTED:
352 		if (gnlh->cmd == NL80211_CMD_SCAN_ABORTED)
353 			printf("scan aborted:");
354 		if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
355 			nla_for_each_nested(nst, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem_nst)
356 				printf(" %d", nla_get_u32(nst));
357 			printf(",");
358 		}
359 		if (tb[NL80211_ATTR_SCAN_SSIDS]) {
360 			nla_for_each_nested(nst, tb[NL80211_ATTR_SCAN_SSIDS], rem_nst) {
361 				printf(" \"");
362 				print_ssid_escaped(nla_len(nst), nla_data(nst));
363 				printf("\"");
364 			}
365 		}
366 		printf("\n");
367 		break;
368 	case NL80211_CMD_START_SCHED_SCAN:
369 		printf("scheduled scan started\n");
370 		break;
371 	case NL80211_CMD_SCHED_SCAN_STOPPED:
372 		printf("sched scan stopped\n");
373 		break;
374 	case NL80211_CMD_SCHED_SCAN_RESULTS:
375 		printf("got scheduled scan results\n");
376 		break;
377 	case NL80211_CMD_REG_CHANGE:
378 		printf("regulatory domain change: ");
379 
380 		reg_type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]);
381 
382 		switch (reg_type) {
383 		case NL80211_REGDOM_TYPE_COUNTRY:
384 			printf("set to %s by %s request",
385 			       nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]),
386 			       reg_initiator_to_string(nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])));
387 			if (tb[NL80211_ATTR_WIPHY])
388 				printf(" on phy%d", nla_get_u32(tb[NL80211_ATTR_WIPHY]));
389 			break;
390 		case NL80211_REGDOM_TYPE_WORLD:
391 			printf("set to world roaming by %s request",
392 			       reg_initiator_to_string(nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])));
393 			break;
394 		case NL80211_REGDOM_TYPE_CUSTOM_WORLD:
395 			printf("custom world roaming rules in place on phy%d by %s request",
396 			       nla_get_u32(tb[NL80211_ATTR_WIPHY]),
397 			       reg_initiator_to_string(nla_get_u32(tb[NL80211_ATTR_REG_INITIATOR])));
398 			break;
399 		case NL80211_REGDOM_TYPE_INTERSECTION:
400 			printf("intersection used due to a request made by %s",
401 			       reg_initiator_to_string(nla_get_u32(tb[NL80211_ATTR_REG_INITIATOR])));
402 			if (tb[NL80211_ATTR_WIPHY])
403 				printf(" on phy%d", nla_get_u32(tb[NL80211_ATTR_WIPHY]));
404 			break;
405 		default:
406 			printf("unknown source (upgrade this utility)");
407 			break;
408 		}
409 
410 		printf("\n");
411 		break;
412 	case NL80211_CMD_REG_BEACON_HINT:
413 
414 		wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
415 
416 		memset(&chan_before_beacon, 0, sizeof(chan_before_beacon));
417 		memset(&chan_after_beacon, 0, sizeof(chan_after_beacon));
418 
419 		if (parse_beacon_hint_chan(tb[NL80211_ATTR_FREQ_BEFORE],
420 					   &chan_before_beacon))
421 			break;
422 		if (parse_beacon_hint_chan(tb[NL80211_ATTR_FREQ_AFTER],
423 					   &chan_after_beacon))
424 			break;
425 
426 		if (chan_before_beacon.center_freq != chan_after_beacon.center_freq)
427 			break;
428 
429 		/* A beacon hint is sent _only_ if something _did_ change */
430 		printf("beacon hint:\n");
431 
432 		printf("phy%d %d MHz [%d]:\n",
433 		       wiphy_idx,
434 		       chan_before_beacon.center_freq,
435 		       ieee80211_frequency_to_channel(chan_before_beacon.center_freq));
436 
437 		if (chan_before_beacon.no_ir && !chan_after_beacon.no_ir) {
438 			if (chan_before_beacon.no_ibss && !chan_after_beacon.no_ibss)
439 				printf("\to Initiating radiation enabled\n");
440 			else
441 				printf("\to active scan enabled\n");
442 		} else if (chan_before_beacon.no_ibss && !chan_after_beacon.no_ibss) {
443 			printf("\to ibss enabled\n");
444 		}
445 
446 		break;
447 	case NL80211_CMD_NEW_STATION:
448 		mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
449 		printf("new station %s\n", macbuf);
450 		break;
451 	case NL80211_CMD_DEL_STATION:
452 		mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
453 		printf("del station %s\n", macbuf);
454 		break;
455 	case NL80211_CMD_JOIN_IBSS:
456 		mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
457 		printf("IBSS %s joined\n", macbuf);
458 		break;
459 	case NL80211_CMD_AUTHENTICATE:
460 		printf("auth");
461 		if (tb[NL80211_ATTR_FRAME])
462 			print_frame(args, tb[NL80211_ATTR_FRAME]);
463 		else if (tb[NL80211_ATTR_TIMED_OUT])
464 			printf(": timed out");
465 		else
466 			printf(": unknown event");
467 		printf("\n");
468 		break;
469 	case NL80211_CMD_ASSOCIATE:
470 		printf("assoc");
471 		if (tb[NL80211_ATTR_FRAME])
472 			print_frame(args, tb[NL80211_ATTR_FRAME]);
473 		else if (tb[NL80211_ATTR_TIMED_OUT])
474 			printf(": timed out");
475 		else
476 			printf(": unknown event");
477 		printf("\n");
478 		break;
479 	case NL80211_CMD_DEAUTHENTICATE:
480 		printf("deauth");
481 		print_frame(args, tb[NL80211_ATTR_FRAME]);
482 		printf("\n");
483 		break;
484 	case NL80211_CMD_DISASSOCIATE:
485 		printf("disassoc");
486 		print_frame(args, tb[NL80211_ATTR_FRAME]);
487 		printf("\n");
488 		break;
489 	case NL80211_CMD_UNPROT_DEAUTHENTICATE:
490 		printf("unprotected deauth");
491 		print_frame(args, tb[NL80211_ATTR_FRAME]);
492 		printf("\n");
493 		break;
494 	case NL80211_CMD_UNPROT_DISASSOCIATE:
495 		printf("unprotected disassoc");
496 		print_frame(args, tb[NL80211_ATTR_FRAME]);
497 		printf("\n");
498 		break;
499 	case NL80211_CMD_CONNECT:
500 		status = 0;
501 		if (!tb[NL80211_ATTR_STATUS_CODE])
502 			printf("unknown connect status");
503 		else if (nla_get_u16(tb[NL80211_ATTR_STATUS_CODE]) == 0)
504 			printf("connected");
505 		else {
506 			status = nla_get_u16(tb[NL80211_ATTR_STATUS_CODE]);
507 			printf("failed to connect");
508 		}
509 		if (tb[NL80211_ATTR_MAC]) {
510 			mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
511 			printf(" to %s", macbuf);
512 		}
513 		if (status)
514 			printf(", status: %d: %s", status, get_status_str(status));
515 		printf("\n");
516 		break;
517 	case NL80211_CMD_ROAM:
518 		printf("roamed");
519 		if (tb[NL80211_ATTR_MAC]) {
520 			mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
521 			printf(" to %s", macbuf);
522 		}
523 		printf("\n");
524 		break;
525 	case NL80211_CMD_DISCONNECT:
526 		printf("disconnected");
527 		if (tb[NL80211_ATTR_DISCONNECTED_BY_AP])
528 			printf(" (by AP)");
529 		else
530 			printf(" (local request)");
531 		if (tb[NL80211_ATTR_REASON_CODE])
532 			printf(" reason: %d: %s", nla_get_u16(tb[NL80211_ATTR_REASON_CODE]),
533 				get_reason_str(nla_get_u16(tb[NL80211_ATTR_REASON_CODE])));
534 		printf("\n");
535 		break;
536 	case NL80211_CMD_REMAIN_ON_CHANNEL:
537 		printf("remain on freq %d (%dms, cookie %llx)\n",
538 			nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]),
539 			nla_get_u32(tb[NL80211_ATTR_DURATION]),
540 			(unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE]));
541 		break;
542 	case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL:
543 		printf("done with remain on freq %d (cookie %llx)\n",
544 			nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]),
545 			(unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE]));
546 		break;
547 	case NL80211_CMD_NOTIFY_CQM:
548 		parse_cqm_event(tb);
549 		break;
550 	case NL80211_CMD_MICHAEL_MIC_FAILURE:
551 		parse_mic_failure(tb);
552 		break;
553 	case NL80211_CMD_FRAME_TX_STATUS:
554 		printf("mgmt TX status (cookie %llx): %s\n",
555 			(unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE]),
556 			tb[NL80211_ATTR_ACK] ? "acked" : "no ack");
557 		break;
558 	case NL80211_CMD_PMKSA_CANDIDATE:
559 		printf("PMKSA candidate found\n");
560 		break;
561 	case NL80211_CMD_SET_WOWLAN:
562 		parse_wowlan_wake_event(tb);
563 		break;
564 	case NL80211_CMD_PROBE_CLIENT:
565 		if (tb[NL80211_ATTR_MAC])
566 			mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
567 		else
568 			strcpy(macbuf, "??");
569 		printf("probe client %s (cookie %llx): %s\n",
570 		       macbuf,
571 		       (unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE]),
572 		       tb[NL80211_ATTR_ACK] ? "acked" : "no ack");
573 		break;
574 	case NL80211_CMD_VENDOR:
575 		printf("vendor event %.6x:%d\n",
576 			nla_get_u32(tb[NL80211_ATTR_VENDOR_ID]),
577 			nla_get_u32(tb[NL80211_ATTR_VENDOR_SUBCMD]));
578 		if (args->frame && tb[NL80211_ATTR_VENDOR_DATA])
579 			iw_hexdump("vendor event",
580 				   nla_data(tb[NL80211_ATTR_VENDOR_DATA]),
581 				   nla_len(tb[NL80211_ATTR_VENDOR_DATA]));
582 		break;
583 	case NL80211_CMD_RADAR_DETECT:
584 		printf("radar event ");
585 		if (tb[NL80211_ATTR_RADAR_EVENT]) {
586 			switch (nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT])) {
587 				case NL80211_RADAR_DETECTED:
588 					printf("(radar detected)");
589 					break;
590 				case NL80211_RADAR_CAC_FINISHED:
591 					printf("(cac finished)");
592 					break;
593 				case NL80211_RADAR_CAC_ABORTED:
594 					printf("(cac aborted)");
595 					break;
596 				case NL80211_RADAR_NOP_FINISHED:
597 					printf("(nop finished)");
598 					break;
599 				default:
600 					printf("(unknown)");
601 					break;
602 			};
603 		} else {
604 			printf("(unknown)");
605 		}
606 		printf("\n");
607 		break;
608 	case NL80211_CMD_DEL_WIPHY:
609 		printf("delete wiphy\n");
610 		break;
611 	default:
612 		printf("unknown event %d (%s)\n",
613 		       gnlh->cmd, command_name(gnlh->cmd));
614 		break;
615 	}
616 
617 	fflush(stdout);
618 	return NL_SKIP;
619 }
620 
621 struct wait_event {
622 	int n_cmds;
623 	const __u32 *cmds;
624 	__u32 cmd;
625 	struct print_event_args *pargs;
626 };
627 
wait_event(struct nl_msg * msg,void * arg)628 static int wait_event(struct nl_msg *msg, void *arg)
629 {
630 	struct wait_event *wait = arg;
631 	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
632 	int i;
633 
634 	for (i = 0; i < wait->n_cmds; i++) {
635 		if (gnlh->cmd == wait->cmds[i]) {
636 			wait->cmd = gnlh->cmd;
637 			if (wait->pargs)
638 				print_event(msg, wait->pargs);
639 		}
640 	}
641 
642 	return NL_SKIP;
643 }
644 
__prepare_listen_events(struct nl80211_state * state)645 int __prepare_listen_events(struct nl80211_state *state)
646 {
647 	int mcid, ret;
648 
649 	/* Configuration multicast group */
650 	mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "config");
651 	if (mcid < 0)
652 		return mcid;
653 
654 	ret = nl_socket_add_membership(state->nl_sock, mcid);
655 	if (ret)
656 		return ret;
657 
658 	/* Scan multicast group */
659 	mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "scan");
660 	if (mcid >= 0) {
661 		ret = nl_socket_add_membership(state->nl_sock, mcid);
662 		if (ret)
663 			return ret;
664 	}
665 
666 	/* Regulatory multicast group */
667 	mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "regulatory");
668 	if (mcid >= 0) {
669 		ret = nl_socket_add_membership(state->nl_sock, mcid);
670 		if (ret)
671 			return ret;
672 	}
673 
674 	/* MLME multicast group */
675 	mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "mlme");
676 	if (mcid >= 0) {
677 		ret = nl_socket_add_membership(state->nl_sock, mcid);
678 		if (ret)
679 			return ret;
680 	}
681 
682 	mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "vendor");
683 	if (mcid >= 0) {
684 		ret = nl_socket_add_membership(state->nl_sock, mcid);
685 		if (ret)
686 			return ret;
687 	}
688 
689 	return 0;
690 }
691 
__do_listen_events(struct nl80211_state * state,const int n_waits,const __u32 * waits,struct print_event_args * args)692 __u32 __do_listen_events(struct nl80211_state *state,
693 			 const int n_waits, const __u32 *waits,
694 			 struct print_event_args *args)
695 {
696 	struct nl_cb *cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
697 	struct wait_event wait_ev;
698 
699 	if (!cb) {
700 		fprintf(stderr, "failed to allocate netlink callbacks\n");
701 		return -ENOMEM;
702 	}
703 
704 	/* no sequence checking for multicast messages */
705 	nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
706 
707 	if (n_waits && waits) {
708 		wait_ev.cmds = waits;
709 		wait_ev.n_cmds = n_waits;
710 		wait_ev.pargs = args;
711 		nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, wait_event, &wait_ev);
712 	} else
713 		nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_event, args);
714 
715 	wait_ev.cmd = 0;
716 
717 	while (!wait_ev.cmd)
718 		nl_recvmsgs(state->nl_sock, cb);
719 
720 	nl_cb_put(cb);
721 
722 	return wait_ev.cmd;
723 }
724 
listen_events(struct nl80211_state * state,const int n_waits,const __u32 * waits)725 __u32 listen_events(struct nl80211_state *state,
726 		    const int n_waits, const __u32 *waits)
727 {
728 	int ret;
729 
730 	ret = __prepare_listen_events(state);
731 	if (ret)
732 		return ret;
733 
734 	return __do_listen_events(state, n_waits, waits, NULL);
735 }
736 
print_events(struct nl80211_state * state,struct nl_cb * cb,struct nl_msg * msg,int argc,char ** argv,enum id_input id)737 static int print_events(struct nl80211_state *state,
738 			struct nl_cb *cb,
739 			struct nl_msg *msg,
740 			int argc, char **argv,
741 			enum id_input id)
742 {
743 	struct print_event_args args;
744 	int ret;
745 
746 	memset(&args, 0, sizeof(args));
747 
748 	argc--;
749 	argv++;
750 
751 	while (argc > 0) {
752 		if (strcmp(argv[0], "-f") == 0)
753 			args.frame = true;
754 		else if (strcmp(argv[0], "-t") == 0)
755 			args.time = true;
756 		else if (strcmp(argv[0], "-r") == 0)
757 			args.reltime = true;
758 		else
759 			return 1;
760 		argc--;
761 		argv++;
762 	}
763 
764 	if (args.time && args.reltime)
765 		return 1;
766 
767 	if (argc)
768 		return 1;
769 
770 	ret = __prepare_listen_events(state);
771 	if (ret)
772 		return ret;
773 
774 	return __do_listen_events(state, 0, NULL, &args);
775 }
776 TOPLEVEL(event, "[-t] [-r] [-f]", 0, 0, CIB_NONE, print_events,
777 	"Monitor events from the kernel.\n"
778 	"-t - print timestamp\n"
779 	"-r - print relative timstamp\n"
780 	"-f - print full frame for auth/assoc etc.");
781