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_cipher(const uint8_t *data
)
737 if (memcmp(data
, ms_oui
, 3) == 0) {
740 printf("Use group cipher suite");
755 printf("%.02x-%.02x-%.02x:%d",
756 data
[0], data
[1] ,data
[2], data
[3]);
759 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
762 printf("Use group cipher suite");
777 printf("AES-128-CMAC");
786 printf("%.02x-%.02x-%.02x:%d",
787 data
[0], data
[1] ,data
[2], data
[3]);
791 printf("%.02x-%.02x-%.02x:%d",
792 data
[0], data
[1] ,data
[2], data
[3]);
795 static void print_auth(const uint8_t *data
)
797 if (memcmp(data
, ms_oui
, 3) == 0) {
800 printf("IEEE 802.1X");
806 printf("%.02x-%.02x-%.02x:%d",
807 data
[0], data
[1] ,data
[2], data
[3]);
810 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
813 printf("IEEE 802.1X");
819 printf("FT/IEEE 802.1X");
825 printf("IEEE 802.1X/SHA-256");
828 printf("PSK/SHA-256");
840 printf("IEEE 802.1X/SUITE-B");
843 printf("IEEE 802.1X/SUITE-B-192");
846 printf("FT/IEEE 802.1X/SHA-384");
849 printf("FILS/SHA-256");
852 printf("FILS/SHA-384");
855 printf("FT/FILS/SHA-256");
858 printf("FT/FILS/SHA-384");
864 printf("%.02x-%.02x-%.02x:%d",
865 data
[0], data
[1] ,data
[2], data
[3]);
868 } else if (memcmp(data
, wfa_oui
, 3) == 0) {
877 printf("%.02x-%.02x-%.02x:%d",
878 data
[0], data
[1] ,data
[2], data
[3]);
882 printf("%.02x-%.02x-%.02x:%d",
883 data
[0], data
[1] ,data
[2], data
[3]);
886 static void _print_rsn_ie(const char *defcipher
, const char *defauth
,
887 uint8_t len
, const uint8_t *data
, int is_osen
)
895 version
= data
[0] + (data
[1] << 8);
896 tab_on_first(&first
);
897 printf("\t * Version: %d\n", version
);
904 tab_on_first(&first
);
905 printf("\t * Group cipher: %s\n", defcipher
);
906 printf("\t * Pairwise ciphers: %s\n", defcipher
);
910 tab_on_first(&first
);
911 printf("\t * Group cipher: ");
919 tab_on_first(&first
);
920 printf("\t * Pairwise ciphers: %s\n", defcipher
);
924 count
= data
[0] | (data
[1] << 8);
925 if (2 + (count
* 4) > len
)
928 tab_on_first(&first
);
929 printf("\t * Pairwise ciphers:");
930 for (i
= 0; i
< count
; i
++) {
932 print_cipher(data
+ 2 + (i
* 4));
936 data
+= 2 + (count
* 4);
937 len
-= 2 + (count
* 4);
940 tab_on_first(&first
);
941 printf("\t * Authentication suites: %s\n", defauth
);
945 count
= data
[0] | (data
[1] << 8);
946 if (2 + (count
* 4) > len
)
949 tab_on_first(&first
);
950 printf("\t * Authentication suites:");
951 for (i
= 0; i
< count
; i
++) {
953 print_auth(data
+ 2 + (i
* 4));
957 data
+= 2 + (count
* 4);
958 len
-= 2 + (count
* 4);
961 capa
= data
[0] | (data
[1] << 8);
962 tab_on_first(&first
);
963 printf("\t * Capabilities:");
967 printf(" NoPairwise");
968 switch ((capa
& 0x000c) >> 2) {
970 printf(" 1-PTKSA-RC");
973 printf(" 2-PTKSA-RC");
976 printf(" 4-PTKSA-RC");
979 printf(" 16-PTKSA-RC");
982 switch ((capa
& 0x0030) >> 4) {
984 printf(" 1-GTKSA-RC");
987 printf(" 2-GTKSA-RC");
990 printf(" 4-GTKSA-RC");
993 printf(" 16-GTKSA-RC");
997 printf(" MFP-required");
999 printf(" MFP-capable");
1001 printf(" Peerkey-enabled");
1003 printf(" SPP-AMSDU-capable");
1005 printf(" SPP-AMSDU-required");
1006 printf(" (0x%.4x)\n", capa
);
1012 int pmkid_count
= data
[0] | (data
[1] << 8);
1014 if (len
>= 2 + 16 * pmkid_count
) {
1015 tab_on_first(&first
);
1016 printf("\t * %d PMKIDs\n", pmkid_count
);
1017 /* not printing PMKID values */
1018 data
+= 2 + 16 * pmkid_count
;
1019 len
-= 2 + 16 * pmkid_count
;
1025 tab_on_first(&first
);
1026 printf("\t * Group mgmt cipher suite: ");
1035 printf("\t\t * bogus tail data (%d):", len
);
1037 printf(" %.2x", *data
);
1045 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
1046 uint8_t len
, const uint8_t *data
)
1048 _print_rsn_ie(defcipher
, defauth
, len
, data
, 0);
1051 static void print_osen_ie(const char *defcipher
, const char *defauth
,
1052 uint8_t len
, const uint8_t *data
)
1055 _print_rsn_ie(defcipher
, defauth
, len
, data
, 1);
1058 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1059 const struct print_ies_data
*ie_buffer
)
1061 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
1064 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1065 const struct print_ies_data
*ie_buffer
)
1068 print_ht_capability(data
[0] | (data
[1] << 8));
1069 print_ampdu_length(data
[2] & 3);
1070 print_ampdu_spacing((data
[2] >> 2) & 7);
1071 print_ht_mcs(data
+ 3);
1074 static const char* ntype_11u(uint8_t t
)
1077 case 0: return "Private";
1078 case 1: return "Private with Guest";
1079 case 2: return "Chargeable Public";
1080 case 3: return "Free Public";
1081 case 4: return "Personal Device";
1082 case 5: return "Emergency Services Only";
1083 case 14: return "Test or Experimental";
1084 case 15: return "Wildcard";
1085 default: return "Reserved";
1089 static const char* vgroup_11u(uint8_t t
)
1092 case 0: return "Unspecified";
1093 case 1: return "Assembly";
1094 case 2: return "Business";
1095 case 3: return "Educational";
1096 case 4: return "Factory and Industrial";
1097 case 5: return "Institutional";
1098 case 6: return "Mercantile";
1099 case 7: return "Residential";
1100 case 8: return "Storage";
1101 case 9: return "Utility and Miscellaneous";
1102 case 10: return "Vehicular";
1103 case 11: return "Outdoor";
1104 default: return "Reserved";
1108 static void print_interworking(const uint8_t type
, uint8_t len
,
1109 const uint8_t *data
,
1110 const struct print_ies_data
*ie_buffer
)
1112 /* See Section 7.3.2.92 in the 802.11u spec. */
1115 uint8_t ano
= data
[0];
1116 printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano
));
1117 printf("\t\t\tNetwork Type: %i (%s)\n",
1118 (int)(ano
& 0xf), ntype_11u(ano
& 0xf));
1120 printf("\t\t\tInternet\n");
1122 printf("\t\t\tASRA\n");
1124 printf("\t\t\tESR\n");
1126 printf("\t\t\tUESA\n");
1128 if ((len
== 3) || (len
== 9)) {
1129 printf("\t\tVenue Group: %i (%s)\n",
1130 (int)(data
[1]), vgroup_11u(data
[1]));
1131 printf("\t\tVenue Type: %i\n", (int)(data
[2]));
1134 printf("\t\tHESSID: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
1135 data
[3], data
[4], data
[5], data
[6], data
[7], data
[8]);
1137 printf("\t\tHESSID: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
1138 data
[1], data
[2], data
[3], data
[4], data
[5], data
[6]);
1141 static void print_11u_advert(const uint8_t type
, uint8_t len
,
1142 const uint8_t *data
,
1143 const struct print_ies_data
*ie_buffer
)
1145 /* See Section 7.3.2.93 in the 802.11u spec. */
1146 /* TODO: This code below does not decode private protocol IDs */
1149 while (idx
< (len
- 1)) {
1150 uint8_t qri
= data
[idx
];
1151 uint8_t proto_id
= data
[idx
+ 1];
1152 printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri
));
1153 printf("\t\t\tQuery Response Length Limit: %i\n",
1156 printf("\t\t\tPAME-BI\n");
1159 printf("\t\t\tANQP\n"); break;
1161 printf("\t\t\tMIH Information Service\n"); break;
1163 printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
1165 printf("\t\t\tEmergency Alert System (EAS)\n"); break;
1167 printf("\t\t\tVendor Specific\n"); break;
1169 printf("\t\t\tReserved: %i\n", proto_id
); break;
1175 static void print_11u_rcon(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1176 const struct print_ies_data
*ie_buffer
)
1178 /* See Section 7.3.2.96 in the 802.11u spec. */
1180 int ln0
= data
[1] & 0xf;
1181 int ln1
= ((data
[1] & 0xf0) >> 4);
1186 ln2
= len
- 2 - ln0
- ln1
;
1188 printf("\t\tANQP OIs: %i\n", data
[0]);
1191 printf("\t\tOI 1: ");
1192 if (2 + ln0
> len
) {
1193 printf("Invalid IE length.\n");
1195 for (idx
= 0; idx
< ln0
; idx
++) {
1196 printf("%02hhx", data
[2 + idx
]);
1203 printf("\t\tOI 2: ");
1204 if (2 + ln0
+ ln1
> len
) {
1205 printf("Invalid IE length.\n");
1207 for (idx
= 0; idx
< ln1
; idx
++) {
1208 printf("%02hhx", data
[2 + ln0
+ idx
]);
1215 printf("\t\tOI 3: ");
1216 if (2 + ln0
+ ln1
+ ln2
> len
) {
1217 printf("Invalid IE length.\n");
1219 for (idx
= 0; idx
< ln2
; idx
++) {
1220 printf("%02hhx", data
[2 + ln0
+ ln1
+ idx
]);
1227 static void print_tx_power_envelope(const uint8_t type
, uint8_t len
,
1228 const uint8_t *data
,
1229 const struct print_ies_data
*ie_buffer
)
1231 const uint8_t local_max_tx_power_count
= data
[0] & 7;
1232 const uint8_t local_max_tx_power_unit_interp
= (data
[0] >> 3) & 7;
1234 static const char *power_names
[] = {
1235 "Local Maximum Transmit Power For 20 MHz",
1236 "Local Maximum Transmit Power For 40 MHz",
1237 "Local Maximum Transmit Power For 80 MHz",
1238 "Local Maximum Transmit Power For 160/80+80 MHz",
1243 if (local_max_tx_power_count
+ 2 != len
)
1245 if (local_max_tx_power_unit_interp
!= 0)
1247 for (i
= 0; i
< local_max_tx_power_count
+ 1; ++i
) {
1248 int8_t power_val
= ((int8_t)data
[1 + i
]) >> 1;
1249 int8_t point5
= data
[1 + i
] & 1;
1251 printf("\t\t * %s: %i.5 dBm\n", power_names
[i
], power_val
);
1253 printf("\t\t * %s: %i dBm\n", power_names
[i
], power_val
);
1257 static const char *ht_secondary_offset
[4] = {
1264 static void print_ht_op(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1265 const struct print_ies_data
*ie_buffer
)
1267 static const char *protection
[4] = {
1273 static const char *sta_chan_width
[2] = {
1279 printf("\t\t * primary channel: %d\n", data
[0]);
1280 printf("\t\t * secondary channel offset: %s\n",
1281 ht_secondary_offset
[data
[1] & 0x3]);
1282 printf("\t\t * STA channel width: %s\n", sta_chan_width
[(data
[1] & 0x4)>>2]);
1283 printf("\t\t * RIFS: %d\n", (data
[1] & 0x8)>>3);
1284 printf("\t\t * HT protection: %s\n", protection
[data
[2] & 0x3]);
1285 printf("\t\t * non-GF present: %d\n", (data
[2] & 0x4) >> 2);
1286 printf("\t\t * OBSS non-GF present: %d\n", (data
[2] & 0x10) >> 4);
1287 printf("\t\t * dual beacon: %d\n", (data
[4] & 0x40) >> 6);
1288 printf("\t\t * dual CTS protection: %d\n", (data
[4] & 0x80) >> 7);
1289 printf("\t\t * STBC beacon: %d\n", data
[5] & 0x1);
1290 printf("\t\t * L-SIG TXOP Prot: %d\n", (data
[5] & 0x2) >> 1);
1291 printf("\t\t * PCO active: %d\n", (data
[5] & 0x4) >> 2);
1292 printf("\t\t * PCO phase: %d\n", (data
[5] & 0x8) >> 3);
1295 static void print_capabilities(const uint8_t type
, uint8_t len
,
1296 const uint8_t *data
,
1297 const struct print_ies_data
*ie_buffer
)
1299 int i
, base
, bit
, si_duration
= 0, max_amsdu
= 0;
1300 bool s_psmp_support
= false, is_vht_cap
= false;
1301 unsigned char *ie
= ie_buffer
->ie
;
1302 int ielen
= ie_buffer
->ielen
;
1304 while (ielen
>= 2 && ielen
>= ie
[1]) {
1313 for (i
= 0; i
< len
; i
++) {
1316 for (bit
= 0; bit
< 8; bit
++) {
1317 if (!(data
[i
] & (1 << bit
)))
1322 #define CAPA(bit, name) case bit: printf(" " name); break
1324 /* if the capability 'cap' exists add 'val' to 'sum'
1325 * otherwise print 'Reserved' */
1326 #define ADD_BIT_VAL(bit, cap, sum, val) case (bit): do { \
1328 printf(" Reserved"); \
1335 switch (bit
+ base
) {
1336 CAPA(0, "HT Information Exchange Supported");
1337 CAPA(1, "reserved (On-demand Beacon)");
1338 CAPA(2, "Extended Channel Switching");
1339 CAPA(3, "reserved (Wave Indication)");
1340 CAPA(4, "PSMP Capability");
1341 CAPA(5, "reserved (Service Interval Granularity)");
1344 s_psmp_support
= true;
1345 printf(" S-PSMP Capability");
1349 CAPA(8, "Diagnostics");
1350 CAPA(9, "Multicast Diagnostics");
1351 CAPA(10, "Location Tracking");
1353 CAPA(12, "Proxy ARP Service");
1354 CAPA(13, "Collocated Interference Reporting");
1355 CAPA(14, "Civic Location");
1356 CAPA(15, "Geospatial Location");
1358 CAPA(17, "WNM-Sleep Mode");
1359 CAPA(18, "TIM Broadcast");
1360 CAPA(19, "BSS Transition");
1361 CAPA(20, "QoS Traffic Capability");
1362 CAPA(21, "AC Station Count");
1363 CAPA(22, "Multiple BSSID");
1364 CAPA(23, "Timing Measurement");
1365 CAPA(24, "Channel Usage");
1366 CAPA(25, "SSID List");
1368 CAPA(27, "UTC TSF Offset");
1369 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1370 CAPA(29, "TDLS Peer PSM Support");
1371 CAPA(30, "TDLS channel switching");
1372 CAPA(31, "Interworking");
1373 CAPA(32, "QoS Map");
1375 CAPA(34, "SSPN Interface");
1376 CAPA(35, "Reserved");
1377 CAPA(36, "MSGCF Capability");
1378 CAPA(37, "TDLS Support");
1379 CAPA(38, "TDLS Prohibited");
1380 CAPA(39, "TDLS Channel Switching Prohibited");
1381 CAPA(40, "Reject Unadmitted Frame");
1383 ADD_BIT_VAL(41, s_psmp_support
, si_duration
, 1);
1384 ADD_BIT_VAL(42, s_psmp_support
, si_duration
, 2);
1385 ADD_BIT_VAL(43, s_psmp_support
, si_duration
, 4);
1387 CAPA(44, "Identifier Location");
1388 CAPA(45, "U-APSD Coexistence");
1389 CAPA(46, "WNM-Notification");
1390 CAPA(47, "Reserved");
1391 CAPA(48, "UTF-8 SSID");
1392 CAPA(49, "QMFActivated");
1393 CAPA(50, "QMFReconfigurationActivated");
1394 CAPA(51, "Robust AV Streaming");
1395 CAPA(52, "Advanced GCR");
1396 CAPA(53, "Mesh GCR");
1398 CAPA(55, "QLoad Report");
1399 CAPA(56, "Alternate EDCA");
1400 CAPA(57, "Unprotected TXOP Negotiation");
1401 CAPA(58, "Protected TXOP egotiation");
1402 CAPA(59, "Reserved");
1403 CAPA(60, "Protected QLoad Report");
1404 CAPA(61, "TDLS Wider Bandwidth");
1405 CAPA(62, "Operating Mode Notification");
1407 ADD_BIT_VAL(63, is_vht_cap
, max_amsdu
, 1);
1408 ADD_BIT_VAL(64, is_vht_cap
, max_amsdu
, 2);
1410 CAPA(65, "Channel Schedule Management");
1411 CAPA(66, "Geodatabase Inband Enabling Signal");
1412 CAPA(67, "Network Channel Control");
1413 CAPA(68, "White Space Map");
1414 CAPA(69, "Channel Availability Query");
1415 CAPA(70, "FTM Responder");
1416 CAPA(71, "FTM Initiator");
1417 CAPA(72, "Reserved");
1418 CAPA(73, "Extended Spectrum Management Capable");
1419 CAPA(74, "Reserved");
1430 printf("\n\t\t * Service Interval Granularity is %d ms",
1431 (si_duration
+ 1) * 5);
1434 printf("\n\t\t * Max Number Of MSDUs In A-MSDU is ");
1435 switch (max_amsdu
) {
1437 printf("unlimited");
1456 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1457 const struct print_ies_data
*ie_buffer
)
1459 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1461 data
[0], data
[1], data
[2], data
[3]);
1463 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
1467 static void print_ibssatim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1468 const struct print_ies_data
*ie_buffer
)
1470 printf(" %d TUs\n", (data
[1] << 8) + data
[0]);
1473 static void print_vht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1474 const struct print_ies_data
*ie_buffer
)
1477 print_vht_info((__u32
) data
[0] | ((__u32
)data
[1] << 8) |
1478 ((__u32
)data
[2] << 16) | ((__u32
)data
[3] << 24),
1482 static void print_vht_oper(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1483 const struct print_ies_data
*ie_buffer
)
1485 const char *chandwidths
[] = {
1486 [0] = "20 or 40 MHz",
1493 printf("\t\t * channel width: %d (%s)\n", data
[0],
1494 data
[0] < ARRAY_SIZE(chandwidths
) ? chandwidths
[data
[0]] : "unknown");
1495 printf("\t\t * center freq segment 1: %d\n", data
[1]);
1496 printf("\t\t * center freq segment 2: %d\n", data
[2]);
1497 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data
[4], data
[3]);
1500 static void print_supp_op_classes(const uint8_t type
, uint8_t len
,
1501 const uint8_t *data
,
1502 const struct print_ies_data
*ie_buffer
)
1504 uint8_t *p
= (uint8_t*) data
;
1505 const uint8_t *next_data
= p
+ len
;
1506 int zero_delimiter
= 0;
1507 int one_hundred_thirty_delimiter
= 0;
1510 printf("\t\t * current operating class: %d\n", *p
);
1511 while (++p
< next_data
) {
1513 one_hundred_thirty_delimiter
= 1;
1520 printf("\t\t * operating class: %d\n", *p
);
1522 if (one_hundred_thirty_delimiter
)
1523 while (++p
< next_data
) {
1524 printf("\t\t * current operating class extension: %d\n", *p
);
1527 while (++p
< next_data
- 1) {
1528 printf("\t\t * operating class tuple: %d %d\n", p
[0], p
[1]);
1534 static void print_measurement_pilot_tx(const uint8_t type
, uint8_t len
,
1535 const uint8_t *data
,
1536 const struct print_ies_data
*ie_buffer
)
1538 uint8_t *p
, len_remaining
;
1541 printf("\t\t * interval: %d TUs\n", data
[0]);
1546 p
= (uint8_t *) data
+ 1;
1547 len_remaining
= len
- 1;
1549 while (len_remaining
>=5) {
1550 uint8_t subelement_id
= *p
, len
, *end
;
1559 /* 802.11-2016 only allows vendor specific elements */
1560 if (subelement_id
!= 221) {
1561 printf("\t\t * <Invalid subelement ID %d>\n", subelement_id
);
1565 if (len
< 3 || len
> len_remaining
) {
1566 printf(" <Parse error, element too short>\n");
1570 printf("\t\t * vendor specific: OUI %.2x:%.2x:%.2x, data:",
1572 /* add only two here and use ++p in while loop */
1576 printf(" %.2x", *p
);
1579 len_remaining
-= len
;
1583 static void print_obss_scan_params(const uint8_t type
, uint8_t len
,
1584 const uint8_t *data
,
1585 const struct print_ies_data
*ie_buffer
)
1588 printf("\t\t * passive dwell: %d TUs\n", (data
[1] << 8) | data
[0]);
1589 printf("\t\t * active dwell: %d TUs\n", (data
[3] << 8) | data
[2]);
1590 printf("\t\t * channel width trigger scan interval: %d s\n", (data
[5] << 8) | data
[4]);
1591 printf("\t\t * scan passive total per channel: %d TUs\n", (data
[7] << 8) | data
[6]);
1592 printf("\t\t * scan active total per channel: %d TUs\n", (data
[9] << 8) | data
[8]);
1593 printf("\t\t * BSS width channel transition delay factor: %d\n", (data
[11] << 8) | data
[10]);
1594 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1595 ((data
[13] << 8) | data
[12]) / 100, ((data
[13] << 8) | data
[12]) % 100);
1598 static void print_secchan_offs(const uint8_t type
, uint8_t len
,
1599 const uint8_t *data
,
1600 const struct print_ies_data
*ie_buffer
)
1602 if (data
[0] < ARRAY_SIZE(ht_secondary_offset
))
1603 printf(" %s (%d)\n", ht_secondary_offset
[data
[0]], data
[0]);
1605 printf(" %d\n", data
[0]);
1608 static void print_bss_load(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1609 const struct print_ies_data
*ie_buffer
)
1612 printf("\t\t * station count: %d\n", (data
[1] << 8) | data
[0]);
1613 printf("\t\t * channel utilisation: %d/255\n", data
[2]);
1614 printf("\t\t * available admission capacity: %d [*32us]\n", (data
[4] << 8) | data
[3]);
1617 static void print_mesh_conf(const uint8_t type
, uint8_t len
,
1618 const uint8_t *data
,
1619 const struct print_ies_data
*ie_buffer
)
1622 printf("\t\t * Active Path Selection Protocol ID: %d\n", data
[0]);
1623 printf("\t\t * Active Path Selection Metric ID: %d\n", data
[1]);
1624 printf("\t\t * Congestion Control Mode ID: %d\n", data
[2]);
1625 printf("\t\t * Synchronization Method ID: %d\n", data
[3]);
1626 printf("\t\t * Authentication Protocol ID: %d\n", data
[4]);
1627 printf("\t\t * Mesh Formation Info:\n");
1628 printf("\t\t\t Number of Peerings: %d\n", (data
[5] & 0x7E) >> 1);
1630 printf("\t\t\t Connected to Mesh Gate\n");
1632 printf("\t\t\t Connected to AS\n");
1633 printf("\t\t * Mesh Capability\n");
1635 printf("\t\t\t Accepting Additional Mesh Peerings\n");
1637 printf("\t\t\t MCCA Supported\n");
1639 printf("\t\t\t MCCA Enabled\n");
1641 printf("\t\t\t Forwarding\n");
1643 printf("\t\t\t MBCA Supported\n");
1645 printf("\t\t\t TBTT Adjusting\n");
1647 printf("\t\t\t Mesh Power Save Level\n");
1652 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1653 const struct print_ies_data
*ie_buffer
);
1654 uint8_t minlen
, maxlen
;
1658 static void print_ie(const struct ie_print
*p
, const uint8_t type
, uint8_t len
,
1659 const uint8_t *data
,
1660 const struct print_ies_data
*ie_buffer
)
1667 printf("\t%s:", p
->name
);
1668 if (len
< p
->minlen
|| len
> p
->maxlen
) {
1670 printf(" <invalid: %d bytes:", len
);
1671 for (i
= 0; i
< len
; i
++)
1672 printf(" %.02x", data
[i
]);
1675 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
1677 printf(" <invalid: no data>\n");
1681 p
->print(type
, len
, data
, ie_buffer
);
1684 #define PRINT_IGN { \
1691 static const struct ie_print ieprinters
[] = {
1692 [0] = { "SSID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1693 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1694 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
1695 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
1696 [6] = { "IBSS ATIM window", print_ibssatim
, 2, 2, BIT(PRINT_SCAN
), },
1697 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
1698 [11] = { "BSS Load", print_bss_load
, 5, 5, BIT(PRINT_SCAN
), },
1699 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
1700 [35] = { "TPC report", print_tpcreport
, 2, 2, BIT(PRINT_SCAN
), },
1701 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1702 [45] = { "HT capabilities", print_ht_capa
, 26, 26, BIT(PRINT_SCAN
), },
1703 [47] = { "ERP D4.0", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1704 [59] = { "Supported operating classes", print_supp_op_classes
, 1, 255, BIT(PRINT_SCAN
), },
1705 [66] = { "Measurement Pilot Transmission", print_measurement_pilot_tx
, 1, 255, BIT(PRINT_SCAN
), },
1706 [74] = { "Overlapping BSS scan params", print_obss_scan_params
, 14, 255, BIT(PRINT_SCAN
), },
1707 [61] = { "HT operation", print_ht_op
, 22, 22, BIT(PRINT_SCAN
), },
1708 [62] = { "Secondary Channel Offset", print_secchan_offs
, 1, 1, BIT(PRINT_SCAN
), },
1709 [191] = { "VHT capabilities", print_vht_capa
, 12, 255, BIT(PRINT_SCAN
), },
1710 [192] = { "VHT operation", print_vht_oper
, 5, 255, BIT(PRINT_SCAN
), },
1711 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
1712 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1713 [70] = { "RM enabled capabilities", print_rm_enabled_capabilities
, 5, 5, BIT(PRINT_SCAN
), },
1714 [113] = { "MESH Configuration", print_mesh_conf
, 7, 7, BIT(PRINT_SCAN
), },
1715 [114] = { "MESH ID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1716 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
1717 [107] = { "802.11u Interworking", print_interworking
, 0, 255, BIT(PRINT_SCAN
), },
1718 [108] = { "802.11u Advertisement", print_11u_advert
, 0, 255, BIT(PRINT_SCAN
), },
1719 [111] = { "802.11u Roaming Consortium", print_11u_rcon
, 2, 255, BIT(PRINT_SCAN
), },
1720 [195] = { "Transmit Power Envelope", print_tx_power_envelope
, 2, 5, BIT(PRINT_SCAN
), },
1723 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1724 const struct print_ies_data
*ie_buffer
)
1726 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
1729 static void print_wifi_osen(const uint8_t type
, uint8_t len
,
1730 const uint8_t *data
,
1731 const struct print_ies_data
*ie_buffer
)
1733 print_osen_ie("OSEN", "OSEN", len
, data
);
1736 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
1739 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
1745 printf("Parameter: not version 1: ");
1749 printf("\t * Parameter version 1");
1754 printf("\n\t\t * u-APSD");
1758 for (i
= 0; i
< 4; i
++) {
1759 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
1762 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
1763 (1 << (data
[1] >> 4)) - 1);
1764 printf(", AIFSN %d", data
[0] & 0xf);
1765 if (data
[2] | data
[3])
1766 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
1774 printf("invalid: ");
1778 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1779 const struct print_ies_data
*ie_buffer
)
1785 printf(" information:");
1788 if (print_wifi_wmm_param(data
+ 1, len
- 1))
1792 printf(" type %d:", data
[0]);
1796 for(i
= 1; i
< len
; i
++)
1797 printf(" %.02x", data
[i
]);
1801 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
1805 return "Default (PIN)";
1807 return "User-specified";
1809 return "Machine-specified";
1813 return "PushButton";
1815 return "Registrar-specified";
1821 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1822 const struct print_ies_data
*ie_buffer
)
1825 __u16 subtype
, sublen
;
1828 subtype
= (data
[0] << 8) + data
[1];
1829 sublen
= (data
[2] << 8) + data
[3];
1830 if (sublen
> len
- 4)
1835 tab_on_first(&first
);
1837 printf("\t * Version: (invalid "
1838 "length %d)\n", sublen
);
1841 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
1844 tab_on_first(&first
);
1846 printf("\t * Device Name: (invalid length %d)\n",
1850 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
1854 tab_on_first(&first
);
1856 printf("\t * Device Password ID: (invalid length %d)\n",
1860 id
= data
[4] << 8 | data
[5];
1861 printf("\t * Device Password ID: %u (%s)\n",
1862 id
, wifi_wps_dev_passwd_id(id
));
1866 tab_on_first(&first
);
1868 printf("\t * Manufacturer: (invalid length %d)\n",
1872 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
1875 tab_on_first(&first
);
1877 printf("\t * Model: (invalid length %d)\n",
1881 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
1884 tab_on_first(&first
);
1886 printf("\t * Model Number: (invalid length %d)\n",
1890 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
1896 printf("\t * Response Type: (invalid length %d)\n",
1901 tab_on_first(&first
);
1902 printf("\t * Response Type: %d%s\n",
1903 val
, val
== 3 ? " (AP)" : "");
1910 printf("\t * RF Bands: (invalid length %d)\n",
1915 tab_on_first(&first
);
1916 printf("\t * RF Bands: 0x%x\n", val
);
1923 printf("\t * Selected Registrar: (invalid length %d)\n",
1928 tab_on_first(&first
);
1929 printf("\t * Selected Registrar: 0x%x\n", val
);
1933 tab_on_first(&first
);
1935 printf("\t * Serial Number: (invalid length %d)\n",
1939 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
1945 printf("\t * Wi-Fi Protected Setup State: (invalid length %d)\n",
1950 tab_on_first(&first
);
1951 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1953 val
== 1 ? " (Unconfigured)" : "",
1954 val
== 2 ? " (Configured)" : "");
1958 tab_on_first(&first
);
1959 printf("\t * UUID: ");
1961 printf("(invalid, length=%d)\n", sublen
);
1964 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1965 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1966 data
[4], data
[5], data
[6], data
[7],
1967 data
[8], data
[9], data
[10], data
[11],
1968 data
[12], data
[13], data
[14], data
[15],
1969 data
[16], data
[17], data
[18], data
[19]);
1972 tab_on_first(&first
);
1974 printf("\t * Primary Device Type: (invalid length %d)\n",
1978 printf("\t * Primary Device Type: "
1979 "%u-%02x%02x%02x%02x-%u\n",
1980 data
[4] << 8 | data
[5],
1981 data
[6], data
[7], data
[8], data
[9],
1982 data
[10] << 8 | data
[11]);
1987 tab_on_first(&first
);
1989 printf("\t * AP setup locked: (invalid length %d)\n",
1993 printf("\t * AP setup locked: 0x%.2x\n", val
);
2002 printf("\t * Config methods: (invalid length %d)\n",
2006 meth
= (data
[4] << 8) + data
[5];
2008 tab_on_first(&first
);
2009 printf("\t * %sConfig methods:",
2010 subtype
== 0x1053 ? "Selected Registrar ": "");
2011 #define T(bit, name) do { \
2012 if (meth & (1<<bit)) { \
2032 const __u8
*subdata
= data
+ 4;
2033 __u16 tmplen
= sublen
;
2035 tab_on_first(&first
);
2036 printf("\t * Unknown TLV (%#.4x, %d bytes):",
2039 printf(" %.2x", *subdata
);
2053 printf("\t\t * bogus tail data (%d):", len
);
2055 printf(" %.2x", *data
);
2063 static const struct ie_print wifiprinters
[] = {
2064 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
2065 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
2066 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
2069 static inline void print_p2p(const uint8_t type
, uint8_t len
,
2070 const uint8_t *data
,
2071 const struct print_ies_data
*ie_buffer
)
2079 sublen
= (data
[2] << 8) + data
[1];
2081 if (sublen
> len
- 3)
2085 case 0x02: /* capability */
2086 tab_on_first(&first
);
2088 printf("\t * malformed capability\n");
2091 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
2094 case 0x0d: /* device info */
2095 if (sublen
< 6 + 2 + 8 + 1) {
2096 printf("\t * malformed device info\n");
2100 case 0x00: /* status */
2101 case 0x01: /* minor reason */
2102 case 0x03: /* device ID */
2103 case 0x04: /* GO intent */
2104 case 0x05: /* configuration timeout */
2105 case 0x06: /* listen channel */
2106 case 0x07: /* group BSSID */
2107 case 0x08: /* ext listen timing */
2108 case 0x09: /* intended interface address */
2109 case 0x0a: /* manageability */
2110 case 0x0b: /* channel list */
2111 case 0x0c: /* NoA */
2112 case 0x0e: /* group info */
2113 case 0x0f: /* group ID */
2114 case 0x10: /* interface */
2115 case 0x11: /* operating channel */
2116 case 0x12: /* invitation flags */
2117 case 0xdd: /* vendor specific */
2119 const __u8
*subdata
= data
+ 3;
2120 __u16 tmplen
= sublen
;
2122 tab_on_first(&first
);
2123 printf("\t * Unknown TLV (%#.2x, %d bytes):",
2126 printf(" %.2x", *subdata
);
2140 tab_on_first(&first
);
2141 printf("\t * bogus tail data (%d):", len
);
2143 printf(" %.2x", *data
);
2151 static inline void print_hs20_ind(const uint8_t type
, uint8_t len
,
2152 const uint8_t *data
,
2153 const struct print_ies_data
*ie_buffer
)
2155 /* I can't find the spec for this...just going off what wireshark uses. */
2158 printf("\t\tDGAF: %i\n", (int)(data
[0] & 0x1));
2160 printf("\t\tUnexpected length: %i\n", len
);
2163 static void print_wifi_owe_tarns(const uint8_t type
, uint8_t len
,
2164 const uint8_t *data
,
2165 const struct print_ies_data
*ie_buffer
)
2174 mac_addr_n2a(mac_addr
, data
);
2175 printf("\t\tBSSID: %s\n", mac_addr
);
2178 if (ssid_len
> len
- 7)
2180 printf("\t\tSSID: ");
2181 print_ssid_escaped(ssid_len
, data
+ 7);
2184 /* optional elements */
2185 if (len
>= ssid_len
+ 9) {
2186 printf("\t\tBand Info: %u\n", data
[ssid_len
+ 7]);
2187 printf("\t\tChannel Info: %u\n", data
[ssid_len
+ 8]);
2191 static const struct ie_print wfa_printers
[] = {
2192 [9] = { "P2P", print_p2p
, 2, 255, BIT(PRINT_SCAN
), },
2193 [16] = { "HotSpot 2.0 Indication", print_hs20_ind
, 1, 255, BIT(PRINT_SCAN
), },
2194 [18] = { "HotSpot 2.0 OSEN", print_wifi_osen
, 1, 255, BIT(PRINT_SCAN
), },
2195 [28] = { "OWE Transition Mode", print_wifi_owe_tarns
, 7, 255, BIT(PRINT_SCAN
), },
2198 static void print_vendor(unsigned char len
, unsigned char *data
,
2199 bool unknown
, enum print_ie_type ptype
)
2204 printf("\tVendor specific: <too short> data:");
2205 for(i
= 0; i
< len
; i
++)
2206 printf(" %.02x", data
[i
]);
2211 if (len
>= 4 && memcmp(data
, ms_oui
, 3) == 0) {
2212 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
2213 wifiprinters
[data
[3]].name
&&
2214 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
2215 print_ie(&wifiprinters
[data
[3]],
2216 data
[3], len
- 4, data
+ 4,
2222 printf("\tMS/WiFi %#.2x, data:", data
[3]);
2223 for(i
= 0; i
< len
- 4; i
++)
2224 printf(" %.02x", data
[i
+ 4]);
2229 if (len
>= 4 && memcmp(data
, wfa_oui
, 3) == 0) {
2230 if (data
[3] < ARRAY_SIZE(wfa_printers
) &&
2231 wfa_printers
[data
[3]].name
&&
2232 wfa_printers
[data
[3]].flags
& BIT(ptype
)) {
2233 print_ie(&wfa_printers
[data
[3]],
2234 data
[3], len
- 4, data
+ 4,
2240 printf("\tWFA %#.2x, data:", data
[3]);
2241 for(i
= 0; i
< len
- 4; i
++)
2242 printf(" %.02x", data
[i
+ 4]);
2250 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
2251 data
[0], data
[1], data
[2]);
2252 for (i
= 3; i
< len
; i
++)
2253 printf(" %.2x", data
[i
]);
2257 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
2258 enum print_ie_type ptype
)
2260 struct print_ies_data ie_buffer
= {
2264 if (ie
== NULL
|| ielen
< 0)
2267 while (ielen
>= 2 && ielen
- 2 >= ie
[1]) {
2268 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
2269 ieprinters
[ie
[0]].name
&&
2270 ieprinters
[ie
[0]].flags
& BIT(ptype
)) {
2271 print_ie(&ieprinters
[ie
[0]],
2272 ie
[0], ie
[1], ie
+ 2, &ie_buffer
);
2273 } else if (ie
[0] == 221 /* vendor */) {
2274 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
2275 } else if (unknown
) {
2278 printf("\tUnknown IE (%d):", ie
[0]);
2279 for (i
=0; i
<ie
[1]; i
++)
2280 printf(" %.2x", ie
[2+i
]);
2288 static void print_capa_dmg(__u16 capa
)
2290 switch (capa
& WLAN_CAPABILITY_DMG_TYPE_MASK
) {
2291 case WLAN_CAPABILITY_DMG_TYPE_AP
:
2294 case WLAN_CAPABILITY_DMG_TYPE_PBSS
:
2297 case WLAN_CAPABILITY_DMG_TYPE_IBSS
:
2298 printf(" DMG_IBSS");
2302 if (capa
& WLAN_CAPABILITY_DMG_CBAP_ONLY
)
2303 printf(" CBAP_Only");
2304 if (capa
& WLAN_CAPABILITY_DMG_CBAP_SOURCE
)
2305 printf(" CBAP_Src");
2306 if (capa
& WLAN_CAPABILITY_DMG_PRIVACY
)
2308 if (capa
& WLAN_CAPABILITY_DMG_ECPAC
)
2310 if (capa
& WLAN_CAPABILITY_DMG_SPECTRUM_MGMT
)
2311 printf(" SpectrumMgmt");
2312 if (capa
& WLAN_CAPABILITY_DMG_RADIO_MEASURE
)
2313 printf(" RadioMeasure");
2316 static void print_capa_non_dmg(__u16 capa
)
2318 if (capa
& WLAN_CAPABILITY_ESS
)
2320 if (capa
& WLAN_CAPABILITY_IBSS
)
2322 if (capa
& WLAN_CAPABILITY_CF_POLLABLE
)
2323 printf(" CfPollable");
2324 if (capa
& WLAN_CAPABILITY_CF_POLL_REQUEST
)
2325 printf(" CfPollReq");
2326 if (capa
& WLAN_CAPABILITY_PRIVACY
)
2328 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
2329 printf(" ShortPreamble");
2330 if (capa
& WLAN_CAPABILITY_PBCC
)
2332 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
2333 printf(" ChannelAgility");
2334 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
2335 printf(" SpectrumMgmt");
2336 if (capa
& WLAN_CAPABILITY_QOS
)
2338 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
2339 printf(" ShortSlotTime");
2340 if (capa
& WLAN_CAPABILITY_APSD
)
2342 if (capa
& WLAN_CAPABILITY_RADIO_MEASURE
)
2343 printf(" RadioMeasure");
2344 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
2345 printf(" DSSS-OFDM");
2346 if (capa
& WLAN_CAPABILITY_DEL_BACK
)
2347 printf(" DelayedBACK");
2348 if (capa
& WLAN_CAPABILITY_IMM_BACK
)
2349 printf(" ImmediateBACK");
2352 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
2354 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
2355 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
2356 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
2357 char mac_addr
[20], dev
[20];
2358 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
2359 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
2360 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
2361 [NL80211_BSS_BSSID
] = { },
2362 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
2363 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
2364 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
2365 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
2366 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
2367 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
2368 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
2369 [NL80211_BSS_BEACON_IES
] = { },
2371 struct scan_params
*params
= arg
;
2372 int show
= params
->show_both_ie_sets
? 2 : 1;
2373 bool is_dmg
= false;
2375 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
2376 genlmsg_attrlen(gnlh
, 0), NULL
);
2378 if (!tb
[NL80211_ATTR_BSS
]) {
2379 fprintf(stderr
, "bss info missing!\n");
2382 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
2383 tb
[NL80211_ATTR_BSS
],
2385 fprintf(stderr
, "failed to parse nested attributes!\n");
2389 if (!bss
[NL80211_BSS_BSSID
])
2392 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
2393 printf("BSS %s", mac_addr
);
2394 if (tb
[NL80211_ATTR_IFINDEX
]) {
2395 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
2396 printf("(on %s)", dev
);
2399 if (bss
[NL80211_BSS_STATUS
]) {
2400 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
2401 case NL80211_BSS_STATUS_AUTHENTICATED
:
2402 printf(" -- authenticated");
2404 case NL80211_BSS_STATUS_ASSOCIATED
:
2405 printf(" -- associated");
2407 case NL80211_BSS_STATUS_IBSS_JOINED
:
2408 printf(" -- joined");
2411 printf(" -- unknown status: %d",
2412 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
2418 if (bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]) {
2419 unsigned long long bt
;
2420 bt
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]);
2421 printf("\tlast seen: %llu.%.3llus [boottime]\n", bt
/1000000000, (bt
%1000000000)/1000000);
2424 if (bss
[NL80211_BSS_TSF
]) {
2425 unsigned long long tsf
;
2426 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
2427 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
2428 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
2429 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
2431 if (bss
[NL80211_BSS_FREQUENCY
]) {
2432 int freq
= nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]);
2433 printf("\tfreq: %d\n", freq
);
2437 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
2438 printf("\tbeacon interval: %d TUs\n",
2439 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
2440 if (bss
[NL80211_BSS_CAPABILITY
]) {
2441 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
2442 printf("\tcapability:");
2444 print_capa_dmg(capa
);
2446 print_capa_non_dmg(capa
);
2447 printf(" (0x%.4x)\n", capa
);
2449 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
2450 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
2451 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
2453 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
2454 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
2455 printf("\tsignal: %d/100\n", s
);
2457 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
2458 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
2459 printf("\tlast seen: %d ms ago\n", age
);
2462 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
2463 struct nlattr
*ies
= bss
[NL80211_BSS_INFORMATION_ELEMENTS
];
2464 struct nlattr
*bcnies
= bss
[NL80211_BSS_BEACON_IES
];
2466 if (bss
[NL80211_BSS_PRESP_DATA
] ||
2467 (bcnies
&& (nla_len(ies
) != nla_len(bcnies
) ||
2468 memcmp(nla_data(ies
), nla_data(bcnies
),
2470 printf("\tInformation elements from Probe Response "
2472 print_ies(nla_data(ies
), nla_len(ies
),
2473 params
->unknown
, params
->type
);
2475 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
2476 printf("\tInformation elements from Beacon frame:\n");
2477 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
2478 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
2479 params
->unknown
, params
->type
);
2485 static struct scan_params scan_params
;
2487 static int handle_scan_dump(struct nl80211_state
*state
,
2489 int argc
, char **argv
,
2495 memset(&scan_params
, 0, sizeof(scan_params
));
2497 if (argc
== 1 && !strcmp(argv
[0], "-u"))
2498 scan_params
.unknown
= true;
2499 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
2500 scan_params
.show_both_ie_sets
= true;
2502 scan_params
.type
= PRINT_SCAN
;
2504 register_handler(print_bss_handler
, &scan_params
);
2508 static int handle_scan_combined(struct nl80211_state
*state
,
2510 int argc
, char **argv
,
2514 static char *dump_argv
[] = {
2520 static const __u32 cmds
[] = {
2521 NL80211_CMD_NEW_SCAN_RESULTS
,
2522 NL80211_CMD_SCAN_ABORTED
,
2524 int trig_argc
, dump_argc
, err
;
2527 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
2529 dump_argv
[3] = "-u";
2530 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
2532 dump_argv
[3] = "-b";
2536 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
2537 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
2540 trig_argv
[0] = argv
[0];
2541 trig_argv
[1] = "scan";
2542 trig_argv
[2] = "trigger";
2544 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
2545 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
2546 err
= handle_cmd(state
, id
, trig_argc
, trig_argv
);
2552 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
2554 * This code has a bug, which requires creating a separate
2555 * nl80211 socket to fix:
2556 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
2557 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
2558 * before (!) we listen to it, because we only start listening
2559 * after we send our scan request.
2561 * Doing it the other way around has a race condition as well,
2562 * if you first open the events socket you may get a notification
2563 * for a previous scan.
2565 * The only proper way to fix this would be to listen to events
2566 * before sending the command, and for the kernel to send the
2567 * scan request along with the event, so that you can match up
2568 * whether the scan you requested was finished or aborted (this
2569 * may result in processing a scan that another application
2570 * requested, but that doesn't seem to be a problem).
2572 * Alas, the kernel doesn't do that (yet).
2575 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
2576 NL80211_CMD_SCAN_ABORTED
) {
2577 printf("scan aborted!\n");
2581 dump_argv
[0] = argv
[0];
2582 return handle_cmd(state
, id
, dump_argc
, dump_argv
);
2584 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,
2585 CIB_NETDEV
, handle_scan_combined
,
2586 "Scan on the given frequencies and probe for the given SSIDs\n"
2587 "(or wildcard if not given) unless passive scanning is requested.\n"
2588 "If -u is specified print unknown data in the scan results.\n"
2589 "Specified (vendor) IEs must be well-formed.");
2590 COMMAND(scan
, dump
, "[-u]",
2591 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
2592 "Dump the current scan results. If -u is specified, print unknown\n"
2593 "data in scan results.");
2594 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]",
2595 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
2596 "Trigger a scan on the given frequencies with probing for the given\n"
2597 "SSIDs (or wildcard if not given) unless passive scanning is requested.\n"
2598 "Duration(in TUs), if specified, will be used to set dwell times.\n");
2601 static int handle_scan_abort(struct nl80211_state
*state
,
2603 int argc
, char **argv
,
2608 COMMAND(scan
, abort
, "",
2609 NL80211_CMD_ABORT_SCAN
, 0, CIB_NETDEV
, handle_scan_abort
,
2610 "Abort ongoing scan");
2612 static int handle_start_sched_scan(struct nl80211_state
*state
,
2614 int argc
, char **argv
, enum id_input id
)
2616 return parse_sched_scan(msg
, &argc
, &argv
);
2619 static int handle_stop_sched_scan(struct nl80211_state
*state
,
2620 struct nl_msg
*msg
, int argc
, char **argv
,
2629 COMMAND(scan
, sched_start
,
2631 NL80211_CMD_START_SCHED_SCAN
, 0, CIB_NETDEV
, handle_start_sched_scan
,
2632 "Start a scheduled scan at the specified interval on the given frequencies\n"
2633 "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2634 "scanning is requested. If matches are specified, only matching results\n"
2635 "will be returned.");
2636 COMMAND(scan
, sched_stop
, "",
2637 NL80211_CMD_STOP_SCHED_SCAN
, 0, CIB_NETDEV
, handle_stop_sched_scan
,
2638 "Stop an ongoing scheduled scan.");