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