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>
15 #define WLAN_CAPABILITY_ESS (1<<0)
16 #define WLAN_CAPABILITY_IBSS (1<<1)
17 #define WLAN_CAPABILITY_CF_POLLABLE (1<<2)
18 #define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3)
19 #define WLAN_CAPABILITY_PRIVACY (1<<4)
20 #define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
21 #define WLAN_CAPABILITY_PBCC (1<<6)
22 #define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
23 #define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8)
24 #define WLAN_CAPABILITY_QOS (1<<9)
25 #define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10)
26 #define WLAN_CAPABILITY_APSD (1<<11)
27 #define WLAN_CAPABILITY_RADIO_MEASURE (1<<12)
28 #define WLAN_CAPABILITY_DSSS_OFDM (1<<13)
29 #define WLAN_CAPABILITY_DEL_BACK (1<<14)
30 #define WLAN_CAPABILITY_IMM_BACK (1<<15)
31 /* DMG (60gHz) 802.11ad */
32 /* type - bits 0..1 */
33 #define WLAN_CAPABILITY_DMG_TYPE_MASK (3<<0)
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 */
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)
44 #define WLAN_CAPABILITY_DMG_SPECTRUM_MGMT (1<<8)
45 #define WLAN_CAPABILITY_DMG_RADIO_MEASURE (1<<12)
47 static unsigned char ms_oui
[3] = { 0x00, 0x50, 0xf2 };
48 static unsigned char ieee80211_oui
[3] = { 0x00, 0x0f, 0xac };
49 static unsigned char wfa_oui
[3] = { 0x50, 0x6f, 0x9a };
53 enum print_ie_type type
;
54 bool show_both_ie_sets
;
57 #define IEEE80211_COUNTRY_EXTENSION_ID 201
59 union ieee80211_country_ie_triplet
{
64 } __attribute__ ((packed
)) chans
;
66 __u8 reg_extension_id
;
69 } __attribute__ ((packed
)) ext
;
70 } __attribute__ ((packed
));
72 int parse_sched_scan(struct nl_msg
*msg
, int *argc
, char ***argv
)
74 struct nl_msg
*matchset
= NULL
, *freqs
= NULL
, *ssids
= NULL
;
75 struct nl_msg
*scan_plans
= NULL
;
76 struct nlattr
*match
= NULL
, *plan
= NULL
;
83 } parse_state
= ND_TOPLEVEL
;
85 char *end
, **v
= *argv
;
87 unsigned int freq
, interval
= 0, delay
= 0, iterations
= 0;
88 bool have_matchset
= false, have_freqs
= false, have_ssids
= false;
89 bool have_active
= false, have_passive
= false, have_plans
= false;
92 matchset
= nlmsg_alloc();
98 freqs
= nlmsg_alloc();
104 ssids
= nlmsg_alloc();
110 scan_plans
= nlmsg_alloc();
117 switch (parse_state
) {
119 if (!strcmp(v
[0], "interval")) {
123 goto nla_put_failure
;
126 if (interval
|| have_plans
) {
128 goto nla_put_failure
;
130 interval
= strtoul(v
[0], &end
, 10);
131 if (*end
|| !interval
) {
133 goto nla_put_failure
;
136 NL80211_ATTR_SCHED_SCAN_INTERVAL
,
138 } else if (!strcmp(v
[0], "scan_plans")) {
139 parse_state
= ND_PLANS
;
140 if (have_plans
|| interval
) {
142 goto nla_put_failure
;
147 } else if (!strcmp(v
[0], "delay")) {
151 goto nla_put_failure
;
156 goto nla_put_failure
;
158 delay
= strtoul(v
[0], &end
, 10);
161 goto nla_put_failure
;
164 NL80211_ATTR_SCHED_SCAN_DELAY
,
166 } else if (!strcmp(v
[0], "matches")) {
167 parse_state
= ND_MATCH
;
170 goto nla_put_failure
;
174 } else if (!strcmp(v
[0], "freqs")) {
175 parse_state
= ND_FREQS
;
178 goto nla_put_failure
;
183 } else if (!strcmp(v
[0], "active")) {
184 parse_state
= ND_ACTIVE
;
185 if (have_active
|| have_passive
) {
187 goto nla_put_failure
;
192 } else if (!strcmp(v
[0], "passive")) {
193 if (have_active
|| have_passive
) {
195 goto nla_put_failure
;
199 } else if (!strncmp(v
[0], "randomise", 9) ||
200 !strncmp(v
[0], "randomize", 9)) {
201 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
202 err
= parse_random_mac_addr(msg
, v
[0] + 9);
204 goto nla_put_failure
;
206 /* this element is not for us, so
207 * return to continue parsing.
209 goto nla_put_failure
;
215 if (!strcmp(v
[0], "ssid")) {
219 goto nla_put_failure
;
222 /* TODO: for now we can only have an
223 * SSID in the match, so we can start
224 * the match nest here.
226 match
= nla_nest_start(matchset
, i
);
229 goto nla_put_failure
;
233 NL80211_SCHED_SCAN_MATCH_ATTR_SSID
,
235 nla_nest_end(matchset
, match
);
238 have_matchset
= true;
242 /* other element that cannot be part
243 * of a match indicates the end of the
245 /* need at least one match in the matchset */
248 goto nla_put_failure
;
251 parse_state
= ND_TOPLEVEL
;
256 freq
= strtoul(v
[0], &end
, 10);
260 goto nla_put_failure
;
263 parse_state
= ND_TOPLEVEL
;
265 NLA_PUT_U32(freqs
, i
, freq
);
271 if (!strcmp(v
[0], "ssid")) {
275 goto nla_put_failure
;
279 NL80211_SCHED_SCAN_MATCH_ATTR_SSID
,
286 /* other element that cannot be part
287 * of a match indicates the end of the
289 /* need at least one item in the set */
292 goto nla_put_failure
;
295 parse_state
= ND_TOPLEVEL
;
300 interval
= strtoul(v
[0], &end
, 10);
306 goto nla_put_failure
;
310 iterations
= strtoul(iter
, &end
, 10);
311 if (*end
|| !iterations
) {
313 goto nla_put_failure
;
317 plan
= nla_nest_start(scan_plans
, i
+ 1);
320 goto nla_put_failure
;
323 NLA_PUT_U32(scan_plans
,
324 NL80211_SCHED_SCAN_PLAN_INTERVAL
,
328 NLA_PUT_U32(scan_plans
,
329 NL80211_SCHED_SCAN_PLAN_ITERATIONS
,
332 parse_state
= ND_TOPLEVEL
;
334 nla_nest_end(scan_plans
, plan
);
343 NLA_PUT(ssids
, 1, 0, "");
345 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
347 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
349 nla_put_nested(msg
, NL80211_ATTR_SCHED_SCAN_MATCH
, matchset
);
351 nla_put_nested(msg
, NL80211_ATTR_SCHED_SCAN_PLANS
, scan_plans
);
353 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
357 nla_nest_end(msg
, match
);
360 nlmsg_free(matchset
);
361 nlmsg_free(scan_plans
);
369 static int handle_scan(struct nl80211_state
*state
,
371 int argc
, char **argv
,
374 struct nl_msg
*ssids
= NULL
, *freqs
= NULL
;
388 unsigned int duration
= 0;
389 bool passive
= false, have_ssids
= false, have_freqs
= false;
390 bool duration_mandatory
= false;
391 size_t ies_len
= 0, meshid_len
= 0;
392 unsigned char *ies
= NULL
, *meshid
= NULL
, *tmpies
= NULL
;
393 unsigned int flags
= 0;
395 ssids
= nlmsg_alloc();
399 freqs
= nlmsg_alloc();
405 for (i
= 0; i
< argc
; i
++) {
408 if (strcmp(argv
[i
], "freq") == 0) {
412 } else if (strcmp(argv
[i
], "ies") == 0) {
415 } else if (strcmp(argv
[i
], "lowpri") == 0) {
416 flags
|= NL80211_SCAN_FLAG_LOW_PRIORITY
;
418 } else if (strcmp(argv
[i
], "flush") == 0) {
419 flags
|= NL80211_SCAN_FLAG_FLUSH
;
421 } else if (strcmp(argv
[i
], "ap-force") == 0) {
422 flags
|= NL80211_SCAN_FLAG_AP
;
424 } else if (strcmp(argv
[i
], "duration-mandatory") == 0) {
425 duration_mandatory
= true;
427 } else if (strncmp(argv
[i
], "randomise", 9) == 0 ||
428 strncmp(argv
[i
], "randomize", 9) == 0) {
429 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
430 err
= parse_random_mac_addr(msg
, argv
[i
] + 9);
432 goto nla_put_failure
;
434 } else if (strcmp(argv
[i
], "ssid") == 0) {
438 } else if (strcmp(argv
[i
], "passive") == 0) {
442 } else if (strcmp(argv
[i
], "meshid") == 0) {
445 } else if (strcmp(argv
[i
], "duration") == 0) {
449 /* fall through - this is an error */
452 goto nla_put_failure
;
454 freq
= strtoul(argv
[i
], &eptr
, 10);
455 if (eptr
!= argv
[i
] + strlen(argv
[i
])) {
456 /* failed to parse as number -- maybe a tag? */
461 NLA_PUT_U32(freqs
, i
, freq
);
466 ies
= parse_hex(argv
[i
], &ies_len
);
468 goto nla_put_failure
;
472 NLA_PUT(ssids
, i
, strlen(argv
[i
]), argv
[i
]);
475 meshid_len
= strlen(argv
[i
]);
476 meshid
= (unsigned char *) malloc(meshid_len
+ 2);
478 goto nla_put_failure
;
479 meshid
[0] = 114; /* mesh element id */
480 meshid
[1] = meshid_len
;
481 memcpy(&meshid
[2], argv
[i
], meshid_len
);
486 duration
= strtoul(argv
[i
], &eptr
, 10);
493 tmpies
= (unsigned char *) malloc(ies_len
+ meshid_len
);
495 goto nla_put_failure
;
497 memcpy(tmpies
, ies
, ies_len
);
499 memcpy(&tmpies
[ies_len
], meshid
, meshid_len
);
500 if (nla_put(msg
, NL80211_ATTR_IE
, ies_len
+ meshid_len
, tmpies
) < 0)
501 goto nla_put_failure
;
505 NLA_PUT(ssids
, 1, 0, "");
507 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
510 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
512 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
514 NLA_PUT_U16(msg
, NL80211_ATTR_MEASUREMENT_DURATION
, duration
);
515 if (duration_mandatory
) {
518 NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY
);
521 goto nla_put_failure
;
538 static void tab_on_first(bool *first
)
546 struct print_ies_data
{
551 static void print_ssid(const uint8_t type
, uint8_t len
, const uint8_t *data
,
552 const struct print_ies_data
*ie_buffer
)
555 print_ssid_escaped(len
, data
);
559 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
560 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
562 static void print_supprates(const uint8_t type
, uint8_t len
,
564 const struct print_ies_data
*ie_buffer
)
570 for (i
= 0; i
< len
; i
++) {
571 int r
= data
[i
] & 0x7f;
573 if (r
== BSS_MEMBERSHIP_SELECTOR_VHT_PHY
&& data
[i
] & 0x80)
575 else if (r
== BSS_MEMBERSHIP_SELECTOR_HT_PHY
&& data
[i
] & 0x80)
578 printf("%d.%d", r
/2, 5*(r
&1));
580 printf("%s ", data
[i
] & 0x80 ? "*" : "");
585 static void print_rm_enabled_capabilities(const uint8_t type
, uint8_t len
,
587 const struct print_ies_data
*ie_buffer
)
589 __u64 capa
= ((__u64
) data
[0]) |
590 ((__u64
) data
[1]) << 8 |
591 ((__u64
) data
[2]) << 16 |
592 ((__u64
) data
[3]) << 24 |
593 ((__u64
) data
[4]) << 32;
596 printf("\t\tCapabilities: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
601 #define PRINT_RM_CAPA(_bit, _str) \
603 if (capa & BIT(_bit)) \
604 printf("\t\t\t" _str "\n"); \
607 PRINT_RM_CAPA(0, "Link Measurement");
608 PRINT_RM_CAPA(1, "Neighbor Report");
609 PRINT_RM_CAPA(2, "Parallel Measurements");
610 PRINT_RM_CAPA(3, "Repeated Measurements");
611 PRINT_RM_CAPA(4, "Beacon Passive Measurement");
612 PRINT_RM_CAPA(5, "Beacon Active Measurement");
613 PRINT_RM_CAPA(6, "Beacon Table Measurement");
614 PRINT_RM_CAPA(7, "Beacon Measurement Reporting Conditions");
615 PRINT_RM_CAPA(8, "Frame Measurement");
616 PRINT_RM_CAPA(9, "Channel Load");
617 PRINT_RM_CAPA(10, "Noise Histogram Measurement");
618 PRINT_RM_CAPA(11, "Statistics Measurement");
619 PRINT_RM_CAPA(12, "LCI Measurement");
620 PRINT_RM_CAPA(13, "LCI Azimuth");
621 PRINT_RM_CAPA(14, "Transmit Stream/Category Measurement");
622 PRINT_RM_CAPA(15, "Triggered Transmit Stream/Category");
623 PRINT_RM_CAPA(16, "AP Channel Report");
624 PRINT_RM_CAPA(17, "RM MIB Capability");
626 PRINT_RM_CAPA(27, "Measurement Pilot Transmission Information");
627 PRINT_RM_CAPA(28, "Neighbor Report TSF Offset");
628 PRINT_RM_CAPA(29, "RCPI Measurement");
629 PRINT_RM_CAPA(30, "RSNI Measurement");
630 PRINT_RM_CAPA(31, "BSS Average Access Delay");
631 PRINT_RM_CAPA(32, "BSS Available Admission");
632 PRINT_RM_CAPA(33, "Antenna");
633 PRINT_RM_CAPA(34, "FTM Range Report");
634 PRINT_RM_CAPA(35, "Civic Location Measurement");
636 printf("\t\tNonoperating Channel Max Measurement Duration: %i\n", data
[3] >> 5);
637 printf("\t\tMeasurement Pilot Capability: %i\n", data
[4] & 7);
640 static void print_ds(const uint8_t type
, uint8_t len
, const uint8_t *data
,
641 const struct print_ies_data
*ie_buffer
)
643 printf(" channel %d\n", data
[0]);
646 static const char *country_env_str(char environment
)
648 switch (environment
) {
650 return "Indoor only";
652 return "Outdoor only";
654 return "Indoor/Outdoor";
660 static void print_country(const uint8_t type
, uint8_t len
, const uint8_t *data
,
661 const struct print_ies_data
*ie_buffer
)
663 printf(" %.*s", 2, data
);
665 printf("\tEnvironment: %s\n", country_env_str(data
[2]));
671 printf("\t\tNo country IE triplets present\n");
677 union ieee80211_country_ie_triplet
*triplet
= (void *) data
;
679 if (triplet
->ext
.reg_extension_id
>= IEEE80211_COUNTRY_EXTENSION_ID
) {
680 printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
681 triplet
->ext
.reg_extension_id
,
682 triplet
->ext
.reg_class
,
683 triplet
->ext
.coverage_class
,
684 triplet
->ext
.coverage_class
* 450);
692 if (triplet
->chans
.first_channel
<= 14)
693 end_channel
= triplet
->chans
.first_channel
+ (triplet
->chans
.num_channels
- 1);
695 end_channel
= triplet
->chans
.first_channel
+ (4 * (triplet
->chans
.num_channels
- 1));
697 printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet
->chans
.first_channel
, end_channel
, triplet
->chans
.max_power
);
706 static void print_powerconstraint(const uint8_t type
, uint8_t len
,
708 const struct print_ies_data
*ie_buffer
)
710 printf(" %d dB\n", data
[0]);
713 static void print_tpcreport(const uint8_t type
, uint8_t len
,
715 const struct print_ies_data
*ie_buffer
)
717 printf(" TX power: %d dBm\n", data
[0]);
718 /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
721 static void print_erp(const uint8_t type
, uint8_t len
, const uint8_t *data
,
722 const struct print_ies_data
*ie_buffer
)
725 printf(" <no flags>");
727 printf(" NonERP_Present");
729 printf(" Use_Protection");
731 printf(" Barker_Preamble_Mode");
735 static void print_ap_channel_report(const uint8_t type
, uint8_t len
, const uint8_t *data
,
736 const struct print_ies_data
*ie_buffer
)
738 uint8_t oper_class
= data
[0];
742 printf("\t\t * operating class: %d\n", oper_class
);
743 printf("\t\t * channel(s):");
744 for (i
= 1; i
< len
; ++i
) {
745 printf(" %d", data
[i
]);
750 static void print_cipher(const uint8_t *data
)
752 if (memcmp(data
, ms_oui
, 3) == 0) {
755 printf("Use group cipher suite");
770 printf("%.02x-%.02x-%.02x:%d",
771 data
[0], data
[1] ,data
[2], data
[3]);
774 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
777 printf("Use group cipher suite");
792 printf("AES-128-CMAC");
801 printf("%.02x-%.02x-%.02x:%d",
802 data
[0], data
[1] ,data
[2], data
[3]);
806 printf("%.02x-%.02x-%.02x:%d",
807 data
[0], data
[1] ,data
[2], data
[3]);
810 static void print_auth(const uint8_t *data
)
812 if (memcmp(data
, ms_oui
, 3) == 0) {
815 printf("IEEE 802.1X");
821 printf("%.02x-%.02x-%.02x:%d",
822 data
[0], data
[1] ,data
[2], data
[3]);
825 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
828 printf("IEEE 802.1X");
834 printf("FT/IEEE 802.1X");
840 printf("IEEE 802.1X/SHA-256");
843 printf("PSK/SHA-256");
855 printf("IEEE 802.1X/SUITE-B");
858 printf("IEEE 802.1X/SUITE-B-192");
861 printf("FT/IEEE 802.1X/SHA-384");
864 printf("FILS/SHA-256");
867 printf("FILS/SHA-384");
870 printf("FT/FILS/SHA-256");
873 printf("FT/FILS/SHA-384");
879 printf("%.02x-%.02x-%.02x:%d",
880 data
[0], data
[1] ,data
[2], data
[3]);
883 } else if (memcmp(data
, wfa_oui
, 3) == 0) {
892 printf("%.02x-%.02x-%.02x:%d",
893 data
[0], data
[1] ,data
[2], data
[3]);
897 printf("%.02x-%.02x-%.02x:%d",
898 data
[0], data
[1] ,data
[2], data
[3]);
901 static void _print_rsn_ie(const char *defcipher
, const char *defauth
,
902 uint8_t len
, const uint8_t *data
, int is_osen
)
910 version
= data
[0] + (data
[1] << 8);
911 tab_on_first(&first
);
912 printf("\t * Version: %d\n", version
);
919 tab_on_first(&first
);
920 printf("\t * Group cipher: %s\n", defcipher
);
921 printf("\t * Pairwise ciphers: %s\n", defcipher
);
925 tab_on_first(&first
);
926 printf("\t * Group cipher: ");
934 tab_on_first(&first
);
935 printf("\t * Pairwise ciphers: %s\n", defcipher
);
939 count
= data
[0] | (data
[1] << 8);
940 if (2 + (count
* 4) > len
)
943 tab_on_first(&first
);
944 printf("\t * Pairwise ciphers:");
945 for (i
= 0; i
< count
; i
++) {
947 print_cipher(data
+ 2 + (i
* 4));
951 data
+= 2 + (count
* 4);
952 len
-= 2 + (count
* 4);
955 tab_on_first(&first
);
956 printf("\t * Authentication suites: %s\n", defauth
);
960 count
= data
[0] | (data
[1] << 8);
961 if (2 + (count
* 4) > len
)
964 tab_on_first(&first
);
965 printf("\t * Authentication suites:");
966 for (i
= 0; i
< count
; i
++) {
968 print_auth(data
+ 2 + (i
* 4));
972 data
+= 2 + (count
* 4);
973 len
-= 2 + (count
* 4);
976 capa
= data
[0] | (data
[1] << 8);
977 tab_on_first(&first
);
978 printf("\t * Capabilities:");
982 printf(" NoPairwise");
983 switch ((capa
& 0x000c) >> 2) {
985 printf(" 1-PTKSA-RC");
988 printf(" 2-PTKSA-RC");
991 printf(" 4-PTKSA-RC");
994 printf(" 16-PTKSA-RC");
997 switch ((capa
& 0x0030) >> 4) {
999 printf(" 1-GTKSA-RC");
1002 printf(" 2-GTKSA-RC");
1005 printf(" 4-GTKSA-RC");
1008 printf(" 16-GTKSA-RC");
1012 printf(" MFP-required");
1014 printf(" MFP-capable");
1016 printf(" Peerkey-enabled");
1018 printf(" SPP-AMSDU-capable");
1020 printf(" SPP-AMSDU-required");
1021 printf(" (0x%.4x)\n", capa
);
1027 int pmkid_count
= data
[0] | (data
[1] << 8);
1029 if (len
>= 2 + 16 * pmkid_count
) {
1030 tab_on_first(&first
);
1031 printf("\t * %d PMKIDs\n", pmkid_count
);
1032 /* not printing PMKID values */
1033 data
+= 2 + 16 * pmkid_count
;
1034 len
-= 2 + 16 * pmkid_count
;
1040 tab_on_first(&first
);
1041 printf("\t * Group mgmt cipher suite: ");
1050 printf("\t\t * bogus tail data (%d):", len
);
1052 printf(" %.2x", *data
);
1060 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
1061 uint8_t len
, const uint8_t *data
)
1063 _print_rsn_ie(defcipher
, defauth
, len
, data
, 0);
1066 static void print_osen_ie(const char *defcipher
, const char *defauth
,
1067 uint8_t len
, const uint8_t *data
)
1070 _print_rsn_ie(defcipher
, defauth
, len
, data
, 1);
1073 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1074 const struct print_ies_data
*ie_buffer
)
1076 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
1079 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1080 const struct print_ies_data
*ie_buffer
)
1083 print_ht_capability(data
[0] | (data
[1] << 8));
1084 print_ampdu_length(data
[2] & 3);
1085 print_ampdu_spacing((data
[2] >> 2) & 7);
1086 print_ht_mcs(data
+ 3);
1089 static const char* ntype_11u(uint8_t t
)
1092 case 0: return "Private";
1093 case 1: return "Private with Guest";
1094 case 2: return "Chargeable Public";
1095 case 3: return "Free Public";
1096 case 4: return "Personal Device";
1097 case 5: return "Emergency Services Only";
1098 case 14: return "Test or Experimental";
1099 case 15: return "Wildcard";
1100 default: return "Reserved";
1104 static const char* vgroup_11u(uint8_t t
)
1107 case 0: return "Unspecified";
1108 case 1: return "Assembly";
1109 case 2: return "Business";
1110 case 3: return "Educational";
1111 case 4: return "Factory and Industrial";
1112 case 5: return "Institutional";
1113 case 6: return "Mercantile";
1114 case 7: return "Residential";
1115 case 8: return "Storage";
1116 case 9: return "Utility and Miscellaneous";
1117 case 10: return "Vehicular";
1118 case 11: return "Outdoor";
1119 default: return "Reserved";
1123 static void print_interworking(const uint8_t type
, uint8_t len
,
1124 const uint8_t *data
,
1125 const struct print_ies_data
*ie_buffer
)
1127 /* See Section 7.3.2.92 in the 802.11u spec. */
1130 uint8_t ano
= data
[0];
1131 printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano
));
1132 printf("\t\t\tNetwork Type: %i (%s)\n",
1133 (int)(ano
& 0xf), ntype_11u(ano
& 0xf));
1135 printf("\t\t\tInternet\n");
1137 printf("\t\t\tASRA\n");
1139 printf("\t\t\tESR\n");
1141 printf("\t\t\tUESA\n");
1143 if ((len
== 3) || (len
== 9)) {
1144 printf("\t\tVenue Group: %i (%s)\n",
1145 (int)(data
[1]), vgroup_11u(data
[1]));
1146 printf("\t\tVenue Type: %i\n", (int)(data
[2]));
1149 printf("\t\tHESSID: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
1150 data
[3], data
[4], data
[5], data
[6], data
[7], data
[8]);
1152 printf("\t\tHESSID: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
1153 data
[1], data
[2], data
[3], data
[4], data
[5], data
[6]);
1156 static void print_11u_advert(const uint8_t type
, uint8_t len
,
1157 const uint8_t *data
,
1158 const struct print_ies_data
*ie_buffer
)
1160 /* See Section 7.3.2.93 in the 802.11u spec. */
1161 /* TODO: This code below does not decode private protocol IDs */
1164 while (idx
< (len
- 1)) {
1165 uint8_t qri
= data
[idx
];
1166 uint8_t proto_id
= data
[idx
+ 1];
1167 printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri
));
1168 printf("\t\t\tQuery Response Length Limit: %i\n",
1171 printf("\t\t\tPAME-BI\n");
1174 printf("\t\t\tANQP\n"); break;
1176 printf("\t\t\tMIH Information Service\n"); break;
1178 printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
1180 printf("\t\t\tEmergency Alert System (EAS)\n"); break;
1182 printf("\t\t\tVendor Specific\n"); break;
1184 printf("\t\t\tReserved: %i\n", proto_id
); break;
1190 static void print_11u_rcon(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1191 const struct print_ies_data
*ie_buffer
)
1193 /* See Section 7.3.2.96 in the 802.11u spec. */
1195 int ln0
= data
[1] & 0xf;
1196 int ln1
= ((data
[1] & 0xf0) >> 4);
1201 ln2
= len
- 2 - ln0
- ln1
;
1203 printf("\t\tANQP OIs: %i\n", data
[0]);
1206 printf("\t\tOI 1: ");
1207 if (2 + ln0
> len
) {
1208 printf("Invalid IE length.\n");
1210 for (idx
= 0; idx
< ln0
; idx
++) {
1211 printf("%02hhx", data
[2 + idx
]);
1218 printf("\t\tOI 2: ");
1219 if (2 + ln0
+ ln1
> len
) {
1220 printf("Invalid IE length.\n");
1222 for (idx
= 0; idx
< ln1
; idx
++) {
1223 printf("%02hhx", data
[2 + ln0
+ idx
]);
1230 printf("\t\tOI 3: ");
1231 if (2 + ln0
+ ln1
+ ln2
> len
) {
1232 printf("Invalid IE length.\n");
1234 for (idx
= 0; idx
< ln2
; idx
++) {
1235 printf("%02hhx", data
[2 + ln0
+ ln1
+ idx
]);
1242 static void print_tx_power_envelope(const uint8_t type
, uint8_t len
,
1243 const uint8_t *data
,
1244 const struct print_ies_data
*ie_buffer
)
1246 const uint8_t local_max_tx_power_count
= data
[0] & 7;
1247 const uint8_t local_max_tx_power_unit_interp
= (data
[0] >> 3) & 7;
1249 static const char *power_names
[] = {
1250 "Local Maximum Transmit Power For 20 MHz",
1251 "Local Maximum Transmit Power For 40 MHz",
1252 "Local Maximum Transmit Power For 80 MHz",
1253 "Local Maximum Transmit Power For 160/80+80 MHz",
1258 if (local_max_tx_power_count
+ 2 != len
)
1260 if (local_max_tx_power_unit_interp
!= 0)
1262 for (i
= 0; i
< local_max_tx_power_count
+ 1; ++i
) {
1263 int8_t power_val
= ((int8_t)data
[1 + i
]) >> 1;
1264 int8_t point5
= data
[1 + i
] & 1;
1266 printf("\t\t * %s: %i.5 dBm\n", power_names
[i
], power_val
);
1268 printf("\t\t * %s: %i dBm\n", power_names
[i
], power_val
);
1272 static const char *ht_secondary_offset
[4] = {
1279 static void print_ht_op(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1280 const struct print_ies_data
*ie_buffer
)
1282 static const char *protection
[4] = {
1288 static const char *sta_chan_width
[2] = {
1294 printf("\t\t * primary channel: %d\n", data
[0]);
1295 printf("\t\t * secondary channel offset: %s\n",
1296 ht_secondary_offset
[data
[1] & 0x3]);
1297 printf("\t\t * STA channel width: %s\n", sta_chan_width
[(data
[1] & 0x4)>>2]);
1298 printf("\t\t * RIFS: %d\n", (data
[1] & 0x8)>>3);
1299 printf("\t\t * HT protection: %s\n", protection
[data
[2] & 0x3]);
1300 printf("\t\t * non-GF present: %d\n", (data
[2] & 0x4) >> 2);
1301 printf("\t\t * OBSS non-GF present: %d\n", (data
[2] & 0x10) >> 4);
1302 printf("\t\t * dual beacon: %d\n", (data
[4] & 0x40) >> 6);
1303 printf("\t\t * dual CTS protection: %d\n", (data
[4] & 0x80) >> 7);
1304 printf("\t\t * STBC beacon: %d\n", data
[5] & 0x1);
1305 printf("\t\t * L-SIG TXOP Prot: %d\n", (data
[5] & 0x2) >> 1);
1306 printf("\t\t * PCO active: %d\n", (data
[5] & 0x4) >> 2);
1307 printf("\t\t * PCO phase: %d\n", (data
[5] & 0x8) >> 3);
1310 static void print_capabilities(const uint8_t type
, uint8_t len
,
1311 const uint8_t *data
,
1312 const struct print_ies_data
*ie_buffer
)
1314 int i
, base
, bit
, si_duration
= 0, max_amsdu
= 0;
1315 bool s_psmp_support
= false, is_vht_cap
= false;
1316 unsigned char *ie
= ie_buffer
->ie
;
1317 int ielen
= ie_buffer
->ielen
;
1319 while (ielen
>= 2 && ielen
>= ie
[1]) {
1328 for (i
= 0; i
< len
; i
++) {
1331 for (bit
= 0; bit
< 8; bit
++) {
1332 if (!(data
[i
] & (1 << bit
)))
1337 #define CAPA(bit, name) case bit: printf(" " name); break
1339 /* if the capability 'cap' exists add 'val' to 'sum'
1340 * otherwise print 'Reserved' */
1341 #define ADD_BIT_VAL(bit, cap, sum, val) case (bit): do { \
1343 printf(" Reserved"); \
1350 switch (bit
+ base
) {
1351 CAPA(0, "HT Information Exchange Supported");
1352 CAPA(1, "reserved (On-demand Beacon)");
1353 CAPA(2, "Extended Channel Switching");
1354 CAPA(3, "reserved (Wave Indication)");
1355 CAPA(4, "PSMP Capability");
1356 CAPA(5, "reserved (Service Interval Granularity)");
1359 s_psmp_support
= true;
1360 printf(" S-PSMP Capability");
1364 CAPA(8, "Diagnostics");
1365 CAPA(9, "Multicast Diagnostics");
1366 CAPA(10, "Location Tracking");
1368 CAPA(12, "Proxy ARP Service");
1369 CAPA(13, "Collocated Interference Reporting");
1370 CAPA(14, "Civic Location");
1371 CAPA(15, "Geospatial Location");
1373 CAPA(17, "WNM-Sleep Mode");
1374 CAPA(18, "TIM Broadcast");
1375 CAPA(19, "BSS Transition");
1376 CAPA(20, "QoS Traffic Capability");
1377 CAPA(21, "AC Station Count");
1378 CAPA(22, "Multiple BSSID");
1379 CAPA(23, "Timing Measurement");
1380 CAPA(24, "Channel Usage");
1381 CAPA(25, "SSID List");
1383 CAPA(27, "UTC TSF Offset");
1384 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1385 CAPA(29, "TDLS Peer PSM Support");
1386 CAPA(30, "TDLS channel switching");
1387 CAPA(31, "Interworking");
1388 CAPA(32, "QoS Map");
1390 CAPA(34, "SSPN Interface");
1391 CAPA(35, "Reserved");
1392 CAPA(36, "MSGCF Capability");
1393 CAPA(37, "TDLS Support");
1394 CAPA(38, "TDLS Prohibited");
1395 CAPA(39, "TDLS Channel Switching Prohibited");
1396 CAPA(40, "Reject Unadmitted Frame");
1398 ADD_BIT_VAL(41, s_psmp_support
, si_duration
, 1);
1399 ADD_BIT_VAL(42, s_psmp_support
, si_duration
, 2);
1400 ADD_BIT_VAL(43, s_psmp_support
, si_duration
, 4);
1402 CAPA(44, "Identifier Location");
1403 CAPA(45, "U-APSD Coexistence");
1404 CAPA(46, "WNM-Notification");
1405 CAPA(47, "Reserved");
1406 CAPA(48, "UTF-8 SSID");
1407 CAPA(49, "QMFActivated");
1408 CAPA(50, "QMFReconfigurationActivated");
1409 CAPA(51, "Robust AV Streaming");
1410 CAPA(52, "Advanced GCR");
1411 CAPA(53, "Mesh GCR");
1413 CAPA(55, "QLoad Report");
1414 CAPA(56, "Alternate EDCA");
1415 CAPA(57, "Unprotected TXOP Negotiation");
1416 CAPA(58, "Protected TXOP egotiation");
1417 CAPA(59, "Reserved");
1418 CAPA(60, "Protected QLoad Report");
1419 CAPA(61, "TDLS Wider Bandwidth");
1420 CAPA(62, "Operating Mode Notification");
1422 ADD_BIT_VAL(63, is_vht_cap
, max_amsdu
, 1);
1423 ADD_BIT_VAL(64, is_vht_cap
, max_amsdu
, 2);
1425 CAPA(65, "Channel Schedule Management");
1426 CAPA(66, "Geodatabase Inband Enabling Signal");
1427 CAPA(67, "Network Channel Control");
1428 CAPA(68, "White Space Map");
1429 CAPA(69, "Channel Availability Query");
1430 CAPA(70, "FTM Responder");
1431 CAPA(71, "FTM Initiator");
1432 CAPA(72, "Reserved");
1433 CAPA(73, "Extended Spectrum Management Capable");
1434 CAPA(74, "Reserved");
1445 printf("\n\t\t * Service Interval Granularity is %d ms",
1446 (si_duration
+ 1) * 5);
1449 printf("\n\t\t * Max Number Of MSDUs In A-MSDU is ");
1450 switch (max_amsdu
) {
1452 printf("unlimited");
1471 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1472 const struct print_ies_data
*ie_buffer
)
1474 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1476 data
[0], data
[1], data
[2], data
[3]);
1478 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
1482 static void print_ibssatim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1483 const struct print_ies_data
*ie_buffer
)
1485 printf(" %d TUs\n", (data
[1] << 8) + data
[0]);
1488 static void print_vht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1489 const struct print_ies_data
*ie_buffer
)
1492 print_vht_info((__u32
) data
[0] | ((__u32
)data
[1] << 8) |
1493 ((__u32
)data
[2] << 16) | ((__u32
)data
[3] << 24),
1497 static void print_vht_oper(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1498 const struct print_ies_data
*ie_buffer
)
1500 const char *chandwidths
[] = {
1501 [0] = "20 or 40 MHz",
1508 printf("\t\t * channel width: %d (%s)\n", data
[0],
1509 data
[0] < ARRAY_SIZE(chandwidths
) ? chandwidths
[data
[0]] : "unknown");
1510 printf("\t\t * center freq segment 1: %d\n", data
[1]);
1511 printf("\t\t * center freq segment 2: %d\n", data
[2]);
1512 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data
[4], data
[3]);
1515 static void print_supp_op_classes(const uint8_t type
, uint8_t len
,
1516 const uint8_t *data
,
1517 const struct print_ies_data
*ie_buffer
)
1519 uint8_t *p
= (uint8_t*) data
;
1520 const uint8_t *next_data
= p
+ len
;
1521 int zero_delimiter
= 0;
1522 int one_hundred_thirty_delimiter
= 0;
1525 printf("\t\t * current operating class: %d\n", *p
);
1526 while (++p
< next_data
) {
1528 one_hundred_thirty_delimiter
= 1;
1535 printf("\t\t * operating class: %d\n", *p
);
1537 if (one_hundred_thirty_delimiter
)
1538 while (++p
< next_data
) {
1539 printf("\t\t * current operating class extension: %d\n", *p
);
1542 while (++p
< next_data
- 1) {
1543 printf("\t\t * operating class tuple: %d %d\n", p
[0], p
[1]);
1549 static void print_measurement_pilot_tx(const uint8_t type
, uint8_t len
,
1550 const uint8_t *data
,
1551 const struct print_ies_data
*ie_buffer
)
1553 uint8_t *p
, len_remaining
;
1556 printf("\t\t * interval: %d TUs\n", data
[0]);
1561 p
= (uint8_t *) data
+ 1;
1562 len_remaining
= len
- 1;
1564 while (len_remaining
>=5) {
1565 uint8_t subelement_id
= *p
, len
, *end
;
1574 /* 802.11-2016 only allows vendor specific elements */
1575 if (subelement_id
!= 221) {
1576 printf("\t\t * <Invalid subelement ID %d>\n", subelement_id
);
1580 if (len
< 3 || len
> len_remaining
) {
1581 printf(" <Parse error, element too short>\n");
1585 printf("\t\t * vendor specific: OUI %.2x:%.2x:%.2x, data:",
1587 /* add only two here and use ++p in while loop */
1591 printf(" %.2x", *p
);
1594 len_remaining
-= len
;
1598 static void print_obss_scan_params(const uint8_t type
, uint8_t len
,
1599 const uint8_t *data
,
1600 const struct print_ies_data
*ie_buffer
)
1603 printf("\t\t * passive dwell: %d TUs\n", (data
[1] << 8) | data
[0]);
1604 printf("\t\t * active dwell: %d TUs\n", (data
[3] << 8) | data
[2]);
1605 printf("\t\t * channel width trigger scan interval: %d s\n", (data
[5] << 8) | data
[4]);
1606 printf("\t\t * scan passive total per channel: %d TUs\n", (data
[7] << 8) | data
[6]);
1607 printf("\t\t * scan active total per channel: %d TUs\n", (data
[9] << 8) | data
[8]);
1608 printf("\t\t * BSS width channel transition delay factor: %d\n", (data
[11] << 8) | data
[10]);
1609 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1610 ((data
[13] << 8) | data
[12]) / 100, ((data
[13] << 8) | data
[12]) % 100);
1613 static void print_secchan_offs(const uint8_t type
, uint8_t len
,
1614 const uint8_t *data
,
1615 const struct print_ies_data
*ie_buffer
)
1617 if (data
[0] < ARRAY_SIZE(ht_secondary_offset
))
1618 printf(" %s (%d)\n", ht_secondary_offset
[data
[0]], data
[0]);
1620 printf(" %d\n", data
[0]);
1623 static void print_bss_load(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1624 const struct print_ies_data
*ie_buffer
)
1627 printf("\t\t * station count: %d\n", (data
[1] << 8) | data
[0]);
1628 printf("\t\t * channel utilisation: %d/255\n", data
[2]);
1629 printf("\t\t * available admission capacity: %d [*32us]\n", (data
[4] << 8) | data
[3]);
1632 static void print_mesh_conf(const uint8_t type
, uint8_t len
,
1633 const uint8_t *data
,
1634 const struct print_ies_data
*ie_buffer
)
1637 printf("\t\t * Active Path Selection Protocol ID: %d\n", data
[0]);
1638 printf("\t\t * Active Path Selection Metric ID: %d\n", data
[1]);
1639 printf("\t\t * Congestion Control Mode ID: %d\n", data
[2]);
1640 printf("\t\t * Synchronization Method ID: %d\n", data
[3]);
1641 printf("\t\t * Authentication Protocol ID: %d\n", data
[4]);
1642 printf("\t\t * Mesh Formation Info:\n");
1643 printf("\t\t\t Number of Peerings: %d\n", (data
[5] & 0x7E) >> 1);
1645 printf("\t\t\t Connected to Mesh Gate\n");
1647 printf("\t\t\t Connected to AS\n");
1648 printf("\t\t * Mesh Capability\n");
1650 printf("\t\t\t Accepting Additional Mesh Peerings\n");
1652 printf("\t\t\t MCCA Supported\n");
1654 printf("\t\t\t MCCA Enabled\n");
1656 printf("\t\t\t Forwarding\n");
1658 printf("\t\t\t MBCA Supported\n");
1660 printf("\t\t\t TBTT Adjusting\n");
1662 printf("\t\t\t Mesh Power Save Level\n");
1667 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1668 const struct print_ies_data
*ie_buffer
);
1669 uint8_t minlen
, maxlen
;
1673 static void print_ie(const struct ie_print
*p
, const uint8_t type
, uint8_t len
,
1674 const uint8_t *data
,
1675 const struct print_ies_data
*ie_buffer
)
1682 printf("\t%s:", p
->name
);
1683 if (len
< p
->minlen
|| len
> p
->maxlen
) {
1685 printf(" <invalid: %d bytes:", len
);
1686 for (i
= 0; i
< len
; i
++)
1687 printf(" %.02x", data
[i
]);
1690 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
1692 printf(" <invalid: no data>\n");
1696 p
->print(type
, len
, data
, ie_buffer
);
1699 #define PRINT_IGN { \
1706 static const struct ie_print ieprinters
[] = {
1707 [0] = { "SSID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1708 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1709 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
1710 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
1711 [6] = { "IBSS ATIM window", print_ibssatim
, 2, 2, BIT(PRINT_SCAN
), },
1712 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
1713 [11] = { "BSS Load", print_bss_load
, 5, 5, BIT(PRINT_SCAN
), },
1714 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
1715 [35] = { "TPC report", print_tpcreport
, 2, 2, BIT(PRINT_SCAN
), },
1716 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1717 [45] = { "HT capabilities", print_ht_capa
, 26, 26, BIT(PRINT_SCAN
), },
1718 [47] = { "ERP D4.0", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1719 [51] = { "AP Channel Report", print_ap_channel_report
, 1, 255, BIT(PRINT_SCAN
), },
1720 [59] = { "Supported operating classes", print_supp_op_classes
, 1, 255, BIT(PRINT_SCAN
), },
1721 [66] = { "Measurement Pilot Transmission", print_measurement_pilot_tx
, 1, 255, BIT(PRINT_SCAN
), },
1722 [74] = { "Overlapping BSS scan params", print_obss_scan_params
, 14, 255, BIT(PRINT_SCAN
), },
1723 [61] = { "HT operation", print_ht_op
, 22, 22, BIT(PRINT_SCAN
), },
1724 [62] = { "Secondary Channel Offset", print_secchan_offs
, 1, 1, BIT(PRINT_SCAN
), },
1725 [191] = { "VHT capabilities", print_vht_capa
, 12, 255, BIT(PRINT_SCAN
), },
1726 [192] = { "VHT operation", print_vht_oper
, 5, 255, BIT(PRINT_SCAN
), },
1727 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
1728 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1729 [70] = { "RM enabled capabilities", print_rm_enabled_capabilities
, 5, 5, BIT(PRINT_SCAN
), },
1730 [113] = { "MESH Configuration", print_mesh_conf
, 7, 7, BIT(PRINT_SCAN
), },
1731 [114] = { "MESH ID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1732 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
1733 [107] = { "802.11u Interworking", print_interworking
, 0, 255, BIT(PRINT_SCAN
), },
1734 [108] = { "802.11u Advertisement", print_11u_advert
, 0, 255, BIT(PRINT_SCAN
), },
1735 [111] = { "802.11u Roaming Consortium", print_11u_rcon
, 2, 255, BIT(PRINT_SCAN
), },
1736 [195] = { "Transmit Power Envelope", print_tx_power_envelope
, 2, 5, BIT(PRINT_SCAN
), },
1739 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1740 const struct print_ies_data
*ie_buffer
)
1742 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
1745 static void print_wifi_osen(const uint8_t type
, uint8_t len
,
1746 const uint8_t *data
,
1747 const struct print_ies_data
*ie_buffer
)
1749 print_osen_ie("OSEN", "OSEN", len
, data
);
1752 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
1755 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
1761 printf("Parameter: not version 1: ");
1765 printf("\t * Parameter version 1");
1770 printf("\n\t\t * u-APSD");
1774 for (i
= 0; i
< 4; i
++) {
1775 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
1778 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
1779 (1 << (data
[1] >> 4)) - 1);
1780 printf(", AIFSN %d", data
[0] & 0xf);
1781 if (data
[2] | data
[3])
1782 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
1790 printf("invalid: ");
1794 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1795 const struct print_ies_data
*ie_buffer
)
1801 printf(" information:");
1804 if (print_wifi_wmm_param(data
+ 1, len
- 1))
1808 printf(" type %d:", data
[0]);
1812 for(i
= 1; i
< len
; i
++)
1813 printf(" %.02x", data
[i
]);
1817 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
1821 return "Default (PIN)";
1823 return "User-specified";
1825 return "Machine-specified";
1829 return "PushButton";
1831 return "Registrar-specified";
1837 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1838 const struct print_ies_data
*ie_buffer
)
1841 __u16 subtype
, sublen
;
1844 subtype
= (data
[0] << 8) + data
[1];
1845 sublen
= (data
[2] << 8) + data
[3];
1846 if (sublen
> len
- 4)
1851 tab_on_first(&first
);
1853 printf("\t * Version: (invalid "
1854 "length %d)\n", sublen
);
1857 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
1860 tab_on_first(&first
);
1862 printf("\t * Device Name: (invalid length %d)\n",
1866 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
1870 tab_on_first(&first
);
1872 printf("\t * Device Password ID: (invalid length %d)\n",
1876 id
= data
[4] << 8 | data
[5];
1877 printf("\t * Device Password ID: %u (%s)\n",
1878 id
, wifi_wps_dev_passwd_id(id
));
1882 tab_on_first(&first
);
1884 printf("\t * Manufacturer: (invalid length %d)\n",
1888 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
1891 tab_on_first(&first
);
1893 printf("\t * Model: (invalid length %d)\n",
1897 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
1900 tab_on_first(&first
);
1902 printf("\t * Model Number: (invalid length %d)\n",
1906 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
1912 printf("\t * Response Type: (invalid length %d)\n",
1917 tab_on_first(&first
);
1918 printf("\t * Response Type: %d%s\n",
1919 val
, val
== 3 ? " (AP)" : "");
1926 printf("\t * RF Bands: (invalid length %d)\n",
1931 tab_on_first(&first
);
1932 printf("\t * RF Bands: 0x%x\n", val
);
1939 printf("\t * Selected Registrar: (invalid length %d)\n",
1944 tab_on_first(&first
);
1945 printf("\t * Selected Registrar: 0x%x\n", val
);
1949 tab_on_first(&first
);
1951 printf("\t * Serial Number: (invalid length %d)\n",
1955 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
1961 printf("\t * Wi-Fi Protected Setup State: (invalid length %d)\n",
1966 tab_on_first(&first
);
1967 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1969 val
== 1 ? " (Unconfigured)" : "",
1970 val
== 2 ? " (Configured)" : "");
1974 tab_on_first(&first
);
1975 printf("\t * UUID: ");
1977 printf("(invalid, length=%d)\n", sublen
);
1980 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1981 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1982 data
[4], data
[5], data
[6], data
[7],
1983 data
[8], data
[9], data
[10], data
[11],
1984 data
[12], data
[13], data
[14], data
[15],
1985 data
[16], data
[17], data
[18], data
[19]);
1988 tab_on_first(&first
);
1995 uint8_t v2
= data
[9];
1996 printf("\t * Version2: %d.%d\n", v2
>> 4, v2
& 0xf);
2000 tab_on_first(&first
);
2002 printf("\t * Primary Device Type: (invalid length %d)\n",
2006 printf("\t * Primary Device Type: "
2007 "%u-%02x%02x%02x%02x-%u\n",
2008 data
[4] << 8 | data
[5],
2009 data
[6], data
[7], data
[8], data
[9],
2010 data
[10] << 8 | data
[11]);
2015 tab_on_first(&first
);
2017 printf("\t * AP setup locked: (invalid length %d)\n",
2022 printf("\t * AP setup locked: 0x%.2x\n", val
);
2031 printf("\t * Config methods: (invalid length %d)\n",
2035 meth
= (data
[4] << 8) + data
[5];
2037 tab_on_first(&first
);
2038 printf("\t * %sConfig methods:",
2039 subtype
== 0x1053 ? "Selected Registrar ": "");
2040 #define T(bit, name) do { \
2041 if (meth & (1<<bit)) { \
2061 const __u8
*subdata
= data
+ 4;
2062 __u16 tmplen
= sublen
;
2064 tab_on_first(&first
);
2065 printf("\t * Unknown TLV (%#.4x, %d bytes):",
2068 printf(" %.2x", *subdata
);
2082 printf("\t\t * bogus tail data (%d):", len
);
2084 printf(" %.2x", *data
);
2092 static const struct ie_print wifiprinters
[] = {
2093 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
2094 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
2095 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
2098 static inline void print_p2p(const uint8_t type
, uint8_t len
,
2099 const uint8_t *data
,
2100 const struct print_ies_data
*ie_buffer
)
2108 sublen
= (data
[2] << 8) + data
[1];
2110 if (sublen
> len
- 3)
2114 case 0x02: /* capability */
2115 tab_on_first(&first
);
2117 printf("\t * malformed capability\n");
2120 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
2123 case 0x0d: /* device info */
2124 if (sublen
< 6 + 2 + 8 + 1) {
2125 printf("\t * malformed device info\n");
2129 case 0x00: /* status */
2130 case 0x01: /* minor reason */
2131 case 0x03: /* device ID */
2132 case 0x04: /* GO intent */
2133 case 0x05: /* configuration timeout */
2134 case 0x06: /* listen channel */
2135 case 0x07: /* group BSSID */
2136 case 0x08: /* ext listen timing */
2137 case 0x09: /* intended interface address */
2138 case 0x0a: /* manageability */
2139 case 0x0b: /* channel list */
2140 case 0x0c: /* NoA */
2141 case 0x0e: /* group info */
2142 case 0x0f: /* group ID */
2143 case 0x10: /* interface */
2144 case 0x11: /* operating channel */
2145 case 0x12: /* invitation flags */
2146 case 0xdd: /* vendor specific */
2148 const __u8
*subdata
= data
+ 3;
2149 __u16 tmplen
= sublen
;
2151 tab_on_first(&first
);
2152 printf("\t * Unknown TLV (%#.2x, %d bytes):",
2155 printf(" %.2x", *subdata
);
2169 tab_on_first(&first
);
2170 printf("\t * bogus tail data (%d):", len
);
2172 printf(" %.2x", *data
);
2180 static inline void print_hs20_ind(const uint8_t type
, uint8_t len
,
2181 const uint8_t *data
,
2182 const struct print_ies_data
*ie_buffer
)
2184 /* I can't find the spec for this...just going off what wireshark uses. */
2187 printf("\t\tDGAF: %i\n", (int)(data
[0] & 0x1));
2189 printf("\t\tUnexpected length: %i\n", len
);
2192 static void print_wifi_owe_tarns(const uint8_t type
, uint8_t len
,
2193 const uint8_t *data
,
2194 const struct print_ies_data
*ie_buffer
)
2203 mac_addr_n2a(mac_addr
, data
);
2204 printf("\t\tBSSID: %s\n", mac_addr
);
2207 if (ssid_len
> len
- 7)
2209 printf("\t\tSSID: ");
2210 print_ssid_escaped(ssid_len
, data
+ 7);
2213 /* optional elements */
2214 if (len
>= ssid_len
+ 9) {
2215 printf("\t\tBand Info: %u\n", data
[ssid_len
+ 7]);
2216 printf("\t\tChannel Info: %u\n", data
[ssid_len
+ 8]);
2220 static const struct ie_print wfa_printers
[] = {
2221 [9] = { "P2P", print_p2p
, 2, 255, BIT(PRINT_SCAN
), },
2222 [16] = { "HotSpot 2.0 Indication", print_hs20_ind
, 1, 255, BIT(PRINT_SCAN
), },
2223 [18] = { "HotSpot 2.0 OSEN", print_wifi_osen
, 1, 255, BIT(PRINT_SCAN
), },
2224 [28] = { "OWE Transition Mode", print_wifi_owe_tarns
, 7, 255, BIT(PRINT_SCAN
), },
2227 static void print_vendor(unsigned char len
, unsigned char *data
,
2228 bool unknown
, enum print_ie_type ptype
)
2233 printf("\tVendor specific: <too short> data:");
2234 for(i
= 0; i
< len
; i
++)
2235 printf(" %.02x", data
[i
]);
2240 if (len
>= 4 && memcmp(data
, ms_oui
, 3) == 0) {
2241 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
2242 wifiprinters
[data
[3]].name
&&
2243 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
2244 print_ie(&wifiprinters
[data
[3]],
2245 data
[3], len
- 4, data
+ 4,
2251 printf("\tMS/WiFi %#.2x, data:", data
[3]);
2252 for(i
= 0; i
< len
- 4; i
++)
2253 printf(" %.02x", data
[i
+ 4]);
2258 if (len
>= 4 && memcmp(data
, wfa_oui
, 3) == 0) {
2259 if (data
[3] < ARRAY_SIZE(wfa_printers
) &&
2260 wfa_printers
[data
[3]].name
&&
2261 wfa_printers
[data
[3]].flags
& BIT(ptype
)) {
2262 print_ie(&wfa_printers
[data
[3]],
2263 data
[3], len
- 4, data
+ 4,
2269 printf("\tWFA %#.2x, data:", data
[3]);
2270 for(i
= 0; i
< len
- 4; i
++)
2271 printf(" %.02x", data
[i
+ 4]);
2279 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
2280 data
[0], data
[1], data
[2]);
2281 for (i
= 3; i
< len
; i
++)
2282 printf(" %.2x", data
[i
]);
2286 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
2287 enum print_ie_type ptype
)
2289 struct print_ies_data ie_buffer
= {
2293 if (ie
== NULL
|| ielen
< 0)
2296 while (ielen
>= 2 && ielen
- 2 >= ie
[1]) {
2297 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
2298 ieprinters
[ie
[0]].name
&&
2299 ieprinters
[ie
[0]].flags
& BIT(ptype
)) {
2300 print_ie(&ieprinters
[ie
[0]],
2301 ie
[0], ie
[1], ie
+ 2, &ie_buffer
);
2302 } else if (ie
[0] == 221 /* vendor */) {
2303 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
2304 } else if (unknown
) {
2307 printf("\tUnknown IE (%d):", ie
[0]);
2308 for (i
=0; i
<ie
[1]; i
++)
2309 printf(" %.2x", ie
[2+i
]);
2317 static void print_capa_dmg(__u16 capa
)
2319 switch (capa
& WLAN_CAPABILITY_DMG_TYPE_MASK
) {
2320 case WLAN_CAPABILITY_DMG_TYPE_AP
:
2323 case WLAN_CAPABILITY_DMG_TYPE_PBSS
:
2326 case WLAN_CAPABILITY_DMG_TYPE_IBSS
:
2327 printf(" DMG_IBSS");
2331 if (capa
& WLAN_CAPABILITY_DMG_CBAP_ONLY
)
2332 printf(" CBAP_Only");
2333 if (capa
& WLAN_CAPABILITY_DMG_CBAP_SOURCE
)
2334 printf(" CBAP_Src");
2335 if (capa
& WLAN_CAPABILITY_DMG_PRIVACY
)
2337 if (capa
& WLAN_CAPABILITY_DMG_ECPAC
)
2339 if (capa
& WLAN_CAPABILITY_DMG_SPECTRUM_MGMT
)
2340 printf(" SpectrumMgmt");
2341 if (capa
& WLAN_CAPABILITY_DMG_RADIO_MEASURE
)
2342 printf(" RadioMeasure");
2345 static void print_capa_non_dmg(__u16 capa
)
2347 if (capa
& WLAN_CAPABILITY_ESS
)
2349 if (capa
& WLAN_CAPABILITY_IBSS
)
2351 if (capa
& WLAN_CAPABILITY_CF_POLLABLE
)
2352 printf(" CfPollable");
2353 if (capa
& WLAN_CAPABILITY_CF_POLL_REQUEST
)
2354 printf(" CfPollReq");
2355 if (capa
& WLAN_CAPABILITY_PRIVACY
)
2357 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
2358 printf(" ShortPreamble");
2359 if (capa
& WLAN_CAPABILITY_PBCC
)
2361 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
2362 printf(" ChannelAgility");
2363 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
2364 printf(" SpectrumMgmt");
2365 if (capa
& WLAN_CAPABILITY_QOS
)
2367 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
2368 printf(" ShortSlotTime");
2369 if (capa
& WLAN_CAPABILITY_APSD
)
2371 if (capa
& WLAN_CAPABILITY_RADIO_MEASURE
)
2372 printf(" RadioMeasure");
2373 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
2374 printf(" DSSS-OFDM");
2375 if (capa
& WLAN_CAPABILITY_DEL_BACK
)
2376 printf(" DelayedBACK");
2377 if (capa
& WLAN_CAPABILITY_IMM_BACK
)
2378 printf(" ImmediateBACK");
2381 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
2383 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
2384 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
2385 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
2386 char mac_addr
[20], dev
[20];
2387 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
2388 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
2389 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
2390 [NL80211_BSS_BSSID
] = { },
2391 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
2392 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
2393 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
2394 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
2395 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
2396 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
2397 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
2398 [NL80211_BSS_BEACON_IES
] = { },
2400 struct scan_params
*params
= arg
;
2401 int show
= params
->show_both_ie_sets
? 2 : 1;
2402 bool is_dmg
= false;
2404 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
2405 genlmsg_attrlen(gnlh
, 0), NULL
);
2407 if (!tb
[NL80211_ATTR_BSS
]) {
2408 fprintf(stderr
, "bss info missing!\n");
2411 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
2412 tb
[NL80211_ATTR_BSS
],
2414 fprintf(stderr
, "failed to parse nested attributes!\n");
2418 if (!bss
[NL80211_BSS_BSSID
])
2421 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
2422 printf("BSS %s", mac_addr
);
2423 if (tb
[NL80211_ATTR_IFINDEX
]) {
2424 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
2425 printf("(on %s)", dev
);
2428 if (bss
[NL80211_BSS_STATUS
]) {
2429 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
2430 case NL80211_BSS_STATUS_AUTHENTICATED
:
2431 printf(" -- authenticated");
2433 case NL80211_BSS_STATUS_ASSOCIATED
:
2434 printf(" -- associated");
2436 case NL80211_BSS_STATUS_IBSS_JOINED
:
2437 printf(" -- joined");
2440 printf(" -- unknown status: %d",
2441 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
2447 if (bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]) {
2448 unsigned long long bt
;
2449 bt
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]);
2450 printf("\tlast seen: %llu.%.3llus [boottime]\n", bt
/1000000000, (bt
%1000000000)/1000000);
2453 if (bss
[NL80211_BSS_TSF
]) {
2454 unsigned long long tsf
;
2455 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
2456 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
2457 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
2458 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
2460 if (bss
[NL80211_BSS_FREQUENCY
]) {
2461 int freq
= nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]);
2462 printf("\tfreq: %d\n", freq
);
2466 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
2467 printf("\tbeacon interval: %d TUs\n",
2468 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
2469 if (bss
[NL80211_BSS_CAPABILITY
]) {
2470 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
2471 printf("\tcapability:");
2473 print_capa_dmg(capa
);
2475 print_capa_non_dmg(capa
);
2476 printf(" (0x%.4x)\n", capa
);
2478 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
2479 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
2480 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
2482 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
2483 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
2484 printf("\tsignal: %d/100\n", s
);
2486 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
2487 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
2488 printf("\tlast seen: %d ms ago\n", age
);
2491 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
2492 struct nlattr
*ies
= bss
[NL80211_BSS_INFORMATION_ELEMENTS
];
2493 struct nlattr
*bcnies
= bss
[NL80211_BSS_BEACON_IES
];
2495 if (bss
[NL80211_BSS_PRESP_DATA
] ||
2496 (bcnies
&& (nla_len(ies
) != nla_len(bcnies
) ||
2497 memcmp(nla_data(ies
), nla_data(bcnies
),
2499 printf("\tInformation elements from Probe Response "
2501 print_ies(nla_data(ies
), nla_len(ies
),
2502 params
->unknown
, params
->type
);
2504 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
2505 printf("\tInformation elements from Beacon frame:\n");
2506 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
2507 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
2508 params
->unknown
, params
->type
);
2514 static struct scan_params scan_params
;
2516 static int handle_scan_dump(struct nl80211_state
*state
,
2518 int argc
, char **argv
,
2524 memset(&scan_params
, 0, sizeof(scan_params
));
2526 if (argc
== 1 && !strcmp(argv
[0], "-u"))
2527 scan_params
.unknown
= true;
2528 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
2529 scan_params
.show_both_ie_sets
= true;
2531 scan_params
.type
= PRINT_SCAN
;
2533 register_handler(print_bss_handler
, &scan_params
);
2537 static int handle_scan_combined(struct nl80211_state
*state
,
2539 int argc
, char **argv
,
2543 static char *dump_argv
[] = {
2549 static const __u32 cmds
[] = {
2550 NL80211_CMD_NEW_SCAN_RESULTS
,
2551 NL80211_CMD_SCAN_ABORTED
,
2553 int trig_argc
, dump_argc
, err
;
2556 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
2558 dump_argv
[3] = "-u";
2559 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
2561 dump_argv
[3] = "-b";
2565 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
2566 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
2569 trig_argv
[0] = argv
[0];
2570 trig_argv
[1] = "scan";
2571 trig_argv
[2] = "trigger";
2573 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
2574 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
2575 err
= handle_cmd(state
, id
, trig_argc
, trig_argv
);
2581 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
2583 * This code has a bug, which requires creating a separate
2584 * nl80211 socket to fix:
2585 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
2586 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
2587 * before (!) we listen to it, because we only start listening
2588 * after we send our scan request.
2590 * Doing it the other way around has a race condition as well,
2591 * if you first open the events socket you may get a notification
2592 * for a previous scan.
2594 * The only proper way to fix this would be to listen to events
2595 * before sending the command, and for the kernel to send the
2596 * scan request along with the event, so that you can match up
2597 * whether the scan you requested was finished or aborted (this
2598 * may result in processing a scan that another application
2599 * requested, but that doesn't seem to be a problem).
2601 * Alas, the kernel doesn't do that (yet).
2604 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
2605 NL80211_CMD_SCAN_ABORTED
) {
2606 printf("scan aborted!\n");
2610 dump_argv
[0] = argv
[0];
2611 return handle_cmd(state
, id
, dump_argc
, dump_argv
);
2613 TOPLEVEL(scan
, "[-u] [freq <freq>*] [duration <dur>] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force,duration-mandatory] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]", 0, 0,
2614 CIB_NETDEV
, handle_scan_combined
,
2615 "Scan on the given frequencies and probe for the given SSIDs\n"
2616 "(or wildcard if not given) unless passive scanning is requested.\n"
2617 "If -u is specified print unknown data in the scan results.\n"
2618 "Specified (vendor) IEs must be well-formed.");
2619 COMMAND(scan
, dump
, "[-u]",
2620 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
2621 "Dump the current scan results. If -u is specified, print unknown\n"
2622 "data in scan results.");
2623 COMMAND(scan
, trigger
, "[freq <freq>*] [duration <dur>] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force,duration-mandatory] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]",
2624 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
2625 "Trigger a scan on the given frequencies with probing for the given\n"
2626 "SSIDs (or wildcard if not given) unless passive scanning is requested.\n"
2627 "Duration(in TUs), if specified, will be used to set dwell times.\n");
2630 static int handle_scan_abort(struct nl80211_state
*state
,
2632 int argc
, char **argv
,
2637 COMMAND(scan
, abort
, "",
2638 NL80211_CMD_ABORT_SCAN
, 0, CIB_NETDEV
, handle_scan_abort
,
2639 "Abort ongoing scan");
2641 static int handle_start_sched_scan(struct nl80211_state
*state
,
2643 int argc
, char **argv
, enum id_input id
)
2645 return parse_sched_scan(msg
, &argc
, &argv
);
2648 static int handle_stop_sched_scan(struct nl80211_state
*state
,
2649 struct nl_msg
*msg
, int argc
, char **argv
,
2658 COMMAND(scan
, sched_start
,
2660 NL80211_CMD_START_SCHED_SCAN
, 0, CIB_NETDEV
, handle_start_sched_scan
,
2661 "Start a scheduled scan at the specified interval on the given frequencies\n"
2662 "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2663 "scanning is requested. If matches are specified, only matching results\n"
2664 "will be returned.");
2665 COMMAND(scan
, sched_stop
, "",
2666 NL80211_CMD_STOP_SCHED_SCAN
, 0, CIB_NETDEV
, handle_stop_sched_scan
,
2667 "Stop an ongoing scheduled scan.");