• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <net/if.h>
2 #include <errno.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <stdbool.h>
6 
7 #include <netlink/genl/genl.h>
8 #include <netlink/genl/family.h>
9 #include <netlink/genl/ctrl.h>
10 #include <netlink/msg.h>
11 #include <netlink/attr.h>
12 
13 #include "nl80211.h"
14 #include "iw.h"
15 
16 #define WLAN_CAPABILITY_ESS		(1<<0)
17 #define WLAN_CAPABILITY_IBSS		(1<<1)
18 #define WLAN_CAPABILITY_CF_POLLABLE	(1<<2)
19 #define WLAN_CAPABILITY_CF_POLL_REQUEST	(1<<3)
20 #define WLAN_CAPABILITY_PRIVACY		(1<<4)
21 #define WLAN_CAPABILITY_SHORT_PREAMBLE	(1<<5)
22 #define WLAN_CAPABILITY_PBCC		(1<<6)
23 #define WLAN_CAPABILITY_CHANNEL_AGILITY	(1<<7)
24 #define WLAN_CAPABILITY_SPECTRUM_MGMT	(1<<8)
25 #define WLAN_CAPABILITY_QOS		(1<<9)
26 #define WLAN_CAPABILITY_SHORT_SLOT_TIME	(1<<10)
27 #define WLAN_CAPABILITY_APSD		(1<<11)
28 #define WLAN_CAPABILITY_RADIO_MEASURE	(1<<12)
29 #define WLAN_CAPABILITY_DSSS_OFDM	(1<<13)
30 #define WLAN_CAPABILITY_DEL_BACK	(1<<14)
31 #define WLAN_CAPABILITY_IMM_BACK	(1<<15)
32 /* DMG (60gHz) 802.11ad */
33 /* type - bits 0..1 */
34 #define WLAN_CAPABILITY_DMG_TYPE_MASK		(3<<0)
35 
36 #define WLAN_CAPABILITY_DMG_TYPE_IBSS		(1<<0) /* Tx by: STA */
37 #define WLAN_CAPABILITY_DMG_TYPE_PBSS		(2<<0) /* Tx by: PCP */
38 #define WLAN_CAPABILITY_DMG_TYPE_AP		(3<<0) /* Tx by: AP */
39 
40 #define WLAN_CAPABILITY_DMG_CBAP_ONLY		(1<<2)
41 #define WLAN_CAPABILITY_DMG_CBAP_SOURCE		(1<<3)
42 #define WLAN_CAPABILITY_DMG_PRIVACY		(1<<4)
43 #define WLAN_CAPABILITY_DMG_ECPAC		(1<<5)
44 
45 #define WLAN_CAPABILITY_DMG_SPECTRUM_MGMT	(1<<8)
46 #define WLAN_CAPABILITY_DMG_RADIO_MEASURE	(1<<12)
47 
48 static unsigned char ms_oui[3]		= { 0x00, 0x50, 0xf2 };
49 static unsigned char ieee80211_oui[3]	= { 0x00, 0x0f, 0xac };
50 static unsigned char wfa_oui[3]		= { 0x50, 0x6f, 0x9a };
51 
52 struct scan_params {
53 	bool unknown;
54 	enum print_ie_type type;
55 	bool show_both_ie_sets;
56 };
57 
58 #define IEEE80211_COUNTRY_EXTENSION_ID 201
59 
60 union ieee80211_country_ie_triplet {
61 	struct {
62 		__u8 first_channel;
63 		__u8 num_channels;
64 		__s8 max_power;
65 	} __attribute__ ((packed)) chans;
66 	struct {
67 		__u8 reg_extension_id;
68 		__u8 reg_class;
69 		__u8 coverage_class;
70 	} __attribute__ ((packed)) ext;
71 } __attribute__ ((packed));
72 
parse_random_mac_addr(struct nl_msg * msg,char * arg)73 static int parse_random_mac_addr(struct nl_msg *msg, char *arg)
74 {
75 	char *a_addr, *a_mask, *sep;
76 	unsigned char addr[ETH_ALEN], mask[ETH_ALEN];
77 	char *addrs = arg + 9;
78 
79 	if (*addrs != '=')
80 		return 0;
81 
82 	addrs++;
83 	sep = strchr(addrs, '/');
84 	a_addr = addrs;
85 
86 	if (!sep)
87 		return 1;
88 
89 	*sep = 0;
90 	a_mask = sep + 1;
91 	if (mac_addr_a2n(addr, a_addr) || mac_addr_a2n(mask, a_mask))
92 		return 1;
93 
94 	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
95 	NLA_PUT(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN, mask);
96 
97 	return 0;
98  nla_put_failure:
99 	return -ENOBUFS;
100 }
101 
parse_sched_scan(struct nl_msg * msg,int * argc,char *** argv)102 int parse_sched_scan(struct nl_msg *msg, int *argc, char ***argv)
103 {
104 	struct nl_msg *matchset = NULL, *freqs = NULL, *ssids = NULL;
105 	struct nlattr *match = NULL;
106 	enum {
107 		ND_TOPLEVEL,
108 		ND_MATCH,
109 		ND_FREQS,
110 		ND_ACTIVE,
111 	} parse_state = ND_TOPLEVEL;
112 	int c  = *argc;
113 	char *end, **v = *argv;
114 	int err = 0, i = 0;
115 	unsigned int freq, interval = 0, delay = 0;
116 	bool have_matchset = false, have_freqs = false, have_ssids = false;
117 	bool have_active = false, have_passive = false;
118 	uint32_t flags = 0;
119 
120 	matchset = nlmsg_alloc();
121 	if (!matchset) {
122 		err = -ENOBUFS;
123 		goto out;
124 	}
125 
126 	freqs = nlmsg_alloc();
127 	if (!freqs) {
128 		err = -ENOBUFS;
129 		goto out;
130 	}
131 
132 	ssids = nlmsg_alloc();
133 	if (!ssids) {
134 		err = -ENOMEM;
135 		goto out;
136 	}
137 
138 	while (c) {
139 		switch (parse_state) {
140 		case ND_TOPLEVEL:
141 			if (!strcmp(v[0], "interval")) {
142 				c--; v++;
143 				if (c == 0) {
144 					err = -EINVAL;
145 					goto nla_put_failure;
146 				}
147 
148 				if (interval) {
149 					err = -EINVAL;
150 					goto nla_put_failure;
151 				}
152 				interval = strtoul(v[0], &end, 10);
153 				if (*end || !interval) {
154 					err = -EINVAL;
155 					goto nla_put_failure;
156 				}
157 				NLA_PUT_U32(msg,
158 					    NL80211_ATTR_SCHED_SCAN_INTERVAL,
159 					    interval);
160 			} else if (!strcmp(v[0], "delay")) {
161 				c--; v++;
162 				if (c == 0) {
163 					err = -EINVAL;
164 					goto nla_put_failure;
165 				}
166 
167 				if (delay) {
168 					err = -EINVAL;
169 					goto nla_put_failure;
170 				}
171 				delay = strtoul(v[0], &end, 10);
172 				if (*end) {
173 					err = -EINVAL;
174 					goto nla_put_failure;
175 				}
176 				NLA_PUT_U32(msg,
177 					    NL80211_ATTR_SCHED_SCAN_DELAY,
178 					    delay);
179 			} else if (!strcmp(v[0], "matches")) {
180 				parse_state = ND_MATCH;
181 				if (have_matchset) {
182 					err = -EINVAL;
183 					goto nla_put_failure;
184 				}
185 
186 				i = 0;
187 			} else if (!strcmp(v[0], "freqs")) {
188 				parse_state = ND_FREQS;
189 				if (have_freqs) {
190 					err = -EINVAL;
191 					goto nla_put_failure;
192 				}
193 
194 				have_freqs = true;
195 				i = 0;
196 			} else if (!strcmp(v[0], "active")) {
197 				parse_state = ND_ACTIVE;
198 				if (have_active || have_passive) {
199 					err = -EINVAL;
200 					goto nla_put_failure;
201 				}
202 
203 				have_active = true;
204 				i = 0;
205 			} else if (!strcmp(v[0], "passive")) {
206 				if (have_active || have_passive) {
207 					err = -EINVAL;
208 					goto nla_put_failure;
209 				}
210 
211 				have_passive = true;
212 			} else if (!strncmp(v[0], "randomise", 9) ||
213 				   !strncmp(v[0], "randomize", 9)) {
214 				flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;
215 				if (c > 0) {
216 					err = parse_random_mac_addr(msg, v[0]);
217 					if (err)
218 						goto nla_put_failure;
219 				}
220 			} else {
221 				/* this element is not for us, so
222 				 * return to continue parsing.
223 				 */
224 				goto nla_put_failure;
225 			}
226 			c--; v++;
227 
228 			break;
229 		case ND_MATCH:
230 			if (!strcmp(v[0], "ssid")) {
231 				c--; v++;
232 				if (c == 0) {
233 					err = -EINVAL;
234 					goto nla_put_failure;
235 				}
236 
237 				/* TODO: for now we can only have an
238 				 * SSID in the match, so we can start
239 				 * the match nest here.
240 				 */
241 				match = nla_nest_start(matchset, i);
242 				if (!match) {
243 					err = -ENOBUFS;
244 					goto nla_put_failure;
245 				}
246 
247 				NLA_PUT(matchset,
248 					NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
249 					strlen(v[0]), v[0]);
250 				nla_nest_end(matchset, match);
251 				match = NULL;
252 
253 				have_matchset = true;
254 				i++;
255 				c--; v++;
256 			} else {
257 				/* other element that cannot be part
258 				 * of a match indicates the end of the
259 				 * match. */
260 				/* need at least one match in the matchset */
261 				if (i == 0) {
262 					err = -EINVAL;
263 					goto nla_put_failure;
264 				}
265 
266 				parse_state = ND_TOPLEVEL;
267 			}
268 
269 			break;
270 		case ND_FREQS:
271 			freq = strtoul(v[0], &end, 10);
272 			if (*end) {
273 				if (i == 0) {
274 					err = -EINVAL;
275 					goto nla_put_failure;
276 				}
277 
278 				parse_state = ND_TOPLEVEL;
279 			} else {
280 				NLA_PUT_U32(freqs, i, freq);
281 				i++;
282 				c--; v++;
283 			}
284 			break;
285 		case ND_ACTIVE:
286 			if (!strcmp(v[0], "ssid")) {
287 				c--; v++;
288 				if (c == 0) {
289 					err = -EINVAL;
290 					goto nla_put_failure;
291 				}
292 
293 				NLA_PUT(ssids,
294 					NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
295 					strlen(v[0]), v[0]);
296 
297 				have_ssids = true;
298 				i++;
299 				c--; v++;
300 			} else {
301 				/* other element that cannot be part
302 				 * of a match indicates the end of the
303 				 * active set. */
304 				/* need at least one item in the set */
305 				if (i == 0) {
306 					err = -EINVAL;
307 					goto nla_put_failure;
308 				}
309 
310 				parse_state = ND_TOPLEVEL;
311 			}
312 			break;
313 		}
314 	}
315 
316 	if (!have_ssids)
317 		NLA_PUT(ssids, 1, 0, "");
318 	if (!have_passive)
319 		nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
320 	if (have_freqs)
321 		nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
322 	if (have_matchset)
323 		nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH, matchset);
324 	if (flags)
325 		NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, flags);
326 
327 nla_put_failure:
328 	if (match)
329 		nla_nest_end(msg, match);
330 	nlmsg_free(freqs);
331 	nlmsg_free(matchset);
332 
333 out:
334 	*argc = c;
335 	*argv = v;
336 	return err;
337 }
338 
handle_scan(struct nl80211_state * state,struct nl_cb * cb,struct nl_msg * msg,int argc,char ** argv,enum id_input id)339 static int handle_scan(struct nl80211_state *state,
340 		       struct nl_cb *cb,
341 		       struct nl_msg *msg,
342 		       int argc, char **argv,
343 		       enum id_input id)
344 {
345 	struct nl_msg *ssids = NULL, *freqs = NULL;
346 	char *eptr;
347 	int err = -ENOBUFS;
348 	int i;
349 	enum {
350 		NONE,
351 		FREQ,
352 		IES,
353 		SSID,
354 		MESHID,
355 		DONE,
356 	} parse = NONE;
357 	int freq;
358 	bool passive = false, have_ssids = false, have_freqs = false;
359 	size_t ies_len = 0, meshid_len = 0;
360 	unsigned char *ies = NULL, *meshid = NULL, *tmpies;
361 	unsigned int flags = 0;
362 
363 	ssids = nlmsg_alloc();
364 	if (!ssids)
365 		return -ENOMEM;
366 
367 	freqs = nlmsg_alloc();
368 	if (!freqs) {
369 		nlmsg_free(ssids);
370 		return -ENOMEM;
371 	}
372 
373 	for (i = 0; i < argc; i++) {
374 		switch (parse) {
375 		case NONE:
376 			if (strcmp(argv[i], "freq") == 0) {
377 				parse = FREQ;
378 				have_freqs = true;
379 				break;
380 			} else if (strcmp(argv[i], "ies") == 0) {
381 				parse = IES;
382 				break;
383 			} else if (strcmp(argv[i], "lowpri") == 0) {
384 				flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
385 				break;
386 			} else if (strcmp(argv[i], "flush") == 0) {
387 				flags |= NL80211_SCAN_FLAG_FLUSH;
388 				break;
389 			} else if (strcmp(argv[i], "ap-force") == 0) {
390 				flags |= NL80211_SCAN_FLAG_AP;
391 				break;
392 			} else if (strncmp(argv[i], "randomise", 9) == 0 ||
393 				   strncmp(argv[i], "randomize", 9) == 0) {
394 				flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;
395 				err = parse_random_mac_addr(msg, argv[i]);
396 				if (err)
397 					goto nla_put_failure;
398 				break;
399 			} else if (strcmp(argv[i], "ssid") == 0) {
400 				parse = SSID;
401 				have_ssids = true;
402 				break;
403 			} else if (strcmp(argv[i], "passive") == 0) {
404 				parse = DONE;
405 				passive = true;
406 				break;
407 			} else if (strcmp(argv[i], "meshid") == 0) {
408 				parse = MESHID;
409 				break;
410 			}
411 		case DONE:
412 			return 1;
413 		case FREQ:
414 			freq = strtoul(argv[i], &eptr, 10);
415 			if (eptr != argv[i] + strlen(argv[i])) {
416 				/* failed to parse as number -- maybe a tag? */
417 				i--;
418 				parse = NONE;
419 				continue;
420 			}
421 			NLA_PUT_U32(freqs, i, freq);
422 			break;
423 		case IES:
424 			ies = parse_hex(argv[i], &ies_len);
425 			if (!ies)
426 				goto nla_put_failure;
427 			parse = NONE;
428 			break;
429 		case SSID:
430 			NLA_PUT(ssids, i, strlen(argv[i]), argv[i]);
431 			break;
432 		case MESHID:
433 			meshid_len = strlen(argv[i]);
434 			meshid = (unsigned char *) malloc(meshid_len + 2);
435 			if (!meshid)
436 				goto nla_put_failure;
437 			meshid[0] = 114; /* mesh element id */
438 			meshid[1] = meshid_len;
439 			memcpy(&meshid[2], argv[i], meshid_len);
440 			meshid_len += 2;
441 			parse = NONE;
442 			break;
443 		}
444 	}
445 
446 	if (ies || meshid) {
447 		tmpies = (unsigned char *) malloc(ies_len + meshid_len);
448 		if (!tmpies)
449 			goto nla_put_failure;
450 		if (ies) {
451 			memcpy(tmpies, ies, ies_len);
452 			free(ies);
453 		}
454 		if (meshid) {
455 			memcpy(&tmpies[ies_len], meshid, meshid_len);
456 			free(meshid);
457 		}
458 		NLA_PUT(msg, NL80211_ATTR_IE, ies_len + meshid_len, tmpies);
459 		free(tmpies);
460 	}
461 
462 	if (!have_ssids)
463 		NLA_PUT(ssids, 1, 0, "");
464 	if (!passive)
465 		nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
466 
467 	if (have_freqs)
468 		nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
469 	if (flags)
470 		NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, flags);
471 
472 	err = 0;
473  nla_put_failure:
474 	nlmsg_free(ssids);
475 	nlmsg_free(freqs);
476 	return err;
477 }
478 
tab_on_first(bool * first)479 static void tab_on_first(bool *first)
480 {
481 	if (!*first)
482 		printf("\t");
483 	else
484 		*first = false;
485 }
486 
print_ssid(const uint8_t type,uint8_t len,const uint8_t * data)487 static void print_ssid(const uint8_t type, uint8_t len, const uint8_t *data)
488 {
489 	printf(" ");
490 	print_ssid_escaped(len, data);
491 	printf("\n");
492 }
493 
494 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
495 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
496 
print_supprates(const uint8_t type,uint8_t len,const uint8_t * data)497 static void print_supprates(const uint8_t type, uint8_t len, const uint8_t *data)
498 {
499 	int i;
500 
501 	printf(" ");
502 
503 	for (i = 0; i < len; i++) {
504 		int r = data[i] & 0x7f;
505 
506 		if (r == BSS_MEMBERSHIP_SELECTOR_VHT_PHY && data[i] & 0x80)
507 			printf("VHT");
508 		else if (r == BSS_MEMBERSHIP_SELECTOR_HT_PHY && data[i] & 0x80)
509 			printf("HT");
510 		else
511 			printf("%d.%d", r/2, 5*(r&1));
512 
513 		printf("%s ", data[i] & 0x80 ? "*" : "");
514 	}
515 	printf("\n");
516 }
517 
print_ds(const uint8_t type,uint8_t len,const uint8_t * data)518 static void print_ds(const uint8_t type, uint8_t len, const uint8_t *data)
519 {
520 	printf(" channel %d\n", data[0]);
521 }
522 
country_env_str(char environment)523 static const char *country_env_str(char environment)
524 {
525 	switch (environment) {
526 	case 'I':
527 		return "Indoor only";
528 	case 'O':
529 		return "Outdoor only";
530 	case ' ':
531 		return "Indoor/Outdoor";
532 	default:
533 		return "bogus";
534 	}
535 }
536 
print_country(const uint8_t type,uint8_t len,const uint8_t * data)537 static void print_country(const uint8_t type, uint8_t len, const uint8_t *data)
538 {
539 	printf(" %.*s", 2, data);
540 
541 	printf("\tEnvironment: %s\n", country_env_str(data[2]));
542 
543 	data += 3;
544 	len -= 3;
545 
546 	if (len < 3) {
547 		printf("\t\tNo country IE triplets present\n");
548 		return;
549 	}
550 
551 	while (len >= 3) {
552 		int end_channel;
553 		union ieee80211_country_ie_triplet *triplet = (void *) data;
554 
555 		if (triplet->ext.reg_extension_id >= IEEE80211_COUNTRY_EXTENSION_ID) {
556 			printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
557 			       triplet->ext.reg_extension_id,
558 			       triplet->ext.reg_class,
559 			       triplet->ext.coverage_class,
560 			       triplet->ext.coverage_class * 450);
561 
562 			data += 3;
563 			len -= 3;
564 			continue;
565 		}
566 
567 		/* 2 GHz */
568 		if (triplet->chans.first_channel <= 14)
569 			end_channel = triplet->chans.first_channel + (triplet->chans.num_channels - 1);
570 		else
571 			end_channel =  triplet->chans.first_channel + (4 * (triplet->chans.num_channels - 1));
572 
573 		printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet->chans.first_channel, end_channel, triplet->chans.max_power);
574 
575 		data += 3;
576 		len -= 3;
577 	}
578 
579 	return;
580 }
581 
print_powerconstraint(const uint8_t type,uint8_t len,const uint8_t * data)582 static void print_powerconstraint(const uint8_t type, uint8_t len, const uint8_t *data)
583 {
584 	printf(" %d dB\n", data[0]);
585 }
586 
print_tpcreport(const uint8_t type,uint8_t len,const uint8_t * data)587 static void print_tpcreport(const uint8_t type, uint8_t len, const uint8_t *data)
588 {
589 	printf(" TX power: %d dBm\n", data[0]);
590 	/* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
591 }
592 
print_erp(const uint8_t type,uint8_t len,const uint8_t * data)593 static void print_erp(const uint8_t type, uint8_t len, const uint8_t *data)
594 {
595 	if (data[0] == 0x00)
596 		printf(" <no flags>");
597 	if (data[0] & 0x01)
598 		printf(" NonERP_Present");
599 	if (data[0] & 0x02)
600 		printf(" Use_Protection");
601 	if (data[0] & 0x04)
602 		printf(" Barker_Preamble_Mode");
603 	printf("\n");
604 }
605 
print_cipher(const uint8_t * data)606 static void print_cipher(const uint8_t *data)
607 {
608 	if (memcmp(data, ms_oui, 3) == 0) {
609 		switch (data[3]) {
610 		case 0:
611 			printf("Use group cipher suite");
612 			break;
613 		case 1:
614 			printf("WEP-40");
615 			break;
616 		case 2:
617 			printf("TKIP");
618 			break;
619 		case 4:
620 			printf("CCMP");
621 			break;
622 		case 5:
623 			printf("WEP-104");
624 			break;
625 		default:
626 			printf("%.02x-%.02x-%.02x:%d",
627 				data[0], data[1] ,data[2], data[3]);
628 			break;
629 		}
630 	} else if (memcmp(data, ieee80211_oui, 3) == 0) {
631 		switch (data[3]) {
632 		case 0:
633 			printf("Use group cipher suite");
634 			break;
635 		case 1:
636 			printf("WEP-40");
637 			break;
638 		case 2:
639 			printf("TKIP");
640 			break;
641 		case 4:
642 			printf("CCMP");
643 			break;
644 		case 5:
645 			printf("WEP-104");
646 			break;
647 		case 6:
648 			printf("AES-128-CMAC");
649 			break;
650 		case 7:
651 			printf("NO-GROUP");
652 			break;
653 		case 8:
654 			printf("GCMP");
655 			break;
656 		default:
657 			printf("%.02x-%.02x-%.02x:%d",
658 				data[0], data[1] ,data[2], data[3]);
659 			break;
660 		}
661 	} else
662 		printf("%.02x-%.02x-%.02x:%d",
663 			data[0], data[1] ,data[2], data[3]);
664 }
665 
print_auth(const uint8_t * data)666 static void print_auth(const uint8_t *data)
667 {
668 	if (memcmp(data, ms_oui, 3) == 0) {
669 		switch (data[3]) {
670 		case 1:
671 			printf("IEEE 802.1X");
672 			break;
673 		case 2:
674 			printf("PSK");
675 			break;
676 		default:
677 			printf("%.02x-%.02x-%.02x:%d",
678 				data[0], data[1] ,data[2], data[3]);
679 			break;
680 		}
681 	} else if (memcmp(data, ieee80211_oui, 3) == 0) {
682 		switch (data[3]) {
683 		case 1:
684 			printf("IEEE 802.1X");
685 			break;
686 		case 2:
687 			printf("PSK");
688 			break;
689 		case 3:
690 			printf("FT/IEEE 802.1X");
691 			break;
692 		case 4:
693 			printf("FT/PSK");
694 			break;
695 		case 5:
696 			printf("IEEE 802.1X/SHA-256");
697 			break;
698 		case 6:
699 			printf("PSK/SHA-256");
700 			break;
701 		case 7:
702 			printf("TDLS/TPK");
703 			break;
704 		default:
705 			printf("%.02x-%.02x-%.02x:%d",
706 				data[0], data[1] ,data[2], data[3]);
707 			break;
708 		}
709 	} else if (memcmp(data, wfa_oui, 3) == 0) {
710 		switch (data[3]) {
711 		case 1:
712 			printf("OSEN");
713 			break;
714 		default:
715 			printf("%.02x-%.02x-%.02x:%d",
716 				data[0], data[1] ,data[2], data[3]);
717 			break;
718 		}
719 	} else
720 		printf("%.02x-%.02x-%.02x:%d",
721 			data[0], data[1] ,data[2], data[3]);
722 }
723 
_print_rsn_ie(const char * defcipher,const char * defauth,uint8_t len,const uint8_t * data,int is_osen)724 static void _print_rsn_ie(const char *defcipher, const char *defauth,
725 			  uint8_t len, const uint8_t *data, int is_osen)
726 {
727 	bool first = true;
728 	__u16 count, capa;
729 	int i;
730 
731 	if (!is_osen) {
732 		__u16 version;
733 		version = data[0] + (data[1] << 8);
734 		tab_on_first(&first);
735 		printf("\t * Version: %d\n", version);
736 
737 		data += 2;
738 		len -= 2;
739 	}
740 
741 	if (len < 4) {
742 		tab_on_first(&first);
743 		printf("\t * Group cipher: %s\n", defcipher);
744 		printf("\t * Pairwise ciphers: %s\n", defcipher);
745 		return;
746 	}
747 
748 	tab_on_first(&first);
749 	printf("\t * Group cipher: ");
750 	print_cipher(data);
751 	printf("\n");
752 
753 	data += 4;
754 	len -= 4;
755 
756 	if (len < 2) {
757 		tab_on_first(&first);
758 		printf("\t * Pairwise ciphers: %s\n", defcipher);
759 		return;
760 	}
761 
762 	count = data[0] | (data[1] << 8);
763 	if (2 + (count * 4) > len)
764 		goto invalid;
765 
766 	tab_on_first(&first);
767 	printf("\t * Pairwise ciphers:");
768 	for (i = 0; i < count; i++) {
769 		printf(" ");
770 		print_cipher(data + 2 + (i * 4));
771 	}
772 	printf("\n");
773 
774 	data += 2 + (count * 4);
775 	len -= 2 + (count * 4);
776 
777 	if (len < 2) {
778 		tab_on_first(&first);
779 		printf("\t * Authentication suites: %s\n", defauth);
780 		return;
781 	}
782 
783 	count = data[0] | (data[1] << 8);
784 	if (2 + (count * 4) > len)
785 		goto invalid;
786 
787 	tab_on_first(&first);
788 	printf("\t * Authentication suites:");
789 	for (i = 0; i < count; i++) {
790 		printf(" ");
791 		print_auth(data + 2 + (i * 4));
792 	}
793 	printf("\n");
794 
795 	data += 2 + (count * 4);
796 	len -= 2 + (count * 4);
797 
798 	if (len >= 2) {
799 		capa = data[0] | (data[1] << 8);
800 		tab_on_first(&first);
801 		printf("\t * Capabilities:");
802 		if (capa & 0x0001)
803 			printf(" PreAuth");
804 		if (capa & 0x0002)
805 			printf(" NoPairwise");
806 		switch ((capa & 0x000c) >> 2) {
807 		case 0:
808 			printf(" 1-PTKSA-RC");
809 			break;
810 		case 1:
811 			printf(" 2-PTKSA-RC");
812 			break;
813 		case 2:
814 			printf(" 4-PTKSA-RC");
815 			break;
816 		case 3:
817 			printf(" 16-PTKSA-RC");
818 			break;
819 		}
820 		switch ((capa & 0x0030) >> 4) {
821 		case 0:
822 			printf(" 1-GTKSA-RC");
823 			break;
824 		case 1:
825 			printf(" 2-GTKSA-RC");
826 			break;
827 		case 2:
828 			printf(" 4-GTKSA-RC");
829 			break;
830 		case 3:
831 			printf(" 16-GTKSA-RC");
832 			break;
833 		}
834 		if (capa & 0x0040)
835 			printf(" MFP-required");
836 		if (capa & 0x0080)
837 			printf(" MFP-capable");
838 		if (capa & 0x0200)
839 			printf(" Peerkey-enabled");
840 		if (capa & 0x0400)
841 			printf(" SPP-AMSDU-capable");
842 		if (capa & 0x0800)
843 			printf(" SPP-AMSDU-required");
844 		printf(" (0x%.4x)\n", capa);
845 		data += 2;
846 		len -= 2;
847 	}
848 
849 	if (len >= 2) {
850 		int pmkid_count = data[0] | (data[1] << 8);
851 
852 		if (len >= 2 + 16 * pmkid_count) {
853 			tab_on_first(&first);
854 			printf("\t * %d PMKIDs\n", pmkid_count);
855 			/* not printing PMKID values */
856 			data += 2 + 16 * pmkid_count;
857 			len -= 2 + 16 * pmkid_count;
858 		} else
859 			goto invalid;
860 	}
861 
862 	if (len >= 4) {
863 		tab_on_first(&first);
864 		printf("\t * Group mgmt cipher suite: ");
865 		print_cipher(data);
866 		printf("\n");
867 		data += 4;
868 		len -= 4;
869 	}
870 
871  invalid:
872 	if (len != 0) {
873 		printf("\t\t * bogus tail data (%d):", len);
874 		while (len) {
875 			printf(" %.2x", *data);
876 			data++;
877 			len--;
878 		}
879 		printf("\n");
880 	}
881 }
882 
print_rsn_ie(const char * defcipher,const char * defauth,uint8_t len,const uint8_t * data)883 static void print_rsn_ie(const char *defcipher, const char *defauth,
884 			 uint8_t len, const uint8_t *data)
885 {
886 	_print_rsn_ie(defcipher, defauth, len, data, 0);
887 }
888 
print_osen_ie(const char * defcipher,const char * defauth,uint8_t len,const uint8_t * data)889 static void print_osen_ie(const char *defcipher, const char *defauth,
890 			  uint8_t len, const uint8_t *data)
891 {
892 	printf("\n\t");
893 	_print_rsn_ie(defcipher, defauth, len, data, 1);
894 }
895 
print_rsn(const uint8_t type,uint8_t len,const uint8_t * data)896 static void print_rsn(const uint8_t type, uint8_t len, const uint8_t *data)
897 {
898 	print_rsn_ie("CCMP", "IEEE 802.1X", len, data);
899 }
900 
print_ht_capa(const uint8_t type,uint8_t len,const uint8_t * data)901 static void print_ht_capa(const uint8_t type, uint8_t len, const uint8_t *data)
902 {
903 	printf("\n");
904 	print_ht_capability(data[0] | (data[1] << 8));
905 	print_ampdu_length(data[2] & 3);
906 	print_ampdu_spacing((data[2] >> 2) & 7);
907 	print_ht_mcs(data + 3);
908 }
909 
ntype_11u(uint8_t t)910 static const char* ntype_11u(uint8_t t)
911 {
912 	switch (t) {
913 	case 0: return "Private";
914 	case 1: return "Private with Guest";
915 	case 2: return "Chargeable Public";
916 	case 3: return "Free Public";
917 	case 4: return "Personal Device";
918 	case 5: return "Emergency Services Only";
919 	case 14: return "Test or Experimental";
920 	case 15: return "Wildcard";
921 	default: return "Reserved";
922 	}
923 }
924 
vgroup_11u(uint8_t t)925 static const char* vgroup_11u(uint8_t t)
926 {
927 	switch (t) {
928 	case 0: return "Unspecified";
929 	case 1: return "Assembly";
930 	case 2: return "Business";
931 	case 3: return "Educational";
932 	case 4: return "Factory and Industrial";
933 	case 5: return "Institutional";
934 	case 6: return "Mercantile";
935 	case 7: return "Residential";
936 	case 8: return "Storage";
937 	case 9: return "Utility and Miscellaneous";
938 	case 10: return "Vehicular";
939 	case 11: return "Outdoor";
940 	default: return "Reserved";
941 	}
942 }
943 
print_interworking(const uint8_t type,uint8_t len,const uint8_t * data)944 static void print_interworking(const uint8_t type, uint8_t len, const uint8_t *data)
945 {
946 	/* See Section 7.3.2.92 in the 802.11u spec. */
947 	printf("\n");
948 	if (len >= 1) {
949 		uint8_t ano = data[0];
950 		printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano));
951 		printf("\t\t\tNetwork Type: %i (%s)\n",
952 		       (int)(ano & 0xf), ntype_11u(ano & 0xf));
953 		if (ano & (1<<4))
954 			printf("\t\t\tInternet\n");
955 		if (ano & (1<<5))
956 			printf("\t\t\tASRA\n");
957 		if (ano & (1<<6))
958 			printf("\t\t\tESR\n");
959 		if (ano & (1<<7))
960 			printf("\t\t\tUESA\n");
961 	}
962 	if ((len == 3) || (len == 9)) {
963 		printf("\t\tVenue Group: %i (%s)\n",
964 		       (int)(data[1]), vgroup_11u(data[1]));
965 		printf("\t\tVenue Type: %i\n", (int)(data[2]));
966 	}
967 	if (len == 9)
968 		printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
969 		       data[3], data[4], data[5], data[6], data[7], data[8]);
970 	else if (len == 7)
971 		printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
972 		       data[1], data[2], data[3], data[4], data[5], data[6]);
973 }
974 
print_11u_advert(const uint8_t type,uint8_t len,const uint8_t * data)975 static void print_11u_advert(const uint8_t type, uint8_t len, const uint8_t *data)
976 {
977 	/* See Section 7.3.2.93 in the 802.11u spec. */
978 	/* TODO: This code below does not decode private protocol IDs */
979 	int idx = 0;
980 	printf("\n");
981 	while (idx < (len - 1)) {
982 		uint8_t qri = data[idx];
983 		uint8_t proto_id = data[idx + 1];
984 		printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri));
985 		printf("\t\t\tQuery Response Length Limit: %i\n",
986 		       (qri & 0x7f));
987 		if (qri & (1<<7))
988 			printf("\t\t\tPAME-BI\n");
989 		switch(proto_id) {
990 		case 0:
991 			printf("\t\t\tANQP\n"); break;
992 		case 1:
993 			printf("\t\t\tMIH Information Service\n"); break;
994 		case 2:
995 			printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
996 		case 3:
997 			printf("\t\t\tEmergency Alert System (EAS)\n"); break;
998 		case 221:
999 			printf("\t\t\tVendor Specific\n"); break;
1000 		default:
1001 			printf("\t\t\tReserved: %i\n", proto_id); break;
1002 		}
1003 		idx += 2;
1004 	}
1005 }
1006 
print_11u_rcon(const uint8_t type,uint8_t len,const uint8_t * data)1007 static void print_11u_rcon(const uint8_t type, uint8_t len, const uint8_t *data)
1008 {
1009 	/* See Section 7.3.2.96 in the 802.11u spec. */
1010 	int idx = 0;
1011 	int ln0 = data[1] & 0xf;
1012 	int ln1 = ((data[1] & 0xf0) >> 4);
1013 	int ln2 = 0;
1014 	printf("\n");
1015 
1016 	if (ln1)
1017 		ln2 = len - 2 - ln0 - ln1;
1018 
1019 	printf("\t\tANQP OIs: %i\n", data[0]);
1020 
1021 	if (ln0 > 0) {
1022 		printf("\t\tOI 1: ");
1023 		if (2 + ln0 > len) {
1024 			printf("Invalid IE length.\n");
1025 		} else {
1026 			for (idx = 0; idx < ln0; idx++) {
1027 				printf("%02hx", data[2 + idx]);
1028 			}
1029 			printf("\n");
1030 		}
1031 	}
1032 
1033 	if (ln1 > 0) {
1034 		printf("\t\tOI 2: ");
1035 		if (2 + ln0 + ln1 > len) {
1036 			printf("Invalid IE length.\n");
1037 		} else {
1038 			for (idx = 0; idx < ln1; idx++) {
1039 				printf("%02hx", data[2 + ln0 + idx]);
1040 			}
1041 			printf("\n");
1042 		}
1043 	}
1044 
1045 	if (ln2 > 0) {
1046 		printf("\t\tOI 3: ");
1047 		if (2 + ln0 + ln1 + ln2 > len) {
1048 			printf("Invalid IE length.\n");
1049 		} else {
1050 			for (idx = 0; idx < ln2; idx++) {
1051 				printf("%02hx", data[2 + ln0 + ln1 + idx]);
1052 			}
1053 			printf("\n");
1054 		}
1055 	}
1056 }
1057 
1058 static const char *ht_secondary_offset[4] = {
1059 	"no secondary",
1060 	"above",
1061 	"[reserved!]",
1062 	"below",
1063 };
1064 
print_ht_op(const uint8_t type,uint8_t len,const uint8_t * data)1065 static void print_ht_op(const uint8_t type, uint8_t len, const uint8_t *data)
1066 {
1067 	static const char *protection[4] = {
1068 		"no",
1069 		"nonmember",
1070 		"20 MHz",
1071 		"non-HT mixed",
1072 	};
1073 	static const char *sta_chan_width[2] = {
1074 		"20 MHz",
1075 		"any",
1076 	};
1077 
1078 	printf("\n");
1079 	printf("\t\t * primary channel: %d\n", data[0]);
1080 	printf("\t\t * secondary channel offset: %s\n",
1081 		ht_secondary_offset[data[1] & 0x3]);
1082 	printf("\t\t * STA channel width: %s\n", sta_chan_width[(data[1] & 0x4)>>2]);
1083 	printf("\t\t * RIFS: %d\n", (data[1] & 0x8)>>3);
1084 	printf("\t\t * HT protection: %s\n", protection[data[2] & 0x3]);
1085 	printf("\t\t * non-GF present: %d\n", (data[2] & 0x4) >> 2);
1086 	printf("\t\t * OBSS non-GF present: %d\n", (data[2] & 0x10) >> 4);
1087 	printf("\t\t * dual beacon: %d\n", (data[4] & 0x40) >> 6);
1088 	printf("\t\t * dual CTS protection: %d\n", (data[4] & 0x80) >> 7);
1089 	printf("\t\t * STBC beacon: %d\n", data[5] & 0x1);
1090 	printf("\t\t * L-SIG TXOP Prot: %d\n", (data[5] & 0x2) >> 1);
1091 	printf("\t\t * PCO active: %d\n", (data[5] & 0x4) >> 2);
1092 	printf("\t\t * PCO phase: %d\n", (data[5] & 0x8) >> 3);
1093 }
1094 
print_capabilities(const uint8_t type,uint8_t len,const uint8_t * data)1095 static void print_capabilities(const uint8_t type, uint8_t len, const uint8_t *data)
1096 {
1097 	int i, base, bit;
1098 	bool first = true;
1099 
1100 
1101 	for (i = 0; i < len; i++) {
1102 		base = i * 8;
1103 
1104 		for (bit = 0; bit < 8; bit++) {
1105 			if (!(data[i] & (1 << bit)))
1106 				continue;
1107 
1108 			if (!first)
1109 				printf(",");
1110 			else
1111 				first = false;
1112 
1113 #define CAPA(bit, name)		case bit: printf(" " name); break
1114 
1115 			switch (bit + base) {
1116 			CAPA(0, "HT Information Exchange Supported");
1117 			CAPA(1, "reserved (On-demand Beacon)");
1118 			CAPA(2, "Extended Channel Switching");
1119 			CAPA(3, "reserved (Wave Indication)");
1120 			CAPA(4, "PSMP Capability");
1121 			CAPA(5, "reserved (Service Interval Granularity)");
1122 			CAPA(6, "S-PSMP Capability");
1123 			CAPA(7, "Event");
1124 			CAPA(8, "Diagnostics");
1125 			CAPA(9, "Multicast Diagnostics");
1126 			CAPA(10, "Location Tracking");
1127 			CAPA(11, "FMS");
1128 			CAPA(12, "Proxy ARP Service");
1129 			CAPA(13, "Collocated Interference Reporting");
1130 			CAPA(14, "Civic Location");
1131 			CAPA(15, "Geospatial Location");
1132 			CAPA(16, "TFS");
1133 			CAPA(17, "WNM-Sleep Mode");
1134 			CAPA(18, "TIM Broadcast");
1135 			CAPA(19, "BSS Transition");
1136 			CAPA(20, "QoS Traffic Capability");
1137 			CAPA(21, "AC Station Count");
1138 			CAPA(22, "Multiple BSSID");
1139 			CAPA(23, "Timing Measurement");
1140 			CAPA(24, "Channel Usage");
1141 			CAPA(25, "SSID List");
1142 			CAPA(26, "DMS");
1143 			CAPA(27, "UTC TSF Offset");
1144 			CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1145 			CAPA(29, "TDLS Peer PSM Support");
1146 			CAPA(30, "TDLS channel switching");
1147 			CAPA(31, "Interworking");
1148 			CAPA(32, "QoS Map");
1149 			CAPA(33, "EBR");
1150 			CAPA(34, "SSPN Interface");
1151 			CAPA(35, "Reserved");
1152 			CAPA(36, "MSGCF Capability");
1153 			CAPA(37, "TDLS Support");
1154 			CAPA(38, "TDLS Prohibited");
1155 			CAPA(39, "TDLS Channel Switching Prohibited");
1156 			CAPA(40, "Reject Unadmitted Frame");
1157 			CAPA(44, "Identifier Location");
1158 			CAPA(45, "U-APSD Coexistence");
1159 			CAPA(46, "WNM-Notification");
1160 			CAPA(47, "Reserved");
1161 			CAPA(48, "UTF-8 SSID");
1162 			default:
1163 				printf(" %d", bit);
1164 				break;
1165 			}
1166 #undef CAPA
1167 		}
1168 	}
1169 
1170 	printf("\n");
1171 }
1172 
print_tim(const uint8_t type,uint8_t len,const uint8_t * data)1173 static void print_tim(const uint8_t type, uint8_t len, const uint8_t *data)
1174 {
1175 	printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1176 	       "Bitmap[0] 0x%x",
1177 	       data[0], data[1], data[2], data[3]);
1178 	if (len - 4)
1179 		printf(" (+ %u octet%s)", len - 4, len - 4 == 1 ? "" : "s");
1180 	printf("\n");
1181 }
1182 
print_ibssatim(const uint8_t type,uint8_t len,const uint8_t * data)1183 static void print_ibssatim(const uint8_t type, uint8_t len, const uint8_t *data)
1184 {
1185 	printf(" %d TUs", (data[1] << 8) + data[0]);
1186 }
1187 
print_vht_capa(const uint8_t type,uint8_t len,const uint8_t * data)1188 static void print_vht_capa(const uint8_t type, uint8_t len, const uint8_t *data)
1189 {
1190 	printf("\n");
1191 	print_vht_info(data[0] | (data[1] << 8) |
1192 		       (data[2] << 16) | (data[3] << 24),
1193 		       data + 4);
1194 }
1195 
print_vht_oper(const uint8_t type,uint8_t len,const uint8_t * data)1196 static void print_vht_oper(const uint8_t type, uint8_t len, const uint8_t *data)
1197 {
1198 	const char *chandwidths[] = {
1199 		[0] = "20 or 40 MHz",
1200 		[1] = "80 MHz",
1201 		[3] = "80+80 MHz",
1202 		[2] = "160 MHz",
1203 	};
1204 
1205 	printf("\n");
1206 	printf("\t\t * channel width: %d (%s)\n", data[0],
1207 		data[0] < ARRAY_SIZE(chandwidths) ? chandwidths[data[0]] : "unknown");
1208 	printf("\t\t * center freq segment 1: %d\n", data[1]);
1209 	printf("\t\t * center freq segment 2: %d\n", data[2]);
1210 	printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data[4], data[3]);
1211 }
1212 
print_obss_scan_params(const uint8_t type,uint8_t len,const uint8_t * data)1213 static void print_obss_scan_params(const uint8_t type, uint8_t len, const uint8_t *data)
1214 {
1215 	printf("\n");
1216 	printf("\t\t * passive dwell: %d TUs\n", (data[1] << 8) | data[0]);
1217 	printf("\t\t * active dwell: %d TUs\n", (data[3] << 8) | data[2]);
1218 	printf("\t\t * channel width trigger scan interval: %d s\n", (data[5] << 8) | data[4]);
1219 	printf("\t\t * scan passive total per channel: %d TUs\n", (data[7] << 8) | data[6]);
1220 	printf("\t\t * scan active total per channel: %d TUs\n", (data[9] << 8) | data[8]);
1221 	printf("\t\t * BSS width channel transition delay factor: %d\n", (data[11] << 8) | data[10]);
1222 	printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1223 		((data[13] << 8) | data[12]) / 100, ((data[13] << 8) | data[12]) % 100);
1224 }
1225 
print_secchan_offs(const uint8_t type,uint8_t len,const uint8_t * data)1226 static void print_secchan_offs(const uint8_t type, uint8_t len, const uint8_t *data)
1227 {
1228 	if (data[0] < ARRAY_SIZE(ht_secondary_offset))
1229 		printf(" %s (%d)\n", ht_secondary_offset[data[0]], data[0]);
1230 	else
1231 		printf(" %d\n", data[0]);
1232 }
1233 
print_bss_load(const uint8_t type,uint8_t len,const uint8_t * data)1234 static void print_bss_load(const uint8_t type, uint8_t len, const uint8_t *data)
1235 {
1236 	printf("\n");
1237 	printf("\t\t * station count: %d\n", (data[1] << 8) | data[0]);
1238 	printf("\t\t * channel utilisation: %d/255\n", data[2]);
1239 	printf("\t\t * available admission capacity: %d [*32us]\n", (data[4] << 8) | data[3]);
1240 }
1241 
print_mesh_conf(const uint8_t type,uint8_t len,const uint8_t * data)1242 static void print_mesh_conf(const uint8_t type, uint8_t len, const uint8_t *data)
1243 {
1244 	printf("\n");
1245 	printf("\t\t * Active Path Selection Protocol ID: %d\n", data[0]);
1246 	printf("\t\t * Active Path Selection Metric ID: %d\n", data[1]);
1247 	printf("\t\t * Congestion Control Mode ID: %d\n", data[2]);
1248 	printf("\t\t * Synchronization Method ID: %d\n", data[3]);
1249 	printf("\t\t * Authentication Protocol ID: %d\n", data[4]);
1250 	printf("\t\t * Mesh Formation Info:\n");
1251 	printf("\t\t\t Number of Peerings: %d\n", (data[5] & 0x7E) >> 1);
1252 	if (data[5] & 0x01)
1253 		printf("\t\t\t Connected to Mesh Gate\n");
1254 	if (data[5] & 0x80)
1255 		printf("\t\t\t Connected to AS\n");
1256 	printf("\t\t * Mesh Capability\n");
1257 	if (data[6] & 0x01)
1258 		printf("\t\t\t Accepting Additional Mesh Peerings\n");
1259 	if (data[6] & 0x02)
1260 		printf("\t\t\t MCCA Supported\n");
1261 	if (data[6] & 0x04)
1262 		printf("\t\t\t MCCA Enabled\n");
1263 	if (data[6] & 0x08)
1264 		printf("\t\t\t Forwarding\n");
1265 	if (data[6] & 0x10)
1266 		printf("\t\t\t MBCA Supported\n");
1267 	if (data[6] & 0x20)
1268 		printf("\t\t\t TBTT Adjusting\n");
1269 	if (data[6] & 0x40)
1270 		printf("\t\t\t Mesh Power Save Level\n");
1271 }
1272 
1273 struct ie_print {
1274 	const char *name;
1275 	void (*print)(const uint8_t type, uint8_t len, const uint8_t *data);
1276 	uint8_t minlen, maxlen;
1277 	uint8_t flags;
1278 };
1279 
print_ie(const struct ie_print * p,const uint8_t type,uint8_t len,const uint8_t * data)1280 static void print_ie(const struct ie_print *p, const uint8_t type,
1281 		     uint8_t len, const uint8_t *data)
1282 {
1283 	int i;
1284 
1285 	if (!p->print)
1286 		return;
1287 
1288 	printf("\t%s:", p->name);
1289 	if (len < p->minlen || len > p->maxlen) {
1290 		if (len > 1) {
1291 			printf(" <invalid: %d bytes:", len);
1292 			for (i = 0; i < len; i++)
1293 				printf(" %.02x", data[i]);
1294 			printf(">\n");
1295 		} else if (len)
1296 			printf(" <invalid: 1 byte: %.02x>\n", data[0]);
1297 		else
1298 			printf(" <invalid: no data>\n");
1299 		return;
1300 	}
1301 
1302 	p->print(type, len, data);
1303 }
1304 
1305 #define PRINT_IGN {		\
1306 	.name = "IGNORE",	\
1307 	.print = NULL,		\
1308 	.minlen = 0,		\
1309 	.maxlen = 255,		\
1310 }
1311 
1312 static const struct ie_print ieprinters[] = {
1313 	[0] = { "SSID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
1314 	[1] = { "Supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), },
1315 	[3] = { "DS Parameter set", print_ds, 1, 1, BIT(PRINT_SCAN), },
1316 	[5] = { "TIM", print_tim, 4, 255, BIT(PRINT_SCAN), },
1317 	[6] = { "IBSS ATIM window", print_ibssatim, 2, 2, BIT(PRINT_SCAN), },
1318 	[7] = { "Country", print_country, 3, 255, BIT(PRINT_SCAN), },
1319 	[11] = { "BSS Load", print_bss_load, 5, 5, BIT(PRINT_SCAN), },
1320 	[32] = { "Power constraint", print_powerconstraint, 1, 1, BIT(PRINT_SCAN), },
1321 	[35] = { "TPC report", print_tpcreport, 2, 2, BIT(PRINT_SCAN), },
1322 	[42] = { "ERP", print_erp, 1, 255, BIT(PRINT_SCAN), },
1323 	[45] = { "HT capabilities", print_ht_capa, 26, 26, BIT(PRINT_SCAN), },
1324 	[47] = { "ERP D4.0", print_erp, 1, 255, BIT(PRINT_SCAN), },
1325 	[74] = { "Overlapping BSS scan params", print_obss_scan_params, 14, 255, BIT(PRINT_SCAN), },
1326 	[61] = { "HT operation", print_ht_op, 22, 22, BIT(PRINT_SCAN), },
1327 	[62] = { "Secondary Channel Offset", print_secchan_offs, 1, 1, BIT(PRINT_SCAN), },
1328 	[191] = { "VHT capabilities", print_vht_capa, 12, 255, BIT(PRINT_SCAN), },
1329 	[192] = { "VHT operation", print_vht_oper, 5, 255, BIT(PRINT_SCAN), },
1330 	[48] = { "RSN", print_rsn, 2, 255, BIT(PRINT_SCAN), },
1331 	[50] = { "Extended supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), },
1332 	[113] = { "MESH Configuration", print_mesh_conf, 7, 7, BIT(PRINT_SCAN), },
1333 	[114] = { "MESH ID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
1334 	[127] = { "Extended capabilities", print_capabilities, 0, 255, BIT(PRINT_SCAN), },
1335 	[107] = { "802.11u Interworking", print_interworking, 0, 255, BIT(PRINT_SCAN), },
1336 	[108] = { "802.11u Advertisement", print_11u_advert, 0, 255, BIT(PRINT_SCAN), },
1337 	[111] = { "802.11u Roaming Consortium", print_11u_rcon, 0, 255, BIT(PRINT_SCAN), },
1338 };
1339 
print_wifi_wpa(const uint8_t type,uint8_t len,const uint8_t * data)1340 static void print_wifi_wpa(const uint8_t type, uint8_t len, const uint8_t *data)
1341 {
1342 	print_rsn_ie("TKIP", "IEEE 802.1X", len, data);
1343 }
1344 
print_wifi_osen(const uint8_t type,uint8_t len,const uint8_t * data)1345 static void print_wifi_osen(const uint8_t type, uint8_t len, const uint8_t *data)
1346 {
1347 	print_osen_ie("OSEN", "OSEN", len, data);
1348 }
1349 
print_wifi_wmm_param(const uint8_t * data,uint8_t len)1350 static bool print_wifi_wmm_param(const uint8_t *data, uint8_t len)
1351 {
1352 	int i;
1353 	static const char *aci_tbl[] = { "BE", "BK", "VI", "VO" };
1354 
1355 	if (len < 19)
1356 		goto invalid;
1357 
1358 	if (data[0] != 1) {
1359 		printf("Parameter: not version 1: ");
1360 		return false;
1361 	}
1362 
1363 	printf("\t * Parameter version 1");
1364 
1365 	data++;
1366 
1367 	if (data[0] & 0x80)
1368 		printf("\n\t\t * u-APSD");
1369 
1370 	data += 2;
1371 
1372 	for (i = 0; i < 4; i++) {
1373 		printf("\n\t\t * %s:", aci_tbl[(data[0] >> 5) & 3]);
1374 		if (data[0] & 0x10)
1375 			printf(" acm");
1376 		printf(" CW %d-%d", (1 << (data[1] & 0xf)) - 1,
1377 				    (1 << (data[1] >> 4)) - 1);
1378 		printf(", AIFSN %d", data[0] & 0xf);
1379 		if (data[2] | data[3])
1380 			printf(", TXOP %d usec", (data[2] + (data[3] << 8)) * 32);
1381 		data += 4;
1382 	}
1383 
1384 	printf("\n");
1385 	return true;
1386 
1387  invalid:
1388  	printf("invalid: ");
1389  	return false;
1390 }
1391 
print_wifi_wmm(const uint8_t type,uint8_t len,const uint8_t * data)1392 static void print_wifi_wmm(const uint8_t type, uint8_t len, const uint8_t *data)
1393 {
1394 	int i;
1395 
1396 	switch (data[0]) {
1397 	case 0x00:
1398 		printf(" information:");
1399 		break;
1400 	case 0x01:
1401 		if (print_wifi_wmm_param(data + 1, len - 1))
1402 			return;
1403 		break;
1404 	default:
1405 		printf(" type %d:", data[0]);
1406 		break;
1407 	}
1408 
1409 	for(i = 1; i < len; i++)
1410 		printf(" %.02x", data[i]);
1411 	printf("\n");
1412 }
1413 
wifi_wps_dev_passwd_id(uint16_t id)1414 static const char * wifi_wps_dev_passwd_id(uint16_t id)
1415 {
1416 	switch (id) {
1417 	case 0:
1418 		return "Default (PIN)";
1419 	case 1:
1420 		return "User-specified";
1421 	case 2:
1422 		return "Machine-specified";
1423 	case 3:
1424 		return "Rekey";
1425 	case 4:
1426 		return "PushButton";
1427 	case 5:
1428 		return "Registrar-specified";
1429 	default:
1430 		return "??";
1431 	}
1432 }
1433 
print_wifi_wps(const uint8_t type,uint8_t len,const uint8_t * data)1434 static void print_wifi_wps(const uint8_t type, uint8_t len, const uint8_t *data)
1435 {
1436 	bool first = true;
1437 	__u16 subtype, sublen;
1438 
1439 	while (len >= 4) {
1440 		subtype = (data[0] << 8) + data[1];
1441 		sublen = (data[2] << 8) + data[3];
1442 		if (sublen > len)
1443 			break;
1444 
1445 		switch (subtype) {
1446 		case 0x104a:
1447 			tab_on_first(&first);
1448 			printf("\t * Version: %d.%d\n", data[4] >> 4, data[4] & 0xF);
1449 			break;
1450 		case 0x1011:
1451 			tab_on_first(&first);
1452 			printf("\t * Device name: %.*s\n", sublen, data + 4);
1453 			break;
1454 		case 0x1012: {
1455 			uint16_t id;
1456 			tab_on_first(&first);
1457 			if (sublen != 2) {
1458 				printf("\t * Device Password ID: (invalid "
1459 				       "length %d)\n", sublen);
1460 				break;
1461 			}
1462 			id = data[4] << 8 | data[5];
1463 			printf("\t * Device Password ID: %u (%s)\n",
1464 			       id, wifi_wps_dev_passwd_id(id));
1465 			break;
1466 		}
1467 		case 0x1021:
1468 			tab_on_first(&first);
1469 			printf("\t * Manufacturer: %.*s\n", sublen, data + 4);
1470 			break;
1471 		case 0x1023:
1472 			tab_on_first(&first);
1473 			printf("\t * Model: %.*s\n", sublen, data + 4);
1474 			break;
1475 		case 0x1024:
1476 			tab_on_first(&first);
1477 			printf("\t * Model Number: %.*s\n", sublen, data + 4);
1478 			break;
1479 		case 0x103b: {
1480 			__u8 val = data[4];
1481 			tab_on_first(&first);
1482 			printf("\t * Response Type: %d%s\n",
1483 			       val, val == 3 ? " (AP)" : "");
1484 			break;
1485 		}
1486 		case 0x103c: {
1487 			__u8 val = data[4];
1488 			tab_on_first(&first);
1489 			printf("\t * RF Bands: 0x%x\n", val);
1490 			break;
1491 		}
1492 		case 0x1041: {
1493 			__u8 val = data[4];
1494 			tab_on_first(&first);
1495 			printf("\t * Selected Registrar: 0x%x\n", val);
1496 			break;
1497 		}
1498 		case 0x1042:
1499 			tab_on_first(&first);
1500 			printf("\t * Serial Number: %.*s\n", sublen, data + 4);
1501 			break;
1502 		case 0x1044: {
1503 			__u8 val = data[4];
1504 			tab_on_first(&first);
1505 			printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1506 			       val,
1507 			       val == 1 ? " (Unconfigured)" : "",
1508 			       val == 2 ? " (Configured)" : "");
1509 			break;
1510 		}
1511 		case 0x1047:
1512 			tab_on_first(&first);
1513 			printf("\t * UUID: ");
1514 			if (sublen != 16) {
1515 				printf("(invalid, length=%d)\n", sublen);
1516 				break;
1517 			}
1518 			printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1519 				"%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1520 				data[4], data[5], data[6], data[7],
1521 				data[8], data[9], data[10], data[11],
1522 				data[12], data[13], data[14], data[15],
1523 				data[16], data[17], data[18], data[19]);
1524 			break;
1525 		case 0x1054: {
1526 			tab_on_first(&first);
1527 			if (sublen != 8) {
1528 				printf("\t * Primary Device Type: (invalid "
1529 				       "length %d)\n", sublen);
1530 				break;
1531 			}
1532 			printf("\t * Primary Device Type: "
1533 			       "%u-%02x%02x%02x%02x-%u\n",
1534 			       data[4] << 8 | data[5],
1535 			       data[6], data[7], data[8], data[9],
1536 			       data[10] << 8 | data[11]);
1537 			break;
1538 		}
1539 		case 0x1057: {
1540 			__u8 val = data[4];
1541 			tab_on_first(&first);
1542 			printf("\t * AP setup locked: 0x%.2x\n", val);
1543 			break;
1544 		}
1545 		case 0x1008:
1546 		case 0x1053: {
1547 			__u16 meth = (data[4] << 8) + data[5];
1548 			bool comma = false;
1549 			tab_on_first(&first);
1550 			printf("\t * %sConfig methods:",
1551 			       subtype == 0x1053 ? "Selected Registrar ": "");
1552 #define T(bit, name) do {		\
1553 	if (meth & (1<<bit)) {		\
1554 		if (comma)		\
1555 			printf(",");	\
1556 		comma = true;		\
1557 		printf(" " name);	\
1558 	} } while (0)
1559 			T(0, "USB");
1560 			T(1, "Ethernet");
1561 			T(2, "Label");
1562 			T(3, "Display");
1563 			T(4, "Ext. NFC");
1564 			T(5, "Int. NFC");
1565 			T(6, "NFC Intf.");
1566 			T(7, "PBC");
1567 			T(8, "Keypad");
1568 			printf("\n");
1569 			break;
1570 #undef T
1571 		}
1572 		default: {
1573 			const __u8 *subdata = data + 4;
1574 			__u16 tmplen = sublen;
1575 
1576 			tab_on_first(&first);
1577 			printf("\t * Unknown TLV (%#.4x, %d bytes):",
1578 			       subtype, tmplen);
1579 			while (tmplen) {
1580 				printf(" %.2x", *subdata);
1581 				subdata++;
1582 				tmplen--;
1583 			}
1584 			printf("\n");
1585 			break;
1586 		}
1587 		}
1588 
1589 		data += sublen + 4;
1590 		len -= sublen + 4;
1591 	}
1592 
1593 	if (len != 0) {
1594 		printf("\t\t * bogus tail data (%d):", len);
1595 		while (len) {
1596 			printf(" %.2x", *data);
1597 			data++;
1598 			len--;
1599 		}
1600 		printf("\n");
1601 	}
1602 }
1603 
1604 static const struct ie_print wifiprinters[] = {
1605 	[1] = { "WPA", print_wifi_wpa, 2, 255, BIT(PRINT_SCAN), },
1606 	[2] = { "WMM", print_wifi_wmm, 1, 255, BIT(PRINT_SCAN), },
1607 	[4] = { "WPS", print_wifi_wps, 0, 255, BIT(PRINT_SCAN), },
1608 };
1609 
print_p2p(const uint8_t type,uint8_t len,const uint8_t * data)1610 static inline void print_p2p(const uint8_t type, uint8_t len, const uint8_t *data)
1611 {
1612 	bool first = true;
1613 	__u8 subtype;
1614 	__u16 sublen;
1615 
1616 	while (len >= 3) {
1617 		subtype = data[0];
1618 		sublen = (data[2] << 8) + data[1];
1619 
1620 		if (sublen > len - 3)
1621 			break;
1622 
1623 		switch (subtype) {
1624 		case 0x02: /* capability */
1625 			tab_on_first(&first);
1626 			if (sublen < 2) {
1627 				printf("\t * malformed capability\n");
1628 				break;
1629 			}
1630 			printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
1631 				data[3], data[4]);
1632 			break;
1633 		case 0x0d: /* device info */
1634 			if (sublen < 6 + 2 + 8 + 1) {
1635 				printf("\t * malformed device info\n");
1636 				break;
1637 			}
1638 			/* fall through for now */
1639 		case 0x00: /* status */
1640 		case 0x01: /* minor reason */
1641 		case 0x03: /* device ID */
1642 		case 0x04: /* GO intent */
1643 		case 0x05: /* configuration timeout */
1644 		case 0x06: /* listen channel */
1645 		case 0x07: /* group BSSID */
1646 		case 0x08: /* ext listen timing */
1647 		case 0x09: /* intended interface address */
1648 		case 0x0a: /* manageability */
1649 		case 0x0b: /* channel list */
1650 		case 0x0c: /* NoA */
1651 		case 0x0e: /* group info */
1652 		case 0x0f: /* group ID */
1653 		case 0x10: /* interface */
1654 		case 0x11: /* operating channel */
1655 		case 0x12: /* invitation flags */
1656 		case 0xdd: /* vendor specific */
1657 		default: {
1658 			const __u8 *subdata = data + 4;
1659 			__u16 tmplen = sublen;
1660 
1661 			tab_on_first(&first);
1662 			printf("\t * Unknown TLV (%#.2x, %d bytes):",
1663 			       subtype, tmplen);
1664 			while (tmplen) {
1665 				printf(" %.2x", *subdata);
1666 				subdata++;
1667 				tmplen--;
1668 			}
1669 			printf("\n");
1670 			break;
1671 		}
1672 		}
1673 
1674 		data += sublen + 3;
1675 		len -= sublen + 3;
1676 	}
1677 
1678 	if (len != 0) {
1679 		tab_on_first(&first);
1680 		printf("\t * bogus tail data (%d):", len);
1681 		while (len) {
1682 			printf(" %.2x", *data);
1683 			data++;
1684 			len--;
1685 		}
1686 		printf("\n");
1687 	}
1688 }
1689 
print_hs20_ind(const uint8_t type,uint8_t len,const uint8_t * data)1690 static inline void print_hs20_ind(const uint8_t type, uint8_t len, const uint8_t *data)
1691 {
1692 	/* I can't find the spec for this...just going off what wireshark uses. */
1693 	printf("\n");
1694 	if (len > 0)
1695 		printf("\t\tDGAF: %i\n", (int)(data[0] & 0x1));
1696 	else
1697 		printf("\t\tUnexpected length: %i\n", len);
1698 }
1699 
1700 static const struct ie_print wfa_printers[] = {
1701 	[9] = { "P2P", print_p2p, 2, 255, BIT(PRINT_SCAN), },
1702 	[16] = { "HotSpot 2.0 Indication", print_hs20_ind, 1, 255, BIT(PRINT_SCAN), },
1703 	[18] = { "HotSpot 2.0 OSEN", print_wifi_osen, 1, 255, BIT(PRINT_SCAN), },
1704 };
1705 
print_vendor(unsigned char len,unsigned char * data,bool unknown,enum print_ie_type ptype)1706 static void print_vendor(unsigned char len, unsigned char *data,
1707 			 bool unknown, enum print_ie_type ptype)
1708 {
1709 	int i;
1710 
1711 	if (len < 3) {
1712 		printf("\tVendor specific: <too short> data:");
1713 		for(i = 0; i < len; i++)
1714 			printf(" %.02x", data[i]);
1715 		printf("\n");
1716 		return;
1717 	}
1718 
1719 	if (len >= 4 && memcmp(data, ms_oui, 3) == 0) {
1720 		if (data[3] < ARRAY_SIZE(wifiprinters) &&
1721 		    wifiprinters[data[3]].name &&
1722 		    wifiprinters[data[3]].flags & BIT(ptype)) {
1723 			print_ie(&wifiprinters[data[3]], data[3], len - 4, data + 4);
1724 			return;
1725 		}
1726 		if (!unknown)
1727 			return;
1728 		printf("\tMS/WiFi %#.2x, data:", data[3]);
1729 		for(i = 0; i < len - 4; i++)
1730 			printf(" %.02x", data[i + 4]);
1731 		printf("\n");
1732 		return;
1733 	}
1734 
1735 	if (len >= 4 && memcmp(data, wfa_oui, 3) == 0) {
1736 		if (data[3] < ARRAY_SIZE(wfa_printers) &&
1737 		    wfa_printers[data[3]].name &&
1738 		    wfa_printers[data[3]].flags & BIT(ptype)) {
1739 			print_ie(&wfa_printers[data[3]], data[3], len - 4, data + 4);
1740 			return;
1741 		}
1742 		if (!unknown)
1743 			return;
1744 		printf("\tWFA %#.2x, data:", data[3]);
1745 		for(i = 0; i < len - 4; i++)
1746 			printf(" %.02x", data[i + 4]);
1747 		printf("\n");
1748 		return;
1749 	}
1750 
1751 	if (!unknown)
1752 		return;
1753 
1754 	printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
1755 		data[0], data[1], data[2]);
1756 	for (i = 3; i < len; i++)
1757 		printf(" %.2x", data[i]);
1758 	printf("\n");
1759 }
1760 
print_ies(unsigned char * ie,int ielen,bool unknown,enum print_ie_type ptype)1761 void print_ies(unsigned char *ie, int ielen, bool unknown,
1762 	       enum print_ie_type ptype)
1763 {
1764 	while (ielen >= 2 && ielen >= ie[1]) {
1765 		if (ie[0] < ARRAY_SIZE(ieprinters) &&
1766 		    ieprinters[ie[0]].name &&
1767 		    ieprinters[ie[0]].flags & BIT(ptype)) {
1768 			print_ie(&ieprinters[ie[0]], ie[0], ie[1], ie + 2);
1769 		} else if (ie[0] == 221 /* vendor */) {
1770 			print_vendor(ie[1], ie + 2, unknown, ptype);
1771 		} else if (unknown) {
1772 			int i;
1773 
1774 			printf("\tUnknown IE (%d):", ie[0]);
1775 			for (i=0; i<ie[1]; i++)
1776 				printf(" %.2x", ie[2+i]);
1777 			printf("\n");
1778 		}
1779 		ielen -= ie[1] + 2;
1780 		ie += ie[1] + 2;
1781 	}
1782 }
1783 
print_capa_dmg(__u16 capa)1784 static void print_capa_dmg(__u16 capa)
1785 {
1786 	switch (capa & WLAN_CAPABILITY_DMG_TYPE_MASK) {
1787 	case WLAN_CAPABILITY_DMG_TYPE_AP:
1788 		printf(" DMG_ESS");
1789 		break;
1790 	case WLAN_CAPABILITY_DMG_TYPE_PBSS:
1791 		printf(" DMG_PCP");
1792 		break;
1793 	case WLAN_CAPABILITY_DMG_TYPE_IBSS:
1794 		printf(" DMG_IBSS");
1795 		break;
1796 	}
1797 
1798 	if (capa & WLAN_CAPABILITY_DMG_CBAP_ONLY)
1799 		printf(" CBAP_Only");
1800 	if (capa & WLAN_CAPABILITY_DMG_CBAP_SOURCE)
1801 		printf(" CBAP_Src");
1802 	if (capa & WLAN_CAPABILITY_DMG_PRIVACY)
1803 		printf(" Privacy");
1804 	if (capa & WLAN_CAPABILITY_DMG_ECPAC)
1805 		printf(" ECPAC");
1806 	if (capa & WLAN_CAPABILITY_DMG_SPECTRUM_MGMT)
1807 		printf(" SpectrumMgmt");
1808 	if (capa & WLAN_CAPABILITY_DMG_RADIO_MEASURE)
1809 		printf(" RadioMeasure");
1810 }
1811 
print_capa_non_dmg(__u16 capa)1812 static void print_capa_non_dmg(__u16 capa)
1813 {
1814 	if (capa & WLAN_CAPABILITY_ESS)
1815 		printf(" ESS");
1816 	if (capa & WLAN_CAPABILITY_IBSS)
1817 		printf(" IBSS");
1818 	if (capa & WLAN_CAPABILITY_CF_POLLABLE)
1819 		printf(" CfPollable");
1820 	if (capa & WLAN_CAPABILITY_CF_POLL_REQUEST)
1821 		printf(" CfPollReq");
1822 	if (capa & WLAN_CAPABILITY_PRIVACY)
1823 		printf(" Privacy");
1824 	if (capa & WLAN_CAPABILITY_SHORT_PREAMBLE)
1825 		printf(" ShortPreamble");
1826 	if (capa & WLAN_CAPABILITY_PBCC)
1827 		printf(" PBCC");
1828 	if (capa & WLAN_CAPABILITY_CHANNEL_AGILITY)
1829 		printf(" ChannelAgility");
1830 	if (capa & WLAN_CAPABILITY_SPECTRUM_MGMT)
1831 		printf(" SpectrumMgmt");
1832 	if (capa & WLAN_CAPABILITY_QOS)
1833 		printf(" QoS");
1834 	if (capa & WLAN_CAPABILITY_SHORT_SLOT_TIME)
1835 		printf(" ShortSlotTime");
1836 	if (capa & WLAN_CAPABILITY_APSD)
1837 		printf(" APSD");
1838 	if (capa & WLAN_CAPABILITY_RADIO_MEASURE)
1839 		printf(" RadioMeasure");
1840 	if (capa & WLAN_CAPABILITY_DSSS_OFDM)
1841 		printf(" DSSS-OFDM");
1842 	if (capa & WLAN_CAPABILITY_DEL_BACK)
1843 		printf(" DelayedBACK");
1844 	if (capa & WLAN_CAPABILITY_IMM_BACK)
1845 		printf(" ImmediateBACK");
1846 }
1847 
print_bss_handler(struct nl_msg * msg,void * arg)1848 static int print_bss_handler(struct nl_msg *msg, void *arg)
1849 {
1850 	struct nlattr *tb[NL80211_ATTR_MAX + 1];
1851 	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1852 	struct nlattr *bss[NL80211_BSS_MAX + 1];
1853 	char mac_addr[20], dev[20];
1854 	static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
1855 		[NL80211_BSS_TSF] = { .type = NLA_U64 },
1856 		[NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
1857 		[NL80211_BSS_BSSID] = { },
1858 		[NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
1859 		[NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
1860 		[NL80211_BSS_INFORMATION_ELEMENTS] = { },
1861 		[NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
1862 		[NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
1863 		[NL80211_BSS_STATUS] = { .type = NLA_U32 },
1864 		[NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
1865 		[NL80211_BSS_BEACON_IES] = { },
1866 	};
1867 	struct scan_params *params = arg;
1868 	int show = params->show_both_ie_sets ? 2 : 1;
1869 	bool is_dmg = false;
1870 
1871 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1872 		  genlmsg_attrlen(gnlh, 0), NULL);
1873 
1874 	if (!tb[NL80211_ATTR_BSS]) {
1875 		fprintf(stderr, "bss info missing!\n");
1876 		return NL_SKIP;
1877 	}
1878 	if (nla_parse_nested(bss, NL80211_BSS_MAX,
1879 			     tb[NL80211_ATTR_BSS],
1880 			     bss_policy)) {
1881 		fprintf(stderr, "failed to parse nested attributes!\n");
1882 		return NL_SKIP;
1883 	}
1884 
1885 	if (!bss[NL80211_BSS_BSSID])
1886 		return NL_SKIP;
1887 
1888 	mac_addr_n2a(mac_addr, nla_data(bss[NL80211_BSS_BSSID]));
1889 	printf("BSS %s", mac_addr);
1890 	if (tb[NL80211_ATTR_IFINDEX]) {
1891 		if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
1892 		printf("(on %s)", dev);
1893 	}
1894 
1895 	if (bss[NL80211_BSS_STATUS]) {
1896 		switch (nla_get_u32(bss[NL80211_BSS_STATUS])) {
1897 		case NL80211_BSS_STATUS_AUTHENTICATED:
1898 			printf(" -- authenticated");
1899 			break;
1900 		case NL80211_BSS_STATUS_ASSOCIATED:
1901 			printf(" -- associated");
1902 			break;
1903 		case NL80211_BSS_STATUS_IBSS_JOINED:
1904 			printf(" -- joined");
1905 			break;
1906 		default:
1907 			printf(" -- unknown status: %d",
1908 				nla_get_u32(bss[NL80211_BSS_STATUS]));
1909 			break;
1910 		}
1911 	}
1912 	printf("\n");
1913 
1914 	if (bss[NL80211_BSS_TSF]) {
1915 		unsigned long long tsf;
1916 		tsf = (unsigned long long)nla_get_u64(bss[NL80211_BSS_TSF]);
1917 		printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
1918 			tsf, tsf/1000/1000/60/60/24, (tsf/1000/1000/60/60) % 24,
1919 			(tsf/1000/1000/60) % 60, (tsf/1000/1000) % 60);
1920 	}
1921 	if (bss[NL80211_BSS_FREQUENCY]) {
1922 		int freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
1923 		printf("\tfreq: %d\n", freq);
1924 		if (freq > 45000)
1925 			is_dmg = true;
1926 	}
1927 	if (bss[NL80211_BSS_BEACON_INTERVAL])
1928 		printf("\tbeacon interval: %d TUs\n",
1929 			nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]));
1930 	if (bss[NL80211_BSS_CAPABILITY]) {
1931 		__u16 capa = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
1932 		printf("\tcapability:");
1933 		if (is_dmg)
1934 			print_capa_dmg(capa);
1935 		else
1936 			print_capa_non_dmg(capa);
1937 		printf(" (0x%.4x)\n", capa);
1938 	}
1939 	if (bss[NL80211_BSS_SIGNAL_MBM]) {
1940 		int s = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
1941 		printf("\tsignal: %d.%.2d dBm\n", s/100, s%100);
1942 	}
1943 	if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
1944 		unsigned char s = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
1945 		printf("\tsignal: %d/100\n", s);
1946 	}
1947 	if (bss[NL80211_BSS_SEEN_MS_AGO]) {
1948 		int age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
1949 		printf("\tlast seen: %d ms ago\n", age);
1950 	}
1951 
1952 	if (bss[NL80211_BSS_INFORMATION_ELEMENTS] && show--) {
1953 		if (bss[NL80211_BSS_BEACON_IES])
1954 			printf("\tInformation elements from Probe Response "
1955 			       "frame:\n");
1956 		print_ies(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
1957 			  nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
1958 			  params->unknown, params->type);
1959 	}
1960 	if (bss[NL80211_BSS_BEACON_IES] && show--) {
1961 		printf("\tInformation elements from Beacon frame:\n");
1962 		print_ies(nla_data(bss[NL80211_BSS_BEACON_IES]),
1963 			  nla_len(bss[NL80211_BSS_BEACON_IES]),
1964 			  params->unknown, params->type);
1965 	}
1966 
1967 	return NL_SKIP;
1968 }
1969 
1970 static struct scan_params scan_params;
1971 
handle_scan_dump(struct nl80211_state * state,struct nl_cb * cb,struct nl_msg * msg,int argc,char ** argv,enum id_input id)1972 static int handle_scan_dump(struct nl80211_state *state,
1973 			    struct nl_cb *cb,
1974 			    struct nl_msg *msg,
1975 			    int argc, char **argv,
1976 			    enum id_input id)
1977 {
1978 	if (argc > 1)
1979 		return 1;
1980 
1981 	memset(&scan_params, 0, sizeof(scan_params));
1982 
1983 	if (argc == 1 && !strcmp(argv[0], "-u"))
1984 		scan_params.unknown = true;
1985 	else if (argc == 1 && !strcmp(argv[0], "-b"))
1986 		scan_params.show_both_ie_sets = true;
1987 
1988 	scan_params.type = PRINT_SCAN;
1989 
1990 	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_bss_handler,
1991 		  &scan_params);
1992 	return 0;
1993 }
1994 
handle_scan_combined(struct nl80211_state * state,struct nl_cb * cb,struct nl_msg * msg,int argc,char ** argv,enum id_input id)1995 static int handle_scan_combined(struct nl80211_state *state,
1996 				struct nl_cb *cb,
1997 				struct nl_msg *msg,
1998 				int argc, char **argv,
1999 				enum id_input id)
2000 {
2001 	char **trig_argv;
2002 	static char *dump_argv[] = {
2003 		NULL,
2004 		"scan",
2005 		"dump",
2006 		NULL,
2007 	};
2008 	static const __u32 cmds[] = {
2009 		NL80211_CMD_NEW_SCAN_RESULTS,
2010 		NL80211_CMD_SCAN_ABORTED,
2011 	};
2012 	int trig_argc, dump_argc, err;
2013 
2014 	if (argc >= 3 && !strcmp(argv[2], "-u")) {
2015 		dump_argc = 4;
2016 		dump_argv[3] = "-u";
2017 	} else if (argc >= 3 && !strcmp(argv[2], "-b")) {
2018 		dump_argc = 4;
2019 		dump_argv[3] = "-b";
2020 	} else
2021 		dump_argc = 3;
2022 
2023 	trig_argc = 3 + (argc - 2) + (3 - dump_argc);
2024 	trig_argv = calloc(trig_argc, sizeof(*trig_argv));
2025 	if (!trig_argv)
2026 		return -ENOMEM;
2027 	trig_argv[0] = argv[0];
2028 	trig_argv[1] = "scan";
2029 	trig_argv[2] = "trigger";
2030 	int i;
2031 	for (i = 0; i < argc - 2 - (dump_argc - 3); i++)
2032 		trig_argv[i + 3] = argv[i + 2 + (dump_argc - 3)];
2033 	err = handle_cmd(state, id, trig_argc, trig_argv);
2034 	free(trig_argv);
2035 	if (err)
2036 		return err;
2037 
2038 	/*
2039 	 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
2040 	 *
2041 	 * This code has a bug, which requires creating a separate
2042 	 * nl80211 socket to fix:
2043 	 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
2044 	 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
2045 	 * before (!) we listen to it, because we only start listening
2046 	 * after we send our scan request.
2047 	 *
2048 	 * Doing it the other way around has a race condition as well,
2049 	 * if you first open the events socket you may get a notification
2050 	 * for a previous scan.
2051 	 *
2052 	 * The only proper way to fix this would be to listen to events
2053 	 * before sending the command, and for the kernel to send the
2054 	 * scan request along with the event, so that you can match up
2055 	 * whether the scan you requested was finished or aborted (this
2056 	 * may result in processing a scan that another application
2057 	 * requested, but that doesn't seem to be a problem).
2058 	 *
2059 	 * Alas, the kernel doesn't do that (yet).
2060 	 */
2061 
2062 	if (listen_events(state, ARRAY_SIZE(cmds), cmds) ==
2063 					NL80211_CMD_SCAN_ABORTED) {
2064 		printf("scan aborted!\n");
2065 		return 0;
2066 	}
2067 
2068 	dump_argv[0] = argv[0];
2069 	return handle_cmd(state, id, dump_argc, dump_argv);
2070 }
2071 TOPLEVEL(scan, "[-u] [freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]", 0, 0,
2072 	 CIB_NETDEV, handle_scan_combined,
2073 	 "Scan on the given frequencies and probe for the given SSIDs\n"
2074 	 "(or wildcard if not given) unless passive scanning is requested.\n"
2075 	 "If -u is specified print unknown data in the scan results.\n"
2076 	 "Specified (vendor) IEs must be well-formed.");
2077 COMMAND(scan, dump, "[-u]",
2078 	NL80211_CMD_GET_SCAN, NLM_F_DUMP, CIB_NETDEV, handle_scan_dump,
2079 	"Dump the current scan results. If -u is specified, print unknown\n"
2080 	"data in scan results.");
2081 COMMAND(scan, trigger, "[freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]",
2082 	NL80211_CMD_TRIGGER_SCAN, 0, CIB_NETDEV, handle_scan,
2083 	 "Trigger a scan on the given frequencies with probing for the given\n"
2084 	 "SSIDs (or wildcard if not given) unless passive scanning is requested.");
2085 
2086 
handle_start_sched_scan(struct nl80211_state * state,struct nl_cb * cb,struct nl_msg * msg,int argc,char ** argv,enum id_input id)2087 static int handle_start_sched_scan(struct nl80211_state *state,
2088 				   struct nl_cb *cb, struct nl_msg *msg,
2089 				   int argc, char **argv, enum id_input id)
2090 {
2091 	return parse_sched_scan(msg, &argc, &argv);
2092 }
2093 
handle_stop_sched_scan(struct nl80211_state * state,struct nl_cb * cb,struct nl_msg * msg,int argc,char ** argv,enum id_input id)2094 static int handle_stop_sched_scan(struct nl80211_state *state, struct nl_cb *cb,
2095 				  struct nl_msg *msg, int argc, char **argv,
2096 				  enum id_input id)
2097 {
2098 	if (argc != 0)
2099 		return 1;
2100 
2101 	return 0;
2102 }
2103 
2104 COMMAND(scan, sched_start,
2105 	SCHED_SCAN_OPTIONS,
2106 	NL80211_CMD_START_SCHED_SCAN, 0, CIB_NETDEV, handle_start_sched_scan,
2107 	"Start a scheduled scan at the specified interval on the given frequencies\n"
2108 	"with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2109 	"scanning is requested.  If matches are specified, only matching results\n"
2110 	"will be returned.");
2111 COMMAND(scan, sched_stop, "",
2112 	NL80211_CMD_STOP_SCHED_SCAN, 0, CIB_NETDEV, handle_stop_sched_scan,
2113 	"Stop an ongoing scheduled scan.");
2114