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