scan.c revision 4361eef308869ae41395c8b32c5d9aa68d28e5aa
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
48static unsigned char ms_oui[3]		= { 0x00, 0x50, 0xf2 };
49static unsigned char ieee80211_oui[3]	= { 0x00, 0x0f, 0xac };
50static unsigned char wfa_oui[3]		= { 0x50, 0x6f, 0x9a };
51
52struct 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
60union 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
73static int handle_scan(struct nl80211_state *state,
74		       struct nl_cb *cb,
75		       struct nl_msg *msg,
76		       int argc, char **argv,
77		       enum id_input id)
78{
79	struct nl_msg *ssids = NULL, *freqs = NULL;
80	char *eptr;
81	int err = -ENOBUFS;
82	int i;
83	enum {
84		NONE,
85		FREQ,
86		IES,
87		SSID,
88		MESHID,
89		DONE,
90	} parse = NONE;
91	int freq;
92	bool passive = false, have_ssids = false, have_freqs = false;
93	size_t ies_len = 0, meshid_len = 0;
94	unsigned char *ies = NULL, *meshid = NULL, *tmpies;
95	int flags = 0;
96
97	ssids = nlmsg_alloc();
98	if (!ssids)
99		return -ENOMEM;
100
101	freqs = nlmsg_alloc();
102	if (!freqs) {
103		nlmsg_free(ssids);
104		return -ENOMEM;
105	}
106
107	for (i = 0; i < argc; i++) {
108		switch (parse) {
109		case NONE:
110			if (strcmp(argv[i], "freq") == 0) {
111				parse = FREQ;
112				have_freqs = true;
113				break;
114			} else if (strcmp(argv[i], "ies") == 0) {
115				parse = IES;
116				break;
117			} else if (strcmp(argv[i], "lowpri") == 0) {
118				parse = NONE;
119				flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
120				break;
121			} else if (strcmp(argv[i], "flush") == 0) {
122				parse = NONE;
123				flags |= NL80211_SCAN_FLAG_FLUSH;
124				break;
125			} else if (strcmp(argv[i], "ap-force") == 0) {
126				parse = NONE;
127				flags |= NL80211_SCAN_FLAG_AP;
128				break;
129			} else if (strcmp(argv[i], "ssid") == 0) {
130				parse = SSID;
131				have_ssids = true;
132				break;
133			} else if (strcmp(argv[i], "passive") == 0) {
134				parse = DONE;
135				passive = true;
136				break;
137			} else if (strcmp(argv[i], "meshid") == 0) {
138				parse = MESHID;
139				break;
140			}
141		case DONE:
142			return 1;
143		case FREQ:
144			freq = strtoul(argv[i], &eptr, 10);
145			if (eptr != argv[i] + strlen(argv[i])) {
146				/* failed to parse as number -- maybe a tag? */
147				i--;
148				parse = NONE;
149				continue;
150			}
151			NLA_PUT_U32(freqs, i, freq);
152			break;
153		case IES:
154			ies = parse_hex(argv[i], &ies_len);
155			if (!ies)
156				goto nla_put_failure;
157			parse = NONE;
158			break;
159		case SSID:
160			NLA_PUT(ssids, i, strlen(argv[i]), argv[i]);
161			break;
162		case MESHID:
163			meshid_len = strlen(argv[i]);
164			meshid = (unsigned char *) malloc(meshid_len + 2);
165			if (!meshid)
166				goto nla_put_failure;
167			meshid[0] = 114; /* mesh element id */
168			meshid[1] = meshid_len;
169			memcpy(&meshid[2], argv[i], meshid_len);
170			meshid_len += 2;
171			parse = NONE;
172			break;
173		}
174	}
175
176	if (ies || meshid) {
177		tmpies = (unsigned char *) malloc(ies_len + meshid_len);
178		if (!tmpies)
179			goto nla_put_failure;
180		if (ies) {
181			memcpy(tmpies, ies, ies_len);
182			free(ies);
183		}
184		if (meshid) {
185			memcpy(&tmpies[ies_len], meshid, meshid_len);
186			free(meshid);
187		}
188		NLA_PUT(msg, NL80211_ATTR_IE, ies_len + meshid_len, tmpies);
189		free(tmpies);
190	}
191
192	if (!have_ssids)
193		NLA_PUT(ssids, 1, 0, "");
194	if (!passive)
195		nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
196
197	if (have_freqs)
198		nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
199	if (flags)
200		NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, flags);
201
202	err = 0;
203 nla_put_failure:
204	nlmsg_free(ssids);
205	nlmsg_free(freqs);
206	return err;
207}
208
209static void tab_on_first(bool *first)
210{
211	if (!*first)
212		printf("\t");
213	else
214		*first = false;
215}
216
217static void print_ssid(const uint8_t type, uint8_t len, const uint8_t *data)
218{
219	printf(" ");
220	print_ssid_escaped(len, data);
221	printf("\n");
222}
223
224#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
225#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
226
227static void print_supprates(const uint8_t type, uint8_t len, const uint8_t *data)
228{
229	int i;
230
231	printf(" ");
232
233	for (i = 0; i < len; i++) {
234		int r = data[i] & 0x7f;
235
236		if (r == BSS_MEMBERSHIP_SELECTOR_VHT_PHY && data[i] & 0x80)
237			printf("VHT");
238		else if (r == BSS_MEMBERSHIP_SELECTOR_HT_PHY && data[i] & 0x80)
239			printf("HT");
240		else
241			printf("%d.%d", r/2, 5*(r&1));
242
243		printf("%s ", data[i] & 0x80 ? "*" : "");
244	}
245	printf("\n");
246}
247
248static void print_ds(const uint8_t type, uint8_t len, const uint8_t *data)
249{
250	printf(" channel %d\n", data[0]);
251}
252
253static const char *country_env_str(char environment)
254{
255	switch (environment) {
256	case 'I':
257		return "Indoor only";
258	case 'O':
259		return "Outdoor only";
260	case ' ':
261		return "Indoor/Outdoor";
262	default:
263		return "bogus";
264	}
265}
266
267static void print_country(const uint8_t type, uint8_t len, const uint8_t *data)
268{
269	printf(" %.*s", 2, data);
270
271	printf("\tEnvironment: %s\n", country_env_str(data[2]));
272
273	data += 3;
274	len -= 3;
275
276	if (len < 3) {
277		printf("\t\tNo country IE triplets present\n");
278		return;
279	}
280
281	while (len >= 3) {
282		int end_channel;
283		union ieee80211_country_ie_triplet *triplet = (void *) data;
284
285		if (triplet->ext.reg_extension_id >= IEEE80211_COUNTRY_EXTENSION_ID) {
286			printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
287			       triplet->ext.reg_extension_id,
288			       triplet->ext.reg_class,
289			       triplet->ext.coverage_class,
290			       triplet->ext.coverage_class * 450);
291
292			data += 3;
293			len -= 3;
294			continue;
295		}
296
297		/* 2 GHz */
298		if (triplet->chans.first_channel <= 14)
299			end_channel = triplet->chans.first_channel + (triplet->chans.num_channels - 1);
300		else
301			end_channel =  triplet->chans.first_channel + (4 * (triplet->chans.num_channels - 1));
302
303		printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet->chans.first_channel, end_channel, triplet->chans.max_power);
304
305		data += 3;
306		len -= 3;
307	}
308
309	return;
310}
311
312static void print_powerconstraint(const uint8_t type, uint8_t len, const uint8_t *data)
313{
314	printf(" %d dB\n", data[0]);
315}
316
317static void print_tpcreport(const uint8_t type, uint8_t len, const uint8_t *data)
318{
319	printf(" TX power: %d dBm\n", data[0]);
320	/* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
321}
322
323static void print_erp(const uint8_t type, uint8_t len, const uint8_t *data)
324{
325	if (data[0] == 0x00)
326		printf(" <no flags>");
327	if (data[0] & 0x01)
328		printf(" NonERP_Present");
329	if (data[0] & 0x02)
330		printf(" Use_Protection");
331	if (data[0] & 0x04)
332		printf(" Barker_Preamble_Mode");
333	printf("\n");
334}
335
336static void print_cipher(const uint8_t *data)
337{
338	if (memcmp(data, ms_oui, 3) == 0) {
339		switch (data[3]) {
340		case 0:
341			printf("Use group cipher suite");
342			break;
343		case 1:
344			printf("WEP-40");
345			break;
346		case 2:
347			printf("TKIP");
348			break;
349		case 4:
350			printf("CCMP");
351			break;
352		case 5:
353			printf("WEP-104");
354			break;
355		default:
356			printf("%.02x-%.02x-%.02x:%d",
357				data[0], data[1] ,data[2], data[3]);
358			break;
359		}
360	} else if (memcmp(data, ieee80211_oui, 3) == 0) {
361		switch (data[3]) {
362		case 0:
363			printf("Use group cipher suite");
364			break;
365		case 1:
366			printf("WEP-40");
367			break;
368		case 2:
369			printf("TKIP");
370			break;
371		case 4:
372			printf("CCMP");
373			break;
374		case 5:
375			printf("WEP-104");
376			break;
377		case 6:
378			printf("AES-128-CMAC");
379			break;
380		case 8:
381			printf("GCMP");
382			break;
383		default:
384			printf("%.02x-%.02x-%.02x:%d",
385				data[0], data[1] ,data[2], data[3]);
386			break;
387		}
388	} else
389		printf("%.02x-%.02x-%.02x:%d",
390			data[0], data[1] ,data[2], data[3]);
391}
392
393static void print_auth(const uint8_t *data)
394{
395	if (memcmp(data, ms_oui, 3) == 0) {
396		switch (data[3]) {
397		case 1:
398			printf("IEEE 802.1X");
399			break;
400		case 2:
401			printf("PSK");
402			break;
403		default:
404			printf("%.02x-%.02x-%.02x:%d",
405				data[0], data[1] ,data[2], data[3]);
406			break;
407		}
408	} else if (memcmp(data, ieee80211_oui, 3) == 0) {
409		switch (data[3]) {
410		case 1:
411			printf("IEEE 802.1X");
412			break;
413		case 2:
414			printf("PSK");
415			break;
416		case 3:
417			printf("FT/IEEE 802.1X");
418			break;
419		case 4:
420			printf("FT/PSK");
421			break;
422		case 5:
423			printf("IEEE 802.1X/SHA-256");
424			break;
425		case 6:
426			printf("PSK/SHA-256");
427			break;
428		case 7:
429			printf("TDLS/TPK");
430			break;
431		default:
432			printf("%.02x-%.02x-%.02x:%d",
433				data[0], data[1] ,data[2], data[3]);
434			break;
435		}
436	} else
437		printf("%.02x-%.02x-%.02x:%d",
438			data[0], data[1] ,data[2], data[3]);
439}
440
441static void print_rsn_ie(const char *defcipher, const char *defauth,
442			 uint8_t len, const uint8_t *data)
443{
444	bool first = true;
445	__u16 version, count, capa;
446	int i;
447
448	version = data[0] + (data[1] << 8);
449	tab_on_first(&first);
450	printf("\t * Version: %d\n", version);
451
452	data += 2;
453	len -= 2;
454
455	if (len < 4) {
456		tab_on_first(&first);
457		printf("\t * Group cipher: %s\n", defcipher);
458		printf("\t * Pairwise ciphers: %s\n", defcipher);
459		return;
460	}
461
462	tab_on_first(&first);
463	printf("\t * Group cipher: ");
464	print_cipher(data);
465	printf("\n");
466
467	data += 4;
468	len -= 4;
469
470	if (len < 2) {
471		tab_on_first(&first);
472		printf("\t * Pairwise ciphers: %s\n", defcipher);
473		return;
474	}
475
476	count = data[0] | (data[1] << 8);
477	if (2 + (count * 4) > len)
478		goto invalid;
479
480	tab_on_first(&first);
481	printf("\t * Pairwise ciphers:");
482	for (i = 0; i < count; i++) {
483		printf(" ");
484		print_cipher(data + 2 + (i * 4));
485	}
486	printf("\n");
487
488	data += 2 + (count * 4);
489	len -= 2 + (count * 4);
490
491	if (len < 2) {
492		tab_on_first(&first);
493		printf("\t * Authentication suites: %s\n", defauth);
494		return;
495	}
496
497	count = data[0] | (data[1] << 8);
498	if (2 + (count * 4) > len)
499		goto invalid;
500
501	tab_on_first(&first);
502	printf("\t * Authentication suites:");
503	for (i = 0; i < count; i++) {
504		printf(" ");
505		print_auth(data + 2 + (i * 4));
506	}
507	printf("\n");
508
509	data += 2 + (count * 4);
510	len -= 2 + (count * 4);
511
512	if (len >= 2) {
513		capa = data[0] | (data[1] << 8);
514		tab_on_first(&first);
515		printf("\t * Capabilities:");
516		if (capa & 0x0001)
517			printf(" PreAuth");
518		if (capa & 0x0002)
519			printf(" NoPairwise");
520		switch ((capa & 0x000c) >> 2) {
521		case 0:
522			printf(" 1-PTKSA-RC");
523			break;
524		case 1:
525			printf(" 2-PTKSA-RC");
526			break;
527		case 2:
528			printf(" 4-PTKSA-RC");
529			break;
530		case 3:
531			printf(" 16-PTKSA-RC");
532			break;
533		}
534		switch ((capa & 0x0030) >> 4) {
535		case 0:
536			printf(" 1-GTKSA-RC");
537			break;
538		case 1:
539			printf(" 2-GTKSA-RC");
540			break;
541		case 2:
542			printf(" 4-GTKSA-RC");
543			break;
544		case 3:
545			printf(" 16-GTKSA-RC");
546			break;
547		}
548		if (capa & 0x0040)
549			printf(" MFP-required");
550		if (capa & 0x0080)
551			printf(" MFP-capable");
552		if (capa & 0x0200)
553			printf(" Peerkey-enabled");
554		if (capa & 0x0400)
555			printf(" SPP-AMSDU-capable");
556		if (capa & 0x0800)
557			printf(" SPP-AMSDU-required");
558		printf(" (0x%.4x)\n", capa);
559		data += 2;
560		len -= 2;
561	}
562
563	if (len >= 2) {
564		int pmkid_count = data[0] | (data[1] << 8);
565
566		if (len >= 2 + 16 * pmkid_count) {
567			tab_on_first(&first);
568			printf("\t * %d PMKIDs\n", pmkid_count);
569			/* not printing PMKID values */
570			data += 2 + 16 * pmkid_count;
571			len -= 2 + 16 * pmkid_count;
572		} else
573			goto invalid;
574	}
575
576	if (len >= 4) {
577		tab_on_first(&first);
578		printf("\t * Group mgmt cipher suite: ");
579		print_cipher(data);
580		printf("\n");
581		data += 4;
582		len -= 4;
583	}
584
585 invalid:
586	if (len != 0) {
587		printf("\t\t * bogus tail data (%d):", len);
588		while (len) {
589			printf(" %.2x", *data);
590			data++;
591			len--;
592		}
593		printf("\n");
594	}
595}
596
597static void print_rsn(const uint8_t type, uint8_t len, const uint8_t *data)
598{
599	print_rsn_ie("CCMP", "IEEE 802.1X", len, data);
600}
601
602static void print_ht_capa(const uint8_t type, uint8_t len, const uint8_t *data)
603{
604	printf("\n");
605	print_ht_capability(data[0] | (data[1] << 8));
606	print_ampdu_length(data[2] & 3);
607	print_ampdu_spacing((data[2] >> 2) & 7);
608	print_ht_mcs(data + 3);
609}
610
611static const char *ht_secondary_offset[4] = {
612	"no secondary",
613	"above",
614	"[reserved!]",
615	"below",
616};
617
618static void print_ht_op(const uint8_t type, uint8_t len, const uint8_t *data)
619{
620	static const char *protection[4] = {
621		"no",
622		"nonmember",
623		"20 MHz",
624		"non-HT mixed",
625	};
626	static const char *sta_chan_width[2] = {
627		"20 MHz",
628		"any",
629	};
630
631	printf("\n");
632	printf("\t\t * primary channel: %d\n", data[0]);
633	printf("\t\t * secondary channel offset: %s\n",
634		ht_secondary_offset[data[1] & 0x3]);
635	printf("\t\t * STA channel width: %s\n", sta_chan_width[(data[1] & 0x4)>>2]);
636	printf("\t\t * RIFS: %d\n", (data[1] & 0x8)>>3);
637	printf("\t\t * HT protection: %s\n", protection[data[2] & 0x3]);
638	printf("\t\t * non-GF present: %d\n", (data[2] & 0x4) >> 2);
639	printf("\t\t * OBSS non-GF present: %d\n", (data[2] & 0x10) >> 4);
640	printf("\t\t * dual beacon: %d\n", (data[4] & 0x40) >> 6);
641	printf("\t\t * dual CTS protection: %d\n", (data[4] & 0x80) >> 7);
642	printf("\t\t * STBC beacon: %d\n", data[5] & 0x1);
643	printf("\t\t * L-SIG TXOP Prot: %d\n", (data[5] & 0x2) >> 1);
644	printf("\t\t * PCO active: %d\n", (data[5] & 0x4) >> 2);
645	printf("\t\t * PCO phase: %d\n", (data[5] & 0x8) >> 3);
646}
647
648static void print_capabilities(const uint8_t type, uint8_t len, const uint8_t *data)
649{
650	int i, base, bit;
651	bool first = true;
652
653
654	for (i = 0; i < len; i++) {
655		base = i * 8;
656
657		for (bit = 0; bit < 8; bit++) {
658			if (!(data[i] & (1 << bit)))
659				continue;
660
661			if (!first)
662				printf(",");
663			else
664				first = false;
665
666#define CAPA(bit, name)		case bit: printf(" " name); break
667
668			switch (bit + base) {
669			CAPA(0, "HT Information Exchange Supported");
670			CAPA(1, "reserved (On-demand Beacon)");
671			CAPA(2, "Extended Channel Switching");
672			CAPA(3, "reserved (Wave Indication)");
673			CAPA(4, "PSMP Capability");
674			CAPA(5, "reserved (Service Interval Granularity)");
675			CAPA(6, "S-PSMP Capability");
676			CAPA(7, "Event");
677			CAPA(8, "Diagnostics");
678			CAPA(9, "Multicast Diagnostics");
679			CAPA(10, "Location Tracking");
680			CAPA(11, "FMS");
681			CAPA(12, "Proxy ARP Service");
682			CAPA(13, "Collocated Interference Reporting");
683			CAPA(14, "Civic Location");
684			CAPA(15, "Geospatial Location");
685			CAPA(16, "TFS");
686			CAPA(17, "WNM-Sleep Mode");
687			CAPA(18, "TIM Broadcast");
688			CAPA(19, "BSS Transition");
689			CAPA(20, "QoS Traffic Capability");
690			CAPA(21, "AC Station Count");
691			CAPA(22, "Multiple BSSID");
692			CAPA(23, "Timing Measurement");
693			CAPA(24, "Channel Usage");
694			CAPA(25, "SSID List");
695			CAPA(26, "DMS");
696			CAPA(27, "UTC TSF Offset");
697			CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
698			CAPA(29, "TDLS Peer PSM Support");
699			CAPA(30, "TDLS channel switching");
700			CAPA(31, "Interworking");
701			CAPA(32, "QoS Map");
702			CAPA(33, "EBR");
703			CAPA(34, "SSPN Interface");
704			CAPA(35, "Reserved");
705			CAPA(36, "MSGCF Capability");
706			CAPA(37, "TDLS Support");
707			CAPA(38, "TDLS Prohibited");
708			CAPA(39, "TDLS Channel Switching Prohibited");
709			CAPA(40, "Reject Unadmitted Frame");
710			CAPA(44, "Identifier Location");
711			CAPA(45, "U-APSD Coexistence");
712			CAPA(46, "WNM-Notification");
713			CAPA(47, "Reserved");
714			CAPA(48, "UTF-8 SSID");
715			default:
716				printf(" %d", bit);
717				break;
718			}
719#undef CAPA
720		}
721	}
722
723	printf("\n");
724}
725
726static void print_tim(const uint8_t type, uint8_t len, const uint8_t *data)
727{
728	printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
729	       "Bitmap[0] 0x%x",
730	       data[0], data[1], data[2], data[3]);
731	if (len - 4)
732		printf(" (+ %u octet%s)", len - 4, len - 4 == 1 ? "" : "s");
733	printf("\n");
734}
735
736static void print_ibssatim(const uint8_t type, uint8_t len, const uint8_t *data)
737{
738	printf(" %d TUs", (data[1] << 8) + data[0]);
739}
740
741static void print_vht_capa(const uint8_t type, uint8_t len, const uint8_t *data)
742{
743	printf("\n");
744	print_vht_info(data[0] | (data[1] << 8) |
745		       (data[2] << 16) | (data[3] << 24),
746		       data + 4);
747}
748
749static void print_vht_oper(const uint8_t type, uint8_t len, const uint8_t *data)
750{
751	const char *chandwidths[] = {
752		[0] = "20 or 40 MHz",
753		[1] = "80 MHz",
754		[3] = "80+80 MHz",
755		[2] = "160 MHz",
756	};
757
758	printf("\n");
759	printf("\t\t * channel width: %d (%s)\n", data[0],
760		data[0] < ARRAY_SIZE(chandwidths) ? chandwidths[data[0]] : "unknown");
761	printf("\t\t * center freq segment 1: %d\n", data[1]);
762	printf("\t\t * center freq segment 2: %d\n", data[2]);
763	printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data[4], data[3]);
764}
765
766static void print_obss_scan_params(const uint8_t type, uint8_t len, const uint8_t *data)
767{
768	printf("\n");
769	printf("\t\t * passive dwell: %d TUs\n", (data[1] << 8) | data[0]);
770	printf("\t\t * active dwell: %d TUs\n", (data[3] << 8) | data[2]);
771	printf("\t\t * channel width trigger scan interval: %d s\n", (data[5] << 8) | data[4]);
772	printf("\t\t * scan passive total per channel: %d TUs\n", (data[7] << 8) | data[6]);
773	printf("\t\t * scan active total per channel: %d TUs\n", (data[9] << 8) | data[8]);
774	printf("\t\t * BSS width channel transition delay factor: %d\n", (data[11] << 8) | data[10]);
775	printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
776		((data[13] << 8) | data[12]) / 100, ((data[13] << 8) | data[12]) % 100);
777}
778
779static void print_secchan_offs(const uint8_t type, uint8_t len, const uint8_t *data)
780{
781	if (data[0] < ARRAY_SIZE(ht_secondary_offset))
782		printf(" %s (%d)\n", ht_secondary_offset[data[0]], data[0]);
783	else
784		printf(" %d\n", data[0]);
785}
786
787static void print_bss_load(const uint8_t type, uint8_t len, const uint8_t *data)
788{
789	printf("\n");
790	printf("\t\t * station count: %d\n", (data[1] << 8) | data[0]);
791	printf("\t\t * channel utilisation: %d/255\n", data[2]);
792	printf("\t\t * available admission capacity: %d [*32us]\n", (data[4] << 8) | data[3]);
793}
794
795static void print_mesh_conf(const uint8_t type, uint8_t len, const uint8_t *data)
796{
797	printf("\n");
798	printf("\t\t * Active Path Selection Protocol ID: %d\n", data[0]);
799	printf("\t\t * Active Path Selection Metric ID: %d\n", data[1]);
800	printf("\t\t * Congestion Control Mode ID: %d\n", data[2]);
801	printf("\t\t * Synchronization Method ID: %d\n", data[3]);
802	printf("\t\t * Authentication Protocol ID: %d\n", data[4]);
803	printf("\t\t * Mesh Formation Info:\n");
804	printf("\t\t\t Number of Peerings: %d\n", (data[5] & 0x7E) >> 1);
805	if (data[5] & 0x01)
806		printf("\t\t\t Connected to Mesh Gate\n");
807	if (data[5] & 0x80)
808		printf("\t\t\t Connected to AS\n");
809	printf("\t\t * Mesh Capability\n");
810	if (data[6] & 0x01)
811		printf("\t\t\t Accepting Additional Mesh Peerings\n");
812	if (data[6] & 0x02)
813		printf("\t\t\t MCCA Supported\n");
814	if (data[6] & 0x04)
815		printf("\t\t\t MCCA Enabled\n");
816	if (data[6] & 0x08)
817		printf("\t\t\t Forwarding\n");
818	if (data[6] & 0x10)
819		printf("\t\t\t MBCA Supported\n");
820	if (data[6] & 0x20)
821		printf("\t\t\t TBTT Adjusting\n");
822	if (data[6] & 0x40)
823		printf("\t\t\t Mesh Power Save Level\n");
824}
825
826struct ie_print {
827	const char *name;
828	void (*print)(const uint8_t type, uint8_t len, const uint8_t *data);
829	uint8_t minlen, maxlen;
830	uint8_t flags;
831};
832
833static void print_ie(const struct ie_print *p, const uint8_t type,
834		     uint8_t len, const uint8_t *data)
835{
836	int i;
837
838	if (!p->print)
839		return;
840
841	printf("\t%s:", p->name);
842	if (len < p->minlen || len > p->maxlen) {
843		if (len > 1) {
844			printf(" <invalid: %d bytes:", len);
845			for (i = 0; i < len; i++)
846				printf(" %.02x", data[i]);
847			printf(">\n");
848		} else if (len)
849			printf(" <invalid: 1 byte: %.02x>\n", data[0]);
850		else
851			printf(" <invalid: no data>\n");
852		return;
853	}
854
855	p->print(type, len, data);
856}
857
858#define PRINT_IGN {		\
859	.name = "IGNORE",	\
860	.print = NULL,		\
861	.minlen = 0,		\
862	.maxlen = 255,		\
863}
864
865static const struct ie_print ieprinters[] = {
866	[0] = { "SSID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
867	[1] = { "Supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), },
868	[3] = { "DS Parameter set", print_ds, 1, 1, BIT(PRINT_SCAN), },
869	[5] = { "TIM", print_tim, 4, 255, BIT(PRINT_SCAN), },
870	[6] = { "IBSS ATIM window", print_ibssatim, 2, 2, BIT(PRINT_SCAN), },
871	[7] = { "Country", print_country, 3, 255, BIT(PRINT_SCAN), },
872	[11] = { "BSS Load", print_bss_load, 5, 5, BIT(PRINT_SCAN), },
873	[32] = { "Power constraint", print_powerconstraint, 1, 1, BIT(PRINT_SCAN), },
874	[35] = { "TPC report", print_tpcreport, 2, 2, BIT(PRINT_SCAN), },
875	[42] = { "ERP", print_erp, 1, 255, BIT(PRINT_SCAN), },
876	[45] = { "HT capabilities", print_ht_capa, 26, 26, BIT(PRINT_SCAN), },
877	[47] = { "ERP D4.0", print_erp, 1, 255, BIT(PRINT_SCAN), },
878	[74] = { "Overlapping BSS scan params", print_obss_scan_params, 14, 255, BIT(PRINT_SCAN), },
879	[61] = { "HT operation", print_ht_op, 22, 22, BIT(PRINT_SCAN), },
880	[62] = { "Secondary Channel Offset", print_secchan_offs, 1, 1, BIT(PRINT_SCAN), },
881	[191] = { "VHT capabilities", print_vht_capa, 12, 255, BIT(PRINT_SCAN), },
882	[192] = { "VHT operation", print_vht_oper, 5, 255, BIT(PRINT_SCAN), },
883	[48] = { "RSN", print_rsn, 2, 255, BIT(PRINT_SCAN), },
884	[50] = { "Extended supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), },
885	[113] = { "MESH Configuration", print_mesh_conf, 7, 7, BIT(PRINT_SCAN), },
886	[114] = { "MESH ID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
887	[127] = { "Extended capabilities", print_capabilities, 0, 255, BIT(PRINT_SCAN), },
888};
889
890static void print_wifi_wpa(const uint8_t type, uint8_t len, const uint8_t *data)
891{
892	print_rsn_ie("TKIP", "IEEE 802.1X", len, data);
893}
894
895static bool print_wifi_wmm_param(const uint8_t *data, uint8_t len)
896{
897	int i;
898	static const char *aci_tbl[] = { "BE", "BK", "VI", "VO" };
899
900	if (len < 19)
901		goto invalid;
902
903	if (data[0] != 1) {
904		printf("Parameter: not version 1: ");
905		return false;
906	}
907
908	printf("\t * Parameter version 1");
909
910	data++;
911
912	if (data[0] & 0x80)
913		printf("\n\t\t * u-APSD");
914
915	data += 2;
916
917	for (i = 0; i < 4; i++) {
918		printf("\n\t\t * %s:", aci_tbl[(data[0] >> 5) & 3]);
919		if (data[0] & 0x10)
920			printf(" acm");
921		printf(" CW %d-%d", (1 << (data[1] & 0xf)) - 1,
922				    (1 << (data[1] >> 4)) - 1);
923		printf(", AIFSN %d", data[0] & 0xf);
924		if (data[2] | data[3])
925			printf(", TXOP %d usec", (data[2] + (data[3] << 8)) * 32);
926		data += 4;
927	}
928
929	printf("\n");
930	return true;
931
932 invalid:
933 	printf("invalid: ");
934 	return false;
935}
936
937static void print_wifi_wmm(const uint8_t type, uint8_t len, const uint8_t *data)
938{
939	int i;
940
941	switch (data[0]) {
942	case 0x00:
943		printf(" information:");
944		break;
945	case 0x01:
946		if (print_wifi_wmm_param(data + 1, len - 1))
947			return;
948		break;
949	default:
950		printf(" type %d:", data[0]);
951		break;
952	}
953
954	for(i = 1; i < len; i++)
955		printf(" %.02x", data[i]);
956	printf("\n");
957}
958
959static const char * wifi_wps_dev_passwd_id(uint16_t id)
960{
961	switch (id) {
962	case 0:
963		return "Default (PIN)";
964	case 1:
965		return "User-specified";
966	case 2:
967		return "Machine-specified";
968	case 3:
969		return "Rekey";
970	case 4:
971		return "PushButton";
972	case 5:
973		return "Registrar-specified";
974	default:
975		return "??";
976	}
977}
978
979static void print_wifi_wps(const uint8_t type, uint8_t len, const uint8_t *data)
980{
981	bool first = true;
982	__u16 subtype, sublen;
983
984	while (len >= 4) {
985		subtype = (data[0] << 8) + data[1];
986		sublen = (data[2] << 8) + data[3];
987		if (sublen > len)
988			break;
989
990		switch (subtype) {
991		case 0x104a:
992			tab_on_first(&first);
993			printf("\t * Version: %d.%d\n", data[4] >> 4, data[4] & 0xF);
994			break;
995		case 0x1011:
996			tab_on_first(&first);
997			printf("\t * Device name: %.*s\n", sublen, data + 4);
998			break;
999		case 0x1012: {
1000			uint16_t id;
1001			tab_on_first(&first);
1002			if (sublen != 2) {
1003				printf("\t * Device Password ID: (invalid "
1004				       "length %d)\n", sublen);
1005				break;
1006			}
1007			id = data[4] << 8 | data[5];
1008			printf("\t * Device Password ID: %u (%s)\n",
1009			       id, wifi_wps_dev_passwd_id(id));
1010			break;
1011		}
1012		case 0x1021:
1013			tab_on_first(&first);
1014			printf("\t * Manufacturer: %.*s\n", sublen, data + 4);
1015			break;
1016		case 0x1023:
1017			tab_on_first(&first);
1018			printf("\t * Model: %.*s\n", sublen, data + 4);
1019			break;
1020		case 0x1024:
1021			tab_on_first(&first);
1022			printf("\t * Model Number: %.*s\n", sublen, data + 4);
1023			break;
1024		case 0x103b: {
1025			__u8 val = data[4];
1026			tab_on_first(&first);
1027			printf("\t * Response Type: %d%s\n",
1028			       val, val == 3 ? " (AP)" : "");
1029			break;
1030		}
1031		case 0x103c: {
1032			__u8 val = data[4];
1033			tab_on_first(&first);
1034			printf("\t * RF Bands: 0x%x\n", val);
1035			break;
1036		}
1037		case 0x1041: {
1038			__u8 val = data[4];
1039			tab_on_first(&first);
1040			printf("\t * Selected Registrar: 0x%x\n", val);
1041			break;
1042		}
1043		case 0x1042:
1044			tab_on_first(&first);
1045			printf("\t * Serial Number: %.*s\n", sublen, data + 4);
1046			break;
1047		case 0x1044: {
1048			__u8 val = data[4];
1049			tab_on_first(&first);
1050			printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1051			       val,
1052			       val == 1 ? " (Unconfigured)" : "",
1053			       val == 2 ? " (Configured)" : "");
1054			break;
1055		}
1056		case 0x1047:
1057			tab_on_first(&first);
1058			printf("\t * UUID: ");
1059			if (sublen != 16) {
1060				printf("(invalid, length=%d)\n", sublen);
1061				break;
1062			}
1063			printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1064				"%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1065				data[4], data[5], data[6], data[7],
1066				data[8], data[9], data[10], data[11],
1067				data[12], data[13], data[14], data[15],
1068				data[16], data[17], data[18], data[19]);
1069			break;
1070		case 0x1054: {
1071			tab_on_first(&first);
1072			if (sublen != 8) {
1073				printf("\t * Primary Device Type: (invalid "
1074				       "length %d)\n", sublen);
1075				break;
1076			}
1077			printf("\t * Primary Device Type: "
1078			       "%u-%02x%02x%02x%02x-%u\n",
1079			       data[4] << 8 | data[5],
1080			       data[6], data[7], data[8], data[9],
1081			       data[10] << 8 | data[11]);
1082			break;
1083		}
1084		case 0x1057: {
1085			__u8 val = data[4];
1086			tab_on_first(&first);
1087			printf("\t * AP setup locked: 0x%.2x\n", val);
1088			break;
1089		}
1090		case 0x1008:
1091		case 0x1053: {
1092			__u16 meth = (data[4] << 8) + data[5];
1093			bool comma = false;
1094			tab_on_first(&first);
1095			printf("\t * %sConfig methods:",
1096			       subtype == 0x1053 ? "Selected Registrar ": "");
1097#define T(bit, name) do {		\
1098	if (meth & (1<<bit)) {		\
1099		if (comma)		\
1100			printf(",");	\
1101		comma = true;		\
1102		printf(" " name);	\
1103	} } while (0)
1104			T(0, "USB");
1105			T(1, "Ethernet");
1106			T(2, "Label");
1107			T(3, "Display");
1108			T(4, "Ext. NFC");
1109			T(5, "Int. NFC");
1110			T(6, "NFC Intf.");
1111			T(7, "PBC");
1112			T(8, "Keypad");
1113			printf("\n");
1114			break;
1115#undef T
1116		}
1117		default: {
1118			const __u8 *subdata = data + 4;
1119			__u16 tmplen = sublen;
1120
1121			tab_on_first(&first);
1122			printf("\t * Unknown TLV (%#.4x, %d bytes):",
1123			       subtype, tmplen);
1124			while (tmplen) {
1125				printf(" %.2x", *subdata);
1126				subdata++;
1127				tmplen--;
1128			}
1129			printf("\n");
1130			break;
1131		}
1132		}
1133
1134		data += sublen + 4;
1135		len -= sublen + 4;
1136	}
1137
1138	if (len != 0) {
1139		printf("\t\t * bogus tail data (%d):", len);
1140		while (len) {
1141			printf(" %.2x", *data);
1142			data++;
1143			len--;
1144		}
1145		printf("\n");
1146	}
1147}
1148
1149static const struct ie_print wifiprinters[] = {
1150	[1] = { "WPA", print_wifi_wpa, 2, 255, BIT(PRINT_SCAN), },
1151	[2] = { "WMM", print_wifi_wmm, 1, 255, BIT(PRINT_SCAN), },
1152	[4] = { "WPS", print_wifi_wps, 0, 255, BIT(PRINT_SCAN), },
1153};
1154
1155static inline void print_p2p(const uint8_t type, uint8_t len, const uint8_t *data)
1156{
1157	bool first = true;
1158	__u8 subtype;
1159	__u16 sublen;
1160
1161	while (len >= 3) {
1162		subtype = data[0];
1163		sublen = (data[2] << 8) + data[1];
1164
1165		if (sublen > len - 3)
1166			break;
1167
1168		switch (subtype) {
1169		case 0x02: /* capability */
1170			tab_on_first(&first);
1171			if (sublen < 2) {
1172				printf("\t * malformed capability\n");
1173				break;
1174			}
1175			printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
1176				data[3], data[4]);
1177			break;
1178		case 0x0d: /* device info */
1179			if (sublen < 6 + 2 + 8 + 1) {
1180				printf("\t * malformed device info\n");
1181				break;
1182			}
1183			/* fall through for now */
1184		case 0x00: /* status */
1185		case 0x01: /* minor reason */
1186		case 0x03: /* device ID */
1187		case 0x04: /* GO intent */
1188		case 0x05: /* configuration timeout */
1189		case 0x06: /* listen channel */
1190		case 0x07: /* group BSSID */
1191		case 0x08: /* ext listen timing */
1192		case 0x09: /* intended interface address */
1193		case 0x0a: /* manageability */
1194		case 0x0b: /* channel list */
1195		case 0x0c: /* NoA */
1196		case 0x0e: /* group info */
1197		case 0x0f: /* group ID */
1198		case 0x10: /* interface */
1199		case 0x11: /* operating channel */
1200		case 0x12: /* invitation flags */
1201		case 0xdd: /* vendor specific */
1202		default: {
1203			const __u8 *subdata = data + 4;
1204			__u16 tmplen = sublen;
1205
1206			tab_on_first(&first);
1207			printf("\t * Unknown TLV (%#.2x, %d bytes):",
1208			       subtype, tmplen);
1209			while (tmplen) {
1210				printf(" %.2x", *subdata);
1211				subdata++;
1212				tmplen--;
1213			}
1214			printf("\n");
1215			break;
1216		}
1217		}
1218
1219		data += sublen + 3;
1220		len -= sublen + 3;
1221	}
1222
1223	if (len != 0) {
1224		tab_on_first(&first);
1225		printf("\t * bogus tail data (%d):", len);
1226		while (len) {
1227			printf(" %.2x", *data);
1228			data++;
1229			len--;
1230		}
1231		printf("\n");
1232	}
1233}
1234
1235static const struct ie_print wfa_printers[] = {
1236	[9] = { "P2P", print_p2p, 2, 255, BIT(PRINT_SCAN), },
1237};
1238
1239static void print_vendor(unsigned char len, unsigned char *data,
1240			 bool unknown, enum print_ie_type ptype)
1241{
1242	int i;
1243
1244	if (len < 3) {
1245		printf("\tVendor specific: <too short> data:");
1246		for(i = 0; i < len; i++)
1247			printf(" %.02x", data[i]);
1248		printf("\n");
1249		return;
1250	}
1251
1252	if (len >= 4 && memcmp(data, ms_oui, 3) == 0) {
1253		if (data[3] < ARRAY_SIZE(wifiprinters) &&
1254		    wifiprinters[data[3]].name &&
1255		    wifiprinters[data[3]].flags & BIT(ptype)) {
1256			print_ie(&wifiprinters[data[3]], data[3], len - 4, data + 4);
1257			return;
1258		}
1259		if (!unknown)
1260			return;
1261		printf("\tMS/WiFi %#.2x, data:", data[3]);
1262		for(i = 0; i < len - 4; i++)
1263			printf(" %.02x", data[i + 4]);
1264		printf("\n");
1265		return;
1266	}
1267
1268	if (len >= 4 && memcmp(data, wfa_oui, 3) == 0) {
1269		if (data[3] < ARRAY_SIZE(wfa_printers) &&
1270		    wfa_printers[data[3]].name &&
1271		    wfa_printers[data[3]].flags & BIT(ptype)) {
1272			print_ie(&wfa_printers[data[3]], data[3], len - 4, data + 4);
1273			return;
1274		}
1275		if (!unknown)
1276			return;
1277		printf("\tWFA %#.2x, data:", data[3]);
1278		for(i = 0; i < len - 4; i++)
1279			printf(" %.02x", data[i + 4]);
1280		printf("\n");
1281		return;
1282	}
1283
1284	if (!unknown)
1285		return;
1286
1287	printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
1288		data[0], data[1], data[2]);
1289	for (i = 3; i < len; i++)
1290		printf(" %.2x", data[i]);
1291	printf("\n");
1292}
1293
1294void print_ies(unsigned char *ie, int ielen, bool unknown,
1295	       enum print_ie_type ptype)
1296{
1297	while (ielen >= 2 && ielen >= ie[1]) {
1298		if (ie[0] < ARRAY_SIZE(ieprinters) &&
1299		    ieprinters[ie[0]].name &&
1300		    ieprinters[ie[0]].flags & BIT(ptype)) {
1301			print_ie(&ieprinters[ie[0]], ie[0], ie[1], ie + 2);
1302		} else if (ie[0] == 221 /* vendor */) {
1303			print_vendor(ie[1], ie + 2, unknown, ptype);
1304		} else if (unknown) {
1305			int i;
1306
1307			printf("\tUnknown IE (%d):", ie[0]);
1308			for (i=0; i<ie[1]; i++)
1309				printf(" %.2x", ie[2+i]);
1310			printf("\n");
1311		}
1312		ielen -= ie[1] + 2;
1313		ie += ie[1] + 2;
1314	}
1315}
1316
1317static void print_capa_dmg(__u16 capa)
1318{
1319	switch (capa & WLAN_CAPABILITY_DMG_TYPE_MASK) {
1320	case WLAN_CAPABILITY_DMG_TYPE_AP:
1321		printf(" DMG_ESS");
1322		break;
1323	case WLAN_CAPABILITY_DMG_TYPE_PBSS:
1324		printf(" DMG_PCP");
1325		break;
1326	case WLAN_CAPABILITY_DMG_TYPE_IBSS:
1327		printf(" DMG_IBSS");
1328		break;
1329	}
1330
1331	if (capa & WLAN_CAPABILITY_DMG_CBAP_ONLY)
1332		printf(" CBAP_Only");
1333	if (capa & WLAN_CAPABILITY_DMG_CBAP_SOURCE)
1334		printf(" CBAP_Src");
1335	if (capa & WLAN_CAPABILITY_DMG_PRIVACY)
1336		printf(" Privacy");
1337	if (capa & WLAN_CAPABILITY_DMG_ECPAC)
1338		printf(" ECPAC");
1339	if (capa & WLAN_CAPABILITY_DMG_SPECTRUM_MGMT)
1340		printf(" SpectrumMgmt");
1341	if (capa & WLAN_CAPABILITY_DMG_RADIO_MEASURE)
1342		printf(" RadioMeasure");
1343}
1344
1345static void print_capa_non_dmg(__u16 capa)
1346{
1347	if (capa & WLAN_CAPABILITY_ESS)
1348		printf(" ESS");
1349	if (capa & WLAN_CAPABILITY_IBSS)
1350		printf(" IBSS");
1351	if (capa & WLAN_CAPABILITY_CF_POLLABLE)
1352		printf(" CfPollable");
1353	if (capa & WLAN_CAPABILITY_CF_POLL_REQUEST)
1354		printf(" CfPollReq");
1355	if (capa & WLAN_CAPABILITY_PRIVACY)
1356		printf(" Privacy");
1357	if (capa & WLAN_CAPABILITY_SHORT_PREAMBLE)
1358		printf(" ShortPreamble");
1359	if (capa & WLAN_CAPABILITY_PBCC)
1360		printf(" PBCC");
1361	if (capa & WLAN_CAPABILITY_CHANNEL_AGILITY)
1362		printf(" ChannelAgility");
1363	if (capa & WLAN_CAPABILITY_SPECTRUM_MGMT)
1364		printf(" SpectrumMgmt");
1365	if (capa & WLAN_CAPABILITY_QOS)
1366		printf(" QoS");
1367	if (capa & WLAN_CAPABILITY_SHORT_SLOT_TIME)
1368		printf(" ShortSlotTime");
1369	if (capa & WLAN_CAPABILITY_APSD)
1370		printf(" APSD");
1371	if (capa & WLAN_CAPABILITY_RADIO_MEASURE)
1372		printf(" RadioMeasure");
1373	if (capa & WLAN_CAPABILITY_DSSS_OFDM)
1374		printf(" DSSS-OFDM");
1375	if (capa & WLAN_CAPABILITY_DEL_BACK)
1376		printf(" DelayedBACK");
1377	if (capa & WLAN_CAPABILITY_IMM_BACK)
1378		printf(" ImmediateBACK");
1379}
1380
1381static int print_bss_handler(struct nl_msg *msg, void *arg)
1382{
1383	struct nlattr *tb[NL80211_ATTR_MAX + 1];
1384	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1385	struct nlattr *bss[NL80211_BSS_MAX + 1];
1386	char mac_addr[20], dev[20];
1387	static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
1388		[NL80211_BSS_TSF] = { .type = NLA_U64 },
1389		[NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
1390		[NL80211_BSS_BSSID] = { },
1391		[NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
1392		[NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
1393		[NL80211_BSS_INFORMATION_ELEMENTS] = { },
1394		[NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
1395		[NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
1396		[NL80211_BSS_STATUS] = { .type = NLA_U32 },
1397		[NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
1398		[NL80211_BSS_BEACON_IES] = { },
1399	};
1400	struct scan_params *params = arg;
1401	int show = params->show_both_ie_sets ? 2 : 1;
1402	bool is_dmg = false;
1403
1404	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1405		  genlmsg_attrlen(gnlh, 0), NULL);
1406
1407	if (!tb[NL80211_ATTR_BSS]) {
1408		fprintf(stderr, "bss info missing!\n");
1409		return NL_SKIP;
1410	}
1411	if (nla_parse_nested(bss, NL80211_BSS_MAX,
1412			     tb[NL80211_ATTR_BSS],
1413			     bss_policy)) {
1414		fprintf(stderr, "failed to parse nested attributes!\n");
1415		return NL_SKIP;
1416	}
1417
1418	if (!bss[NL80211_BSS_BSSID])
1419		return NL_SKIP;
1420
1421	mac_addr_n2a(mac_addr, nla_data(bss[NL80211_BSS_BSSID]));
1422	printf("BSS %s", mac_addr);
1423	if (tb[NL80211_ATTR_IFINDEX]) {
1424		if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
1425		printf("(on %s)", dev);
1426	}
1427
1428	if (bss[NL80211_BSS_STATUS]) {
1429		switch (nla_get_u32(bss[NL80211_BSS_STATUS])) {
1430		case NL80211_BSS_STATUS_AUTHENTICATED:
1431			printf(" -- authenticated");
1432			break;
1433		case NL80211_BSS_STATUS_ASSOCIATED:
1434			printf(" -- associated");
1435			break;
1436		case NL80211_BSS_STATUS_IBSS_JOINED:
1437			printf(" -- joined");
1438			break;
1439		default:
1440			printf(" -- unknown status: %d",
1441				nla_get_u32(bss[NL80211_BSS_STATUS]));
1442			break;
1443		}
1444	}
1445	printf("\n");
1446
1447	if (bss[NL80211_BSS_TSF]) {
1448		unsigned long long tsf;
1449		tsf = (unsigned long long)nla_get_u64(bss[NL80211_BSS_TSF]);
1450		printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
1451			tsf, tsf/1000/1000/60/60/24, (tsf/1000/1000/60/60) % 24,
1452			(tsf/1000/1000/60) % 60, (tsf/1000/1000) % 60);
1453	}
1454	if (bss[NL80211_BSS_FREQUENCY]) {
1455		int freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
1456		printf("\tfreq: %d\n", freq);
1457		if (freq > 45000)
1458			is_dmg = true;
1459	}
1460	if (bss[NL80211_BSS_BEACON_INTERVAL])
1461		printf("\tbeacon interval: %d TUs\n",
1462			nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]));
1463	if (bss[NL80211_BSS_CAPABILITY]) {
1464		__u16 capa = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
1465		printf("\tcapability:");
1466		if (is_dmg)
1467			print_capa_dmg(capa);
1468		else
1469			print_capa_non_dmg(capa);
1470		printf(" (0x%.4x)\n", capa);
1471	}
1472	if (bss[NL80211_BSS_SIGNAL_MBM]) {
1473		int s = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
1474		printf("\tsignal: %d.%.2d dBm\n", s/100, s%100);
1475	}
1476	if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
1477		unsigned char s = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
1478		printf("\tsignal: %d/100\n", s);
1479	}
1480	if (bss[NL80211_BSS_SEEN_MS_AGO]) {
1481		int age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
1482		printf("\tlast seen: %d ms ago\n", age);
1483	}
1484
1485	if (bss[NL80211_BSS_INFORMATION_ELEMENTS] && show--) {
1486		if (bss[NL80211_BSS_BEACON_IES])
1487			printf("\tInformation elements from Probe Response "
1488			       "frame:\n");
1489		print_ies(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
1490			  nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
1491			  params->unknown, params->type);
1492	}
1493	if (bss[NL80211_BSS_BEACON_IES] && show--) {
1494		printf("\tInformation elements from Beacon frame:\n");
1495		print_ies(nla_data(bss[NL80211_BSS_BEACON_IES]),
1496			  nla_len(bss[NL80211_BSS_BEACON_IES]),
1497			  params->unknown, params->type);
1498	}
1499
1500	return NL_SKIP;
1501}
1502
1503static struct scan_params scan_params;
1504
1505static int handle_scan_dump(struct nl80211_state *state,
1506			    struct nl_cb *cb,
1507			    struct nl_msg *msg,
1508			    int argc, char **argv,
1509			    enum id_input id)
1510{
1511	if (argc > 1)
1512		return 1;
1513
1514	memset(&scan_params, 0, sizeof(scan_params));
1515
1516	if (argc == 1 && !strcmp(argv[0], "-u"))
1517		scan_params.unknown = true;
1518	else if (argc == 1 && !strcmp(argv[0], "-b"))
1519		scan_params.show_both_ie_sets = true;
1520
1521	scan_params.type = PRINT_SCAN;
1522
1523	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_bss_handler,
1524		  &scan_params);
1525	return 0;
1526}
1527
1528static int handle_scan_combined(struct nl80211_state *state,
1529				struct nl_cb *cb,
1530				struct nl_msg *msg,
1531				int argc, char **argv,
1532				enum id_input id)
1533{
1534	char **trig_argv;
1535	static char *dump_argv[] = {
1536		NULL,
1537		"scan",
1538		"dump",
1539		NULL,
1540	};
1541	static const __u32 cmds[] = {
1542		NL80211_CMD_NEW_SCAN_RESULTS,
1543		NL80211_CMD_SCAN_ABORTED,
1544	};
1545	int trig_argc, dump_argc, err;
1546
1547	if (argc >= 3 && !strcmp(argv[2], "-u")) {
1548		dump_argc = 4;
1549		dump_argv[3] = "-u";
1550	} else if (argc >= 3 && !strcmp(argv[2], "-b")) {
1551		dump_argc = 4;
1552		dump_argv[3] = "-b";
1553	} else
1554		dump_argc = 3;
1555
1556	trig_argc = 3 + (argc - 2) + (3 - dump_argc);
1557	trig_argv = calloc(trig_argc, sizeof(*trig_argv));
1558	if (!trig_argv)
1559		return -ENOMEM;
1560	trig_argv[0] = argv[0];
1561	trig_argv[1] = "scan";
1562	trig_argv[2] = "trigger";
1563	int i;
1564	for (i = 0; i < argc - 2 - (dump_argc - 3); i++)
1565		trig_argv[i + 3] = argv[i + 2 + (dump_argc - 3)];
1566	err = handle_cmd(state, id, trig_argc, trig_argv);
1567	free(trig_argv);
1568	if (err)
1569		return err;
1570
1571	/*
1572	 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
1573	 *
1574	 * This code has a bug, which requires creating a separate
1575	 * nl80211 socket to fix:
1576	 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
1577	 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
1578	 * before (!) we listen to it, because we only start listening
1579	 * after we send our scan request.
1580	 *
1581	 * Doing it the other way around has a race condition as well,
1582	 * if you first open the events socket you may get a notification
1583	 * for a previous scan.
1584	 *
1585	 * The only proper way to fix this would be to listen to events
1586	 * before sending the command, and for the kernel to send the
1587	 * scan request along with the event, so that you can match up
1588	 * whether the scan you requested was finished or aborted (this
1589	 * may result in processing a scan that another application
1590	 * requested, but that doesn't seem to be a problem).
1591	 *
1592	 * Alas, the kernel doesn't do that (yet).
1593	 */
1594
1595	if (listen_events(state, ARRAY_SIZE(cmds), cmds) ==
1596					NL80211_CMD_SCAN_ABORTED) {
1597		printf("scan aborted!\n");
1598		return 0;
1599	}
1600
1601	dump_argv[0] = argv[0];
1602	return handle_cmd(state, id, dump_argc, dump_argv);
1603}
1604TOPLEVEL(scan, "[-u] [freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [ssid <ssid>*|passive]", 0, 0,
1605	 CIB_NETDEV, handle_scan_combined,
1606	 "Scan on the given frequencies and probe for the given SSIDs\n"
1607	 "(or wildcard if not given) unless passive scanning is requested.\n"
1608	 "If -u is specified print unknown data in the scan results.\n"
1609	 "Specified (vendor) IEs must be well-formed.");
1610COMMAND(scan, dump, "[-u]",
1611	NL80211_CMD_GET_SCAN, NLM_F_DUMP, CIB_NETDEV, handle_scan_dump,
1612	"Dump the current scan results. If -u is specified, print unknown\n"
1613	"data in scan results.");
1614COMMAND(scan, trigger, "[freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [ssid <ssid>*|passive]",
1615	NL80211_CMD_TRIGGER_SCAN, 0, CIB_NETDEV, handle_scan,
1616	 "Trigger a scan on the given frequencies with probing for the given\n"
1617	 "SSIDs (or wildcard if not given) unless passive scanning is requested.");
1618