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");
1022 printf(" Extended-Key-ID");
1023 printf(" (0x%.4x)\n", capa
);
1029 int pmkid_count
= data
[0] | (data
[1] << 8);
1031 if (len
>= 2 + 16 * pmkid_count
) {
1032 tab_on_first(&first
);
1033 printf("\t * %d PMKIDs\n", pmkid_count
);
1034 /* not printing PMKID values */
1035 data
+= 2 + 16 * pmkid_count
;
1036 len
-= 2 + 16 * pmkid_count
;
1042 tab_on_first(&first
);
1043 printf("\t * Group mgmt cipher suite: ");
1052 printf("\t\t * bogus tail data (%d):", len
);
1054 printf(" %.2x", *data
);
1062 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
1063 uint8_t len
, const uint8_t *data
)
1065 _print_rsn_ie(defcipher
, defauth
, len
, data
, 0);
1068 static void print_osen_ie(const char *defcipher
, const char *defauth
,
1069 uint8_t len
, const uint8_t *data
)
1072 _print_rsn_ie(defcipher
, defauth
, len
, data
, 1);
1075 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1076 const struct print_ies_data
*ie_buffer
)
1078 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
1081 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1082 const struct print_ies_data
*ie_buffer
)
1085 print_ht_capability(data
[0] | (data
[1] << 8));
1086 print_ampdu_length(data
[2] & 3);
1087 print_ampdu_spacing((data
[2] >> 2) & 7);
1088 print_ht_mcs(data
+ 3);
1091 static const char* ntype_11u(uint8_t t
)
1094 case 0: return "Private";
1095 case 1: return "Private with Guest";
1096 case 2: return "Chargeable Public";
1097 case 3: return "Free Public";
1098 case 4: return "Personal Device";
1099 case 5: return "Emergency Services Only";
1100 case 14: return "Test or Experimental";
1101 case 15: return "Wildcard";
1102 default: return "Reserved";
1106 static const char* vgroup_11u(uint8_t t
)
1109 case 0: return "Unspecified";
1110 case 1: return "Assembly";
1111 case 2: return "Business";
1112 case 3: return "Educational";
1113 case 4: return "Factory and Industrial";
1114 case 5: return "Institutional";
1115 case 6: return "Mercantile";
1116 case 7: return "Residential";
1117 case 8: return "Storage";
1118 case 9: return "Utility and Miscellaneous";
1119 case 10: return "Vehicular";
1120 case 11: return "Outdoor";
1121 default: return "Reserved";
1125 static void print_interworking(const uint8_t type
, uint8_t len
,
1126 const uint8_t *data
,
1127 const struct print_ies_data
*ie_buffer
)
1129 /* See Section 7.3.2.92 in the 802.11u spec. */
1132 uint8_t ano
= data
[0];
1133 printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano
));
1134 printf("\t\t\tNetwork Type: %i (%s)\n",
1135 (int)(ano
& 0xf), ntype_11u(ano
& 0xf));
1137 printf("\t\t\tInternet\n");
1139 printf("\t\t\tASRA\n");
1141 printf("\t\t\tESR\n");
1143 printf("\t\t\tUESA\n");
1145 if ((len
== 3) || (len
== 9)) {
1146 printf("\t\tVenue Group: %i (%s)\n",
1147 (int)(data
[1]), vgroup_11u(data
[1]));
1148 printf("\t\tVenue Type: %i\n", (int)(data
[2]));
1151 printf("\t\tHESSID: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
1152 data
[3], data
[4], data
[5], data
[6], data
[7], data
[8]);
1154 printf("\t\tHESSID: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
1155 data
[1], data
[2], data
[3], data
[4], data
[5], data
[6]);
1158 static void print_11u_advert(const uint8_t type
, uint8_t len
,
1159 const uint8_t *data
,
1160 const struct print_ies_data
*ie_buffer
)
1162 /* See Section 7.3.2.93 in the 802.11u spec. */
1163 /* TODO: This code below does not decode private protocol IDs */
1166 while (idx
< (len
- 1)) {
1167 uint8_t qri
= data
[idx
];
1168 uint8_t proto_id
= data
[idx
+ 1];
1169 printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri
));
1170 printf("\t\t\tQuery Response Length Limit: %i\n",
1173 printf("\t\t\tPAME-BI\n");
1176 printf("\t\t\tANQP\n"); break;
1178 printf("\t\t\tMIH Information Service\n"); break;
1180 printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
1182 printf("\t\t\tEmergency Alert System (EAS)\n"); break;
1184 printf("\t\t\tVendor Specific\n"); break;
1186 printf("\t\t\tReserved: %i\n", proto_id
); break;
1192 static void print_11u_rcon(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1193 const struct print_ies_data
*ie_buffer
)
1195 /* See Section 7.3.2.96 in the 802.11u spec. */
1197 int ln0
= data
[1] & 0xf;
1198 int ln1
= ((data
[1] & 0xf0) >> 4);
1203 ln2
= len
- 2 - ln0
- ln1
;
1205 printf("\t\tANQP OIs: %i\n", data
[0]);
1208 printf("\t\tOI 1: ");
1209 if (2 + ln0
> len
) {
1210 printf("Invalid IE length.\n");
1212 for (idx
= 0; idx
< ln0
; idx
++) {
1213 printf("%02hhx", data
[2 + idx
]);
1220 printf("\t\tOI 2: ");
1221 if (2 + ln0
+ ln1
> len
) {
1222 printf("Invalid IE length.\n");
1224 for (idx
= 0; idx
< ln1
; idx
++) {
1225 printf("%02hhx", data
[2 + ln0
+ idx
]);
1232 printf("\t\tOI 3: ");
1233 if (2 + ln0
+ ln1
+ ln2
> len
) {
1234 printf("Invalid IE length.\n");
1236 for (idx
= 0; idx
< ln2
; idx
++) {
1237 printf("%02hhx", data
[2 + ln0
+ ln1
+ idx
]);
1244 static void print_tx_power_envelope(const uint8_t type
, uint8_t len
,
1245 const uint8_t *data
,
1246 const struct print_ies_data
*ie_buffer
)
1248 const uint8_t local_max_tx_power_count
= data
[0] & 7;
1249 const uint8_t local_max_tx_power_unit_interp
= (data
[0] >> 3) & 7;
1251 static const char *power_names
[] = {
1252 "Local Maximum Transmit Power For 20 MHz",
1253 "Local Maximum Transmit Power For 40 MHz",
1254 "Local Maximum Transmit Power For 80 MHz",
1255 "Local Maximum Transmit Power For 160/80+80 MHz",
1260 if (local_max_tx_power_count
+ 2 != len
)
1262 if (local_max_tx_power_unit_interp
!= 0)
1264 for (i
= 0; i
< local_max_tx_power_count
+ 1; ++i
) {
1265 int8_t power_val
= ((int8_t)data
[1 + i
]) >> 1;
1266 int8_t point5
= data
[1 + i
] & 1;
1268 printf("\t\t * %s: %i.5 dBm\n", power_names
[i
], power_val
);
1270 printf("\t\t * %s: %i dBm\n", power_names
[i
], power_val
);
1274 static const char *ht_secondary_offset
[4] = {
1281 static void print_ht_op(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1282 const struct print_ies_data
*ie_buffer
)
1284 static const char *protection
[4] = {
1290 static const char *sta_chan_width
[2] = {
1296 printf("\t\t * primary channel: %d\n", data
[0]);
1297 printf("\t\t * secondary channel offset: %s\n",
1298 ht_secondary_offset
[data
[1] & 0x3]);
1299 printf("\t\t * STA channel width: %s\n", sta_chan_width
[(data
[1] & 0x4)>>2]);
1300 printf("\t\t * RIFS: %d\n", (data
[1] & 0x8)>>3);
1301 printf("\t\t * HT protection: %s\n", protection
[data
[2] & 0x3]);
1302 printf("\t\t * non-GF present: %d\n", (data
[2] & 0x4) >> 2);
1303 printf("\t\t * OBSS non-GF present: %d\n", (data
[2] & 0x10) >> 4);
1304 printf("\t\t * dual beacon: %d\n", (data
[4] & 0x40) >> 6);
1305 printf("\t\t * dual CTS protection: %d\n", (data
[4] & 0x80) >> 7);
1306 printf("\t\t * STBC beacon: %d\n", data
[5] & 0x1);
1307 printf("\t\t * L-SIG TXOP Prot: %d\n", (data
[5] & 0x2) >> 1);
1308 printf("\t\t * PCO active: %d\n", (data
[5] & 0x4) >> 2);
1309 printf("\t\t * PCO phase: %d\n", (data
[5] & 0x8) >> 3);
1312 static void print_capabilities(const uint8_t type
, uint8_t len
,
1313 const uint8_t *data
,
1314 const struct print_ies_data
*ie_buffer
)
1316 int i
, base
, bit
, si_duration
= 0, max_amsdu
= 0;
1317 bool s_psmp_support
= false, is_vht_cap
= false;
1318 unsigned char *ie
= ie_buffer
->ie
;
1319 int ielen
= ie_buffer
->ielen
;
1321 while (ielen
>= 2 && ielen
>= ie
[1]) {
1330 for (i
= 0; i
< len
; i
++) {
1333 for (bit
= 0; bit
< 8; bit
++) {
1334 if (!(data
[i
] & (1 << bit
)))
1339 #define CAPA(bit, name) case bit: printf(" " name); break
1341 /* if the capability 'cap' exists add 'val' to 'sum'
1342 * otherwise print 'Reserved' */
1343 #define ADD_BIT_VAL(bit, cap, sum, val) case (bit): do { \
1345 printf(" Reserved"); \
1352 switch (bit
+ base
) {
1353 CAPA(0, "HT Information Exchange Supported");
1354 CAPA(1, "reserved (On-demand Beacon)");
1355 CAPA(2, "Extended Channel Switching");
1356 CAPA(3, "reserved (Wave Indication)");
1357 CAPA(4, "PSMP Capability");
1358 CAPA(5, "reserved (Service Interval Granularity)");
1361 s_psmp_support
= true;
1362 printf(" S-PSMP Capability");
1366 CAPA(8, "Diagnostics");
1367 CAPA(9, "Multicast Diagnostics");
1368 CAPA(10, "Location Tracking");
1370 CAPA(12, "Proxy ARP Service");
1371 CAPA(13, "Collocated Interference Reporting");
1372 CAPA(14, "Civic Location");
1373 CAPA(15, "Geospatial Location");
1375 CAPA(17, "WNM-Sleep Mode");
1376 CAPA(18, "TIM Broadcast");
1377 CAPA(19, "BSS Transition");
1378 CAPA(20, "QoS Traffic Capability");
1379 CAPA(21, "AC Station Count");
1380 CAPA(22, "Multiple BSSID");
1381 CAPA(23, "Timing Measurement");
1382 CAPA(24, "Channel Usage");
1383 CAPA(25, "SSID List");
1385 CAPA(27, "UTC TSF Offset");
1386 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1387 CAPA(29, "TDLS Peer PSM Support");
1388 CAPA(30, "TDLS channel switching");
1389 CAPA(31, "Interworking");
1390 CAPA(32, "QoS Map");
1392 CAPA(34, "SSPN Interface");
1393 CAPA(35, "Reserved");
1394 CAPA(36, "MSGCF Capability");
1395 CAPA(37, "TDLS Support");
1396 CAPA(38, "TDLS Prohibited");
1397 CAPA(39, "TDLS Channel Switching Prohibited");
1398 CAPA(40, "Reject Unadmitted Frame");
1400 ADD_BIT_VAL(41, s_psmp_support
, si_duration
, 1);
1401 ADD_BIT_VAL(42, s_psmp_support
, si_duration
, 2);
1402 ADD_BIT_VAL(43, s_psmp_support
, si_duration
, 4);
1404 CAPA(44, "Identifier Location");
1405 CAPA(45, "U-APSD Coexistence");
1406 CAPA(46, "WNM-Notification");
1407 CAPA(47, "Reserved");
1408 CAPA(48, "UTF-8 SSID");
1409 CAPA(49, "QMFActivated");
1410 CAPA(50, "QMFReconfigurationActivated");
1411 CAPA(51, "Robust AV Streaming");
1412 CAPA(52, "Advanced GCR");
1413 CAPA(53, "Mesh GCR");
1415 CAPA(55, "QLoad Report");
1416 CAPA(56, "Alternate EDCA");
1417 CAPA(57, "Unprotected TXOP Negotiation");
1418 CAPA(58, "Protected TXOP egotiation");
1419 CAPA(59, "Reserved");
1420 CAPA(60, "Protected QLoad Report");
1421 CAPA(61, "TDLS Wider Bandwidth");
1422 CAPA(62, "Operating Mode Notification");
1424 ADD_BIT_VAL(63, is_vht_cap
, max_amsdu
, 1);
1425 ADD_BIT_VAL(64, is_vht_cap
, max_amsdu
, 2);
1427 CAPA(65, "Channel Schedule Management");
1428 CAPA(66, "Geodatabase Inband Enabling Signal");
1429 CAPA(67, "Network Channel Control");
1430 CAPA(68, "White Space Map");
1431 CAPA(69, "Channel Availability Query");
1432 CAPA(70, "FTM Responder");
1433 CAPA(71, "FTM Initiator");
1434 CAPA(72, "Reserved");
1435 CAPA(73, "Extended Spectrum Management Capable");
1436 CAPA(74, "Reserved");
1447 printf("\n\t\t * Service Interval Granularity is %d ms",
1448 (si_duration
+ 1) * 5);
1451 printf("\n\t\t * Max Number Of MSDUs In A-MSDU is ");
1452 switch (max_amsdu
) {
1454 printf("unlimited");
1473 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1474 const struct print_ies_data
*ie_buffer
)
1476 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1478 data
[0], data
[1], data
[2], data
[3]);
1480 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
1484 static void print_ibssatim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1485 const struct print_ies_data
*ie_buffer
)
1487 printf(" %d TUs\n", (data
[1] << 8) + data
[0]);
1490 static void print_vht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1491 const struct print_ies_data
*ie_buffer
)
1494 print_vht_info((__u32
) data
[0] | ((__u32
)data
[1] << 8) |
1495 ((__u32
)data
[2] << 16) | ((__u32
)data
[3] << 24),
1499 static void print_vht_oper(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1500 const struct print_ies_data
*ie_buffer
)
1502 const char *chandwidths
[] = {
1503 [0] = "20 or 40 MHz",
1510 printf("\t\t * channel width: %d (%s)\n", data
[0],
1511 data
[0] < ARRAY_SIZE(chandwidths
) ? chandwidths
[data
[0]] : "unknown");
1512 printf("\t\t * center freq segment 1: %d\n", data
[1]);
1513 printf("\t\t * center freq segment 2: %d\n", data
[2]);
1514 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data
[4], data
[3]);
1517 static void print_supp_op_classes(const uint8_t type
, uint8_t len
,
1518 const uint8_t *data
,
1519 const struct print_ies_data
*ie_buffer
)
1521 uint8_t *p
= (uint8_t*) data
;
1522 const uint8_t *next_data
= p
+ len
;
1523 int zero_delimiter
= 0;
1524 int one_hundred_thirty_delimiter
= 0;
1527 printf("\t\t * current operating class: %d\n", *p
);
1528 while (++p
< next_data
) {
1530 one_hundred_thirty_delimiter
= 1;
1537 printf("\t\t * operating class: %d\n", *p
);
1539 if (one_hundred_thirty_delimiter
)
1540 while (++p
< next_data
) {
1541 printf("\t\t * current operating class extension: %d\n", *p
);
1544 while (++p
< next_data
- 1) {
1545 printf("\t\t * operating class tuple: %d %d\n", p
[0], p
[1]);
1551 static void print_measurement_pilot_tx(const uint8_t type
, uint8_t len
,
1552 const uint8_t *data
,
1553 const struct print_ies_data
*ie_buffer
)
1555 uint8_t *p
, len_remaining
;
1558 printf("\t\t * interval: %d TUs\n", data
[0]);
1563 p
= (uint8_t *) data
+ 1;
1564 len_remaining
= len
- 1;
1566 while (len_remaining
>=5) {
1567 uint8_t subelement_id
= *p
, len
, *end
;
1576 /* 802.11-2016 only allows vendor specific elements */
1577 if (subelement_id
!= 221) {
1578 printf("\t\t * <Invalid subelement ID %d>\n", subelement_id
);
1582 if (len
< 3 || len
> len_remaining
) {
1583 printf(" <Parse error, element too short>\n");
1587 printf("\t\t * vendor specific: OUI %.2x:%.2x:%.2x, data:",
1589 /* add only two here and use ++p in while loop */
1593 printf(" %.2x", *p
);
1596 len_remaining
-= len
;
1600 static void print_obss_scan_params(const uint8_t type
, uint8_t len
,
1601 const uint8_t *data
,
1602 const struct print_ies_data
*ie_buffer
)
1605 printf("\t\t * passive dwell: %d TUs\n", (data
[1] << 8) | data
[0]);
1606 printf("\t\t * active dwell: %d TUs\n", (data
[3] << 8) | data
[2]);
1607 printf("\t\t * channel width trigger scan interval: %d s\n", (data
[5] << 8) | data
[4]);
1608 printf("\t\t * scan passive total per channel: %d TUs\n", (data
[7] << 8) | data
[6]);
1609 printf("\t\t * scan active total per channel: %d TUs\n", (data
[9] << 8) | data
[8]);
1610 printf("\t\t * BSS width channel transition delay factor: %d\n", (data
[11] << 8) | data
[10]);
1611 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1612 ((data
[13] << 8) | data
[12]) / 100, ((data
[13] << 8) | data
[12]) % 100);
1615 static void print_secchan_offs(const uint8_t type
, uint8_t len
,
1616 const uint8_t *data
,
1617 const struct print_ies_data
*ie_buffer
)
1619 if (data
[0] < ARRAY_SIZE(ht_secondary_offset
))
1620 printf(" %s (%d)\n", ht_secondary_offset
[data
[0]], data
[0]);
1622 printf(" %d\n", data
[0]);
1625 static void print_bss_load(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1626 const struct print_ies_data
*ie_buffer
)
1629 printf("\t\t * station count: %d\n", (data
[1] << 8) | data
[0]);
1630 printf("\t\t * channel utilisation: %d/255\n", data
[2]);
1631 printf("\t\t * available admission capacity: %d [*32us]\n", (data
[4] << 8) | data
[3]);
1634 static void print_mesh_conf(const uint8_t type
, uint8_t len
,
1635 const uint8_t *data
,
1636 const struct print_ies_data
*ie_buffer
)
1639 printf("\t\t * Active Path Selection Protocol ID: %d\n", data
[0]);
1640 printf("\t\t * Active Path Selection Metric ID: %d\n", data
[1]);
1641 printf("\t\t * Congestion Control Mode ID: %d\n", data
[2]);
1642 printf("\t\t * Synchronization Method ID: %d\n", data
[3]);
1643 printf("\t\t * Authentication Protocol ID: %d\n", data
[4]);
1644 printf("\t\t * Mesh Formation Info:\n");
1645 printf("\t\t\t Number of Peerings: %d\n", (data
[5] & 0x7E) >> 1);
1647 printf("\t\t\t Connected to Mesh Gate\n");
1649 printf("\t\t\t Connected to AS\n");
1650 printf("\t\t * Mesh Capability\n");
1652 printf("\t\t\t Accepting Additional Mesh Peerings\n");
1654 printf("\t\t\t MCCA Supported\n");
1656 printf("\t\t\t MCCA Enabled\n");
1658 printf("\t\t\t Forwarding\n");
1660 printf("\t\t\t MBCA Supported\n");
1662 printf("\t\t\t TBTT Adjusting\n");
1664 printf("\t\t\t Mesh Power Save Level\n");
1669 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1670 const struct print_ies_data
*ie_buffer
);
1671 uint8_t minlen
, maxlen
;
1675 static void print_ie(const struct ie_print
*p
, const uint8_t type
, uint8_t len
,
1676 const uint8_t *data
,
1677 const struct print_ies_data
*ie_buffer
)
1684 printf("\t%s:", p
->name
);
1685 if (len
< p
->minlen
|| len
> p
->maxlen
) {
1687 printf(" <invalid: %d bytes:", len
);
1688 for (i
= 0; i
< len
; i
++)
1689 printf(" %.02x", data
[i
]);
1692 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
1694 printf(" <invalid: no data>\n");
1698 p
->print(type
, len
, data
, ie_buffer
);
1701 #define PRINT_IGN { \
1708 static const struct ie_print ieprinters
[] = {
1709 [0] = { "SSID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1710 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1711 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
1712 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
1713 [6] = { "IBSS ATIM window", print_ibssatim
, 2, 2, BIT(PRINT_SCAN
), },
1714 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
1715 [11] = { "BSS Load", print_bss_load
, 5, 5, BIT(PRINT_SCAN
), },
1716 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
1717 [35] = { "TPC report", print_tpcreport
, 2, 2, BIT(PRINT_SCAN
), },
1718 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1719 [45] = { "HT capabilities", print_ht_capa
, 26, 26, BIT(PRINT_SCAN
), },
1720 [47] = { "ERP D4.0", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1721 [51] = { "AP Channel Report", print_ap_channel_report
, 1, 255, BIT(PRINT_SCAN
), },
1722 [59] = { "Supported operating classes", print_supp_op_classes
, 1, 255, BIT(PRINT_SCAN
), },
1723 [66] = { "Measurement Pilot Transmission", print_measurement_pilot_tx
, 1, 255, BIT(PRINT_SCAN
), },
1724 [74] = { "Overlapping BSS scan params", print_obss_scan_params
, 14, 255, BIT(PRINT_SCAN
), },
1725 [61] = { "HT operation", print_ht_op
, 22, 22, BIT(PRINT_SCAN
), },
1726 [62] = { "Secondary Channel Offset", print_secchan_offs
, 1, 1, BIT(PRINT_SCAN
), },
1727 [191] = { "VHT capabilities", print_vht_capa
, 12, 255, BIT(PRINT_SCAN
), },
1728 [192] = { "VHT operation", print_vht_oper
, 5, 255, BIT(PRINT_SCAN
), },
1729 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
1730 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1731 [70] = { "RM enabled capabilities", print_rm_enabled_capabilities
, 5, 5, BIT(PRINT_SCAN
), },
1732 [113] = { "MESH Configuration", print_mesh_conf
, 7, 7, BIT(PRINT_SCAN
), },
1733 [114] = { "MESH ID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1734 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
1735 [107] = { "802.11u Interworking", print_interworking
, 0, 255, BIT(PRINT_SCAN
), },
1736 [108] = { "802.11u Advertisement", print_11u_advert
, 0, 255, BIT(PRINT_SCAN
), },
1737 [111] = { "802.11u Roaming Consortium", print_11u_rcon
, 2, 255, BIT(PRINT_SCAN
), },
1738 [195] = { "Transmit Power Envelope", print_tx_power_envelope
, 2, 5, BIT(PRINT_SCAN
), },
1741 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1742 const struct print_ies_data
*ie_buffer
)
1744 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
1747 static void print_wifi_osen(const uint8_t type
, uint8_t len
,
1748 const uint8_t *data
,
1749 const struct print_ies_data
*ie_buffer
)
1751 print_osen_ie("OSEN", "OSEN", len
, data
);
1754 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
1757 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
1763 printf("Parameter: not version 1: ");
1767 printf("\t * Parameter version 1");
1772 printf("\n\t\t * u-APSD");
1776 for (i
= 0; i
< 4; i
++) {
1777 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
1780 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
1781 (1 << (data
[1] >> 4)) - 1);
1782 printf(", AIFSN %d", data
[0] & 0xf);
1783 if (data
[2] | data
[3])
1784 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
1792 printf("invalid: ");
1796 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1797 const struct print_ies_data
*ie_buffer
)
1803 printf(" information:");
1806 if (print_wifi_wmm_param(data
+ 1, len
- 1))
1810 printf(" type %d:", data
[0]);
1814 for(i
= 1; i
< len
; i
++)
1815 printf(" %.02x", data
[i
]);
1819 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
1823 return "Default (PIN)";
1825 return "User-specified";
1827 return "Machine-specified";
1831 return "PushButton";
1833 return "Registrar-specified";
1839 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1840 const struct print_ies_data
*ie_buffer
)
1843 __u16 subtype
, sublen
;
1846 subtype
= (data
[0] << 8) + data
[1];
1847 sublen
= (data
[2] << 8) + data
[3];
1848 if (sublen
> len
- 4)
1853 tab_on_first(&first
);
1855 printf("\t * Version: (invalid "
1856 "length %d)\n", sublen
);
1859 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
1862 tab_on_first(&first
);
1863 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
1867 tab_on_first(&first
);
1869 printf("\t * Device Password ID: (invalid length %d)\n",
1873 id
= data
[4] << 8 | data
[5];
1874 printf("\t * Device Password ID: %u (%s)\n",
1875 id
, wifi_wps_dev_passwd_id(id
));
1879 tab_on_first(&first
);
1880 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
1883 tab_on_first(&first
);
1884 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
1887 tab_on_first(&first
);
1888 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
1894 printf("\t * Response Type: (invalid length %d)\n",
1899 tab_on_first(&first
);
1900 printf("\t * Response Type: %d%s\n",
1901 val
, val
== 3 ? " (AP)" : "");
1908 printf("\t * RF Bands: (invalid length %d)\n",
1913 tab_on_first(&first
);
1914 printf("\t * RF Bands: 0x%x\n", val
);
1921 printf("\t * Selected Registrar: (invalid length %d)\n",
1926 tab_on_first(&first
);
1927 printf("\t * Selected Registrar: 0x%x\n", val
);
1931 tab_on_first(&first
);
1932 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
1938 printf("\t * Wi-Fi Protected Setup State: (invalid length %d)\n",
1943 tab_on_first(&first
);
1944 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1946 val
== 1 ? " (Unconfigured)" : "",
1947 val
== 2 ? " (Configured)" : "");
1951 tab_on_first(&first
);
1952 printf("\t * UUID: ");
1954 printf("(invalid, length=%d)\n", sublen
);
1957 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1958 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1959 data
[4], data
[5], data
[6], data
[7],
1960 data
[8], data
[9], data
[10], data
[11],
1961 data
[12], data
[13], data
[14], data
[15],
1962 data
[16], data
[17], data
[18], data
[19]);
1965 tab_on_first(&first
);
1972 uint8_t v2
= data
[9];
1973 printf("\t * Version2: %d.%d\n", v2
>> 4, v2
& 0xf);
1975 printf("\t * Unknown vendor extension. len=%u\n",
1980 tab_on_first(&first
);
1982 printf("\t * Primary Device Type: (invalid length %d)\n",
1986 printf("\t * Primary Device Type: "
1987 "%u-%02x%02x%02x%02x-%u\n",
1988 data
[4] << 8 | data
[5],
1989 data
[6], data
[7], data
[8], data
[9],
1990 data
[10] << 8 | data
[11]);
1995 tab_on_first(&first
);
1997 printf("\t * AP setup locked: (invalid length %d)\n",
2002 printf("\t * AP setup locked: 0x%.2x\n", val
);
2011 printf("\t * Config methods: (invalid length %d)\n",
2015 meth
= (data
[4] << 8) + data
[5];
2017 tab_on_first(&first
);
2018 printf("\t * %sConfig methods:",
2019 subtype
== 0x1053 ? "Selected Registrar ": "");
2020 #define T(bit, name) do { \
2021 if (meth & (1<<bit)) { \
2041 const __u8
*subdata
= data
+ 4;
2042 __u16 tmplen
= sublen
;
2044 tab_on_first(&first
);
2045 printf("\t * Unknown TLV (%#.4x, %d bytes):",
2048 printf(" %.2x", *subdata
);
2062 printf("\t\t * bogus tail data (%d):", len
);
2064 printf(" %.2x", *data
);
2072 static const struct ie_print wifiprinters
[] = {
2073 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
2074 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
2075 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
2078 static inline void print_p2p(const uint8_t type
, uint8_t len
,
2079 const uint8_t *data
,
2080 const struct print_ies_data
*ie_buffer
)
2088 sublen
= (data
[2] << 8) + data
[1];
2090 if (sublen
> len
- 3)
2094 case 0x02: /* capability */
2095 tab_on_first(&first
);
2097 printf("\t * malformed capability\n");
2100 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
2103 case 0x0d: /* device info */
2104 if (sublen
< 6 + 2 + 8 + 1) {
2105 printf("\t * malformed device info\n");
2109 case 0x00: /* status */
2110 case 0x01: /* minor reason */
2111 case 0x03: /* device ID */
2112 case 0x04: /* GO intent */
2113 case 0x05: /* configuration timeout */
2114 case 0x06: /* listen channel */
2115 case 0x07: /* group BSSID */
2116 case 0x08: /* ext listen timing */
2117 case 0x09: /* intended interface address */
2118 case 0x0a: /* manageability */
2119 case 0x0b: /* channel list */
2120 case 0x0c: /* NoA */
2121 case 0x0e: /* group info */
2122 case 0x0f: /* group ID */
2123 case 0x10: /* interface */
2124 case 0x11: /* operating channel */
2125 case 0x12: /* invitation flags */
2126 case 0xdd: /* vendor specific */
2128 const __u8
*subdata
= data
+ 3;
2129 __u16 tmplen
= sublen
;
2131 tab_on_first(&first
);
2132 printf("\t * Unknown TLV (%#.2x, %d bytes):",
2135 printf(" %.2x", *subdata
);
2149 tab_on_first(&first
);
2150 printf("\t * bogus tail data (%d):", len
);
2152 printf(" %.2x", *data
);
2160 static inline void print_hs20_ind(const uint8_t type
, uint8_t len
,
2161 const uint8_t *data
,
2162 const struct print_ies_data
*ie_buffer
)
2164 /* I can't find the spec for this...just going off what wireshark uses. */
2167 printf("\t\tDGAF: %i\n", (int)(data
[0] & 0x1));
2169 printf("\t\tUnexpected length: %i\n", len
);
2172 static void print_wifi_owe_tarns(const uint8_t type
, uint8_t len
,
2173 const uint8_t *data
,
2174 const struct print_ies_data
*ie_buffer
)
2183 mac_addr_n2a(mac_addr
, data
);
2184 printf("\t\tBSSID: %s\n", mac_addr
);
2187 if (ssid_len
> len
- 7)
2189 printf("\t\tSSID: ");
2190 print_ssid_escaped(ssid_len
, data
+ 7);
2193 /* optional elements */
2194 if (len
>= ssid_len
+ 9) {
2195 printf("\t\tBand Info: %u\n", data
[ssid_len
+ 7]);
2196 printf("\t\tChannel Info: %u\n", data
[ssid_len
+ 8]);
2200 static const struct ie_print wfa_printers
[] = {
2201 [9] = { "P2P", print_p2p
, 2, 255, BIT(PRINT_SCAN
), },
2202 [16] = { "HotSpot 2.0 Indication", print_hs20_ind
, 1, 255, BIT(PRINT_SCAN
), },
2203 [18] = { "HotSpot 2.0 OSEN", print_wifi_osen
, 1, 255, BIT(PRINT_SCAN
), },
2204 [28] = { "OWE Transition Mode", print_wifi_owe_tarns
, 7, 255, BIT(PRINT_SCAN
), },
2207 static void print_vendor(unsigned char len
, unsigned char *data
,
2208 bool unknown
, enum print_ie_type ptype
)
2213 printf("\tVendor specific: <too short> data:");
2214 for(i
= 0; i
< len
; i
++)
2215 printf(" %.02x", data
[i
]);
2220 if (len
>= 4 && memcmp(data
, ms_oui
, 3) == 0) {
2221 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
2222 wifiprinters
[data
[3]].name
&&
2223 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
2224 print_ie(&wifiprinters
[data
[3]],
2225 data
[3], len
- 4, data
+ 4,
2231 printf("\tMS/WiFi %#.2x, data:", data
[3]);
2232 for(i
= 0; i
< len
- 4; i
++)
2233 printf(" %.02x", data
[i
+ 4]);
2238 if (len
>= 4 && memcmp(data
, wfa_oui
, 3) == 0) {
2239 if (data
[3] < ARRAY_SIZE(wfa_printers
) &&
2240 wfa_printers
[data
[3]].name
&&
2241 wfa_printers
[data
[3]].flags
& BIT(ptype
)) {
2242 print_ie(&wfa_printers
[data
[3]],
2243 data
[3], len
- 4, data
+ 4,
2249 printf("\tWFA %#.2x, data:", data
[3]);
2250 for(i
= 0; i
< len
- 4; i
++)
2251 printf(" %.02x", data
[i
+ 4]);
2259 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
2260 data
[0], data
[1], data
[2]);
2261 for (i
= 3; i
< len
; i
++)
2262 printf(" %.2x", data
[i
]);
2266 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
2267 enum print_ie_type ptype
)
2269 struct print_ies_data ie_buffer
= {
2273 if (ie
== NULL
|| ielen
< 0)
2276 while (ielen
>= 2 && ielen
- 2 >= ie
[1]) {
2277 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
2278 ieprinters
[ie
[0]].name
&&
2279 ieprinters
[ie
[0]].flags
& BIT(ptype
)) {
2280 print_ie(&ieprinters
[ie
[0]],
2281 ie
[0], ie
[1], ie
+ 2, &ie_buffer
);
2282 } else if (ie
[0] == 221 /* vendor */) {
2283 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
2284 } else if (unknown
) {
2287 printf("\tUnknown IE (%d):", ie
[0]);
2288 for (i
=0; i
<ie
[1]; i
++)
2289 printf(" %.2x", ie
[2+i
]);
2297 static void print_capa_dmg(__u16 capa
)
2299 switch (capa
& WLAN_CAPABILITY_DMG_TYPE_MASK
) {
2300 case WLAN_CAPABILITY_DMG_TYPE_AP
:
2303 case WLAN_CAPABILITY_DMG_TYPE_PBSS
:
2306 case WLAN_CAPABILITY_DMG_TYPE_IBSS
:
2307 printf(" DMG_IBSS");
2311 if (capa
& WLAN_CAPABILITY_DMG_CBAP_ONLY
)
2312 printf(" CBAP_Only");
2313 if (capa
& WLAN_CAPABILITY_DMG_CBAP_SOURCE
)
2314 printf(" CBAP_Src");
2315 if (capa
& WLAN_CAPABILITY_DMG_PRIVACY
)
2317 if (capa
& WLAN_CAPABILITY_DMG_ECPAC
)
2319 if (capa
& WLAN_CAPABILITY_DMG_SPECTRUM_MGMT
)
2320 printf(" SpectrumMgmt");
2321 if (capa
& WLAN_CAPABILITY_DMG_RADIO_MEASURE
)
2322 printf(" RadioMeasure");
2325 static void print_capa_non_dmg(__u16 capa
)
2327 if (capa
& WLAN_CAPABILITY_ESS
)
2329 if (capa
& WLAN_CAPABILITY_IBSS
)
2331 if (capa
& WLAN_CAPABILITY_CF_POLLABLE
)
2332 printf(" CfPollable");
2333 if (capa
& WLAN_CAPABILITY_CF_POLL_REQUEST
)
2334 printf(" CfPollReq");
2335 if (capa
& WLAN_CAPABILITY_PRIVACY
)
2337 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
2338 printf(" ShortPreamble");
2339 if (capa
& WLAN_CAPABILITY_PBCC
)
2341 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
2342 printf(" ChannelAgility");
2343 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
2344 printf(" SpectrumMgmt");
2345 if (capa
& WLAN_CAPABILITY_QOS
)
2347 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
2348 printf(" ShortSlotTime");
2349 if (capa
& WLAN_CAPABILITY_APSD
)
2351 if (capa
& WLAN_CAPABILITY_RADIO_MEASURE
)
2352 printf(" RadioMeasure");
2353 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
2354 printf(" DSSS-OFDM");
2355 if (capa
& WLAN_CAPABILITY_DEL_BACK
)
2356 printf(" DelayedBACK");
2357 if (capa
& WLAN_CAPABILITY_IMM_BACK
)
2358 printf(" ImmediateBACK");
2361 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
2363 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
2364 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
2365 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
2366 char mac_addr
[20], dev
[20];
2367 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
2368 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
2369 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
2370 [NL80211_BSS_BSSID
] = { },
2371 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
2372 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
2373 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
2374 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
2375 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
2376 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
2377 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
2378 [NL80211_BSS_BEACON_IES
] = { },
2380 struct scan_params
*params
= arg
;
2381 int show
= params
->show_both_ie_sets
? 2 : 1;
2382 bool is_dmg
= false;
2384 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
2385 genlmsg_attrlen(gnlh
, 0), NULL
);
2387 if (!tb
[NL80211_ATTR_BSS
]) {
2388 fprintf(stderr
, "bss info missing!\n");
2391 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
2392 tb
[NL80211_ATTR_BSS
],
2394 fprintf(stderr
, "failed to parse nested attributes!\n");
2398 if (!bss
[NL80211_BSS_BSSID
])
2401 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
2402 printf("BSS %s", mac_addr
);
2403 if (tb
[NL80211_ATTR_IFINDEX
]) {
2404 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
2405 printf("(on %s)", dev
);
2408 if (bss
[NL80211_BSS_STATUS
]) {
2409 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
2410 case NL80211_BSS_STATUS_AUTHENTICATED
:
2411 printf(" -- authenticated");
2413 case NL80211_BSS_STATUS_ASSOCIATED
:
2414 printf(" -- associated");
2416 case NL80211_BSS_STATUS_IBSS_JOINED
:
2417 printf(" -- joined");
2420 printf(" -- unknown status: %d",
2421 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
2427 if (bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]) {
2428 unsigned long long bt
;
2429 bt
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]);
2430 printf("\tlast seen: %llu.%.3llus [boottime]\n", bt
/1000000000, (bt
%1000000000)/1000000);
2433 if (bss
[NL80211_BSS_TSF
]) {
2434 unsigned long long tsf
;
2435 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
2436 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
2437 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
2438 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
2440 if (bss
[NL80211_BSS_FREQUENCY
]) {
2441 int freq
= nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]);
2442 printf("\tfreq: %d\n", freq
);
2446 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
2447 printf("\tbeacon interval: %d TUs\n",
2448 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
2449 if (bss
[NL80211_BSS_CAPABILITY
]) {
2450 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
2451 printf("\tcapability:");
2453 print_capa_dmg(capa
);
2455 print_capa_non_dmg(capa
);
2456 printf(" (0x%.4x)\n", capa
);
2458 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
2459 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
2460 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
2462 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
2463 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
2464 printf("\tsignal: %d/100\n", s
);
2466 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
2467 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
2468 printf("\tlast seen: %d ms ago\n", age
);
2471 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
2472 struct nlattr
*ies
= bss
[NL80211_BSS_INFORMATION_ELEMENTS
];
2473 struct nlattr
*bcnies
= bss
[NL80211_BSS_BEACON_IES
];
2475 if (bss
[NL80211_BSS_PRESP_DATA
] ||
2476 (bcnies
&& (nla_len(ies
) != nla_len(bcnies
) ||
2477 memcmp(nla_data(ies
), nla_data(bcnies
),
2479 printf("\tInformation elements from Probe Response "
2481 print_ies(nla_data(ies
), nla_len(ies
),
2482 params
->unknown
, params
->type
);
2484 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
2485 printf("\tInformation elements from Beacon frame:\n");
2486 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
2487 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
2488 params
->unknown
, params
->type
);
2494 static struct scan_params scan_params
;
2496 static int handle_scan_dump(struct nl80211_state
*state
,
2498 int argc
, char **argv
,
2504 memset(&scan_params
, 0, sizeof(scan_params
));
2506 if (argc
== 1 && !strcmp(argv
[0], "-u"))
2507 scan_params
.unknown
= true;
2508 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
2509 scan_params
.show_both_ie_sets
= true;
2511 scan_params
.type
= PRINT_SCAN
;
2513 register_handler(print_bss_handler
, &scan_params
);
2517 static int handle_scan_combined(struct nl80211_state
*state
,
2519 int argc
, char **argv
,
2523 static char *dump_argv
[] = {
2529 static const __u32 cmds
[] = {
2530 NL80211_CMD_NEW_SCAN_RESULTS
,
2531 NL80211_CMD_SCAN_ABORTED
,
2533 int trig_argc
, dump_argc
, err
;
2536 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
2538 dump_argv
[3] = "-u";
2539 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
2541 dump_argv
[3] = "-b";
2545 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
2546 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
2549 trig_argv
[0] = argv
[0];
2550 trig_argv
[1] = "scan";
2551 trig_argv
[2] = "trigger";
2553 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
2554 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
2555 err
= handle_cmd(state
, id
, trig_argc
, trig_argv
);
2561 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
2563 * This code has a bug, which requires creating a separate
2564 * nl80211 socket to fix:
2565 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
2566 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
2567 * before (!) we listen to it, because we only start listening
2568 * after we send our scan request.
2570 * Doing it the other way around has a race condition as well,
2571 * if you first open the events socket you may get a notification
2572 * for a previous scan.
2574 * The only proper way to fix this would be to listen to events
2575 * before sending the command, and for the kernel to send the
2576 * scan request along with the event, so that you can match up
2577 * whether the scan you requested was finished or aborted (this
2578 * may result in processing a scan that another application
2579 * requested, but that doesn't seem to be a problem).
2581 * Alas, the kernel doesn't do that (yet).
2584 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
2585 NL80211_CMD_SCAN_ABORTED
) {
2586 printf("scan aborted!\n");
2590 dump_argv
[0] = argv
[0];
2591 return handle_cmd(state
, id
, dump_argc
, dump_argv
);
2593 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,
2594 CIB_NETDEV
, handle_scan_combined
,
2595 "Scan on the given frequencies and probe for the given SSIDs\n"
2596 "(or wildcard if not given) unless passive scanning is requested.\n"
2597 "If -u is specified print unknown data in the scan results.\n"
2598 "Specified (vendor) IEs must be well-formed.");
2599 COMMAND(scan
, dump
, "[-u]",
2600 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
2601 "Dump the current scan results. If -u is specified, print unknown\n"
2602 "data in scan results.");
2603 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]",
2604 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
2605 "Trigger a scan on the given frequencies with probing for the given\n"
2606 "SSIDs (or wildcard if not given) unless passive scanning is requested.\n"
2607 "Duration(in TUs), if specified, will be used to set dwell times.\n");
2610 static int handle_scan_abort(struct nl80211_state
*state
,
2612 int argc
, char **argv
,
2617 COMMAND(scan
, abort
, "",
2618 NL80211_CMD_ABORT_SCAN
, 0, CIB_NETDEV
, handle_scan_abort
,
2619 "Abort ongoing scan");
2621 static int handle_start_sched_scan(struct nl80211_state
*state
,
2623 int argc
, char **argv
, enum id_input id
)
2625 return parse_sched_scan(msg
, &argc
, &argv
);
2628 static int handle_stop_sched_scan(struct nl80211_state
*state
,
2629 struct nl_msg
*msg
, int argc
, char **argv
,
2638 COMMAND(scan
, sched_start
,
2640 NL80211_CMD_START_SCHED_SCAN
, 0, CIB_NETDEV
, handle_start_sched_scan
,
2641 "Start a scheduled scan at the specified interval on the given frequencies\n"
2642 "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2643 "scanning is requested. If matches are specified, only matching results\n"
2644 "will be returned.");
2645 COMMAND(scan
, sched_stop
, "",
2646 NL80211_CMD_STOP_SCHED_SCAN
, 0, CIB_NETDEV
, handle_stop_sched_scan
,
2647 "Stop an ongoing scheduled scan.");