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_ds(const uint8_t type
, uint8_t len
, const uint8_t *data
,
586 const struct print_ies_data
*ie_buffer
)
588 printf(" channel %d\n", data
[0]);
591 static const char *country_env_str(char environment
)
593 switch (environment
) {
595 return "Indoor only";
597 return "Outdoor only";
599 return "Indoor/Outdoor";
605 static void print_country(const uint8_t type
, uint8_t len
, const uint8_t *data
,
606 const struct print_ies_data
*ie_buffer
)
608 printf(" %.*s", 2, data
);
610 printf("\tEnvironment: %s\n", country_env_str(data
[2]));
616 printf("\t\tNo country IE triplets present\n");
622 union ieee80211_country_ie_triplet
*triplet
= (void *) data
;
624 if (triplet
->ext
.reg_extension_id
>= IEEE80211_COUNTRY_EXTENSION_ID
) {
625 printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
626 triplet
->ext
.reg_extension_id
,
627 triplet
->ext
.reg_class
,
628 triplet
->ext
.coverage_class
,
629 triplet
->ext
.coverage_class
* 450);
637 if (triplet
->chans
.first_channel
<= 14)
638 end_channel
= triplet
->chans
.first_channel
+ (triplet
->chans
.num_channels
- 1);
640 end_channel
= triplet
->chans
.first_channel
+ (4 * (triplet
->chans
.num_channels
- 1));
642 printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet
->chans
.first_channel
, end_channel
, triplet
->chans
.max_power
);
651 static void print_powerconstraint(const uint8_t type
, uint8_t len
,
653 const struct print_ies_data
*ie_buffer
)
655 printf(" %d dB\n", data
[0]);
658 static void print_tpcreport(const uint8_t type
, uint8_t len
,
660 const struct print_ies_data
*ie_buffer
)
662 printf(" TX power: %d dBm\n", data
[0]);
663 /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
666 static void print_erp(const uint8_t type
, uint8_t len
, const uint8_t *data
,
667 const struct print_ies_data
*ie_buffer
)
670 printf(" <no flags>");
672 printf(" NonERP_Present");
674 printf(" Use_Protection");
676 printf(" Barker_Preamble_Mode");
680 static void print_cipher(const uint8_t *data
)
682 if (memcmp(data
, ms_oui
, 3) == 0) {
685 printf("Use group cipher suite");
700 printf("%.02x-%.02x-%.02x:%d",
701 data
[0], data
[1] ,data
[2], data
[3]);
704 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
707 printf("Use group cipher suite");
722 printf("AES-128-CMAC");
731 printf("%.02x-%.02x-%.02x:%d",
732 data
[0], data
[1] ,data
[2], data
[3]);
736 printf("%.02x-%.02x-%.02x:%d",
737 data
[0], data
[1] ,data
[2], data
[3]);
740 static void print_auth(const uint8_t *data
)
742 if (memcmp(data
, ms_oui
, 3) == 0) {
745 printf("IEEE 802.1X");
751 printf("%.02x-%.02x-%.02x:%d",
752 data
[0], data
[1] ,data
[2], data
[3]);
755 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
758 printf("IEEE 802.1X");
764 printf("FT/IEEE 802.1X");
770 printf("IEEE 802.1X/SHA-256");
773 printf("PSK/SHA-256");
785 printf("IEEE 802.1X/SUITE-B");
788 printf("IEEE 802.1X/SUITE-B-192");
791 printf("FT/IEEE 802.1X/SHA-384");
794 printf("FILS/SHA-256");
797 printf("FILS/SHA-384");
800 printf("FT/FILS/SHA-256");
803 printf("FT/FILS/SHA-384");
809 printf("%.02x-%.02x-%.02x:%d",
810 data
[0], data
[1] ,data
[2], data
[3]);
813 } else if (memcmp(data
, wfa_oui
, 3) == 0) {
822 printf("%.02x-%.02x-%.02x:%d",
823 data
[0], data
[1] ,data
[2], data
[3]);
827 printf("%.02x-%.02x-%.02x:%d",
828 data
[0], data
[1] ,data
[2], data
[3]);
831 static void _print_rsn_ie(const char *defcipher
, const char *defauth
,
832 uint8_t len
, const uint8_t *data
, int is_osen
)
840 version
= data
[0] + (data
[1] << 8);
841 tab_on_first(&first
);
842 printf("\t * Version: %d\n", version
);
849 tab_on_first(&first
);
850 printf("\t * Group cipher: %s\n", defcipher
);
851 printf("\t * Pairwise ciphers: %s\n", defcipher
);
855 tab_on_first(&first
);
856 printf("\t * Group cipher: ");
864 tab_on_first(&first
);
865 printf("\t * Pairwise ciphers: %s\n", defcipher
);
869 count
= data
[0] | (data
[1] << 8);
870 if (2 + (count
* 4) > len
)
873 tab_on_first(&first
);
874 printf("\t * Pairwise ciphers:");
875 for (i
= 0; i
< count
; i
++) {
877 print_cipher(data
+ 2 + (i
* 4));
881 data
+= 2 + (count
* 4);
882 len
-= 2 + (count
* 4);
885 tab_on_first(&first
);
886 printf("\t * Authentication suites: %s\n", defauth
);
890 count
= data
[0] | (data
[1] << 8);
891 if (2 + (count
* 4) > len
)
894 tab_on_first(&first
);
895 printf("\t * Authentication suites:");
896 for (i
= 0; i
< count
; i
++) {
898 print_auth(data
+ 2 + (i
* 4));
902 data
+= 2 + (count
* 4);
903 len
-= 2 + (count
* 4);
906 capa
= data
[0] | (data
[1] << 8);
907 tab_on_first(&first
);
908 printf("\t * Capabilities:");
912 printf(" NoPairwise");
913 switch ((capa
& 0x000c) >> 2) {
915 printf(" 1-PTKSA-RC");
918 printf(" 2-PTKSA-RC");
921 printf(" 4-PTKSA-RC");
924 printf(" 16-PTKSA-RC");
927 switch ((capa
& 0x0030) >> 4) {
929 printf(" 1-GTKSA-RC");
932 printf(" 2-GTKSA-RC");
935 printf(" 4-GTKSA-RC");
938 printf(" 16-GTKSA-RC");
942 printf(" MFP-required");
944 printf(" MFP-capable");
946 printf(" Peerkey-enabled");
948 printf(" SPP-AMSDU-capable");
950 printf(" SPP-AMSDU-required");
951 printf(" (0x%.4x)\n", capa
);
957 int pmkid_count
= data
[0] | (data
[1] << 8);
959 if (len
>= 2 + 16 * pmkid_count
) {
960 tab_on_first(&first
);
961 printf("\t * %d PMKIDs\n", pmkid_count
);
962 /* not printing PMKID values */
963 data
+= 2 + 16 * pmkid_count
;
964 len
-= 2 + 16 * pmkid_count
;
970 tab_on_first(&first
);
971 printf("\t * Group mgmt cipher suite: ");
980 printf("\t\t * bogus tail data (%d):", len
);
982 printf(" %.2x", *data
);
990 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
991 uint8_t len
, const uint8_t *data
)
993 _print_rsn_ie(defcipher
, defauth
, len
, data
, 0);
996 static void print_osen_ie(const char *defcipher
, const char *defauth
,
997 uint8_t len
, const uint8_t *data
)
1000 _print_rsn_ie(defcipher
, defauth
, len
, data
, 1);
1003 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1004 const struct print_ies_data
*ie_buffer
)
1006 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
1009 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1010 const struct print_ies_data
*ie_buffer
)
1013 print_ht_capability(data
[0] | (data
[1] << 8));
1014 print_ampdu_length(data
[2] & 3);
1015 print_ampdu_spacing((data
[2] >> 2) & 7);
1016 print_ht_mcs(data
+ 3);
1019 static const char* ntype_11u(uint8_t t
)
1022 case 0: return "Private";
1023 case 1: return "Private with Guest";
1024 case 2: return "Chargeable Public";
1025 case 3: return "Free Public";
1026 case 4: return "Personal Device";
1027 case 5: return "Emergency Services Only";
1028 case 14: return "Test or Experimental";
1029 case 15: return "Wildcard";
1030 default: return "Reserved";
1034 static const char* vgroup_11u(uint8_t t
)
1037 case 0: return "Unspecified";
1038 case 1: return "Assembly";
1039 case 2: return "Business";
1040 case 3: return "Educational";
1041 case 4: return "Factory and Industrial";
1042 case 5: return "Institutional";
1043 case 6: return "Mercantile";
1044 case 7: return "Residential";
1045 case 8: return "Storage";
1046 case 9: return "Utility and Miscellaneous";
1047 case 10: return "Vehicular";
1048 case 11: return "Outdoor";
1049 default: return "Reserved";
1053 static void print_interworking(const uint8_t type
, uint8_t len
,
1054 const uint8_t *data
,
1055 const struct print_ies_data
*ie_buffer
)
1057 /* See Section 7.3.2.92 in the 802.11u spec. */
1060 uint8_t ano
= data
[0];
1061 printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano
));
1062 printf("\t\t\tNetwork Type: %i (%s)\n",
1063 (int)(ano
& 0xf), ntype_11u(ano
& 0xf));
1065 printf("\t\t\tInternet\n");
1067 printf("\t\t\tASRA\n");
1069 printf("\t\t\tESR\n");
1071 printf("\t\t\tUESA\n");
1073 if ((len
== 3) || (len
== 9)) {
1074 printf("\t\tVenue Group: %i (%s)\n",
1075 (int)(data
[1]), vgroup_11u(data
[1]));
1076 printf("\t\tVenue Type: %i\n", (int)(data
[2]));
1079 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
1080 data
[3], data
[4], data
[5], data
[6], data
[7], data
[8]);
1082 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
1083 data
[1], data
[2], data
[3], data
[4], data
[5], data
[6]);
1086 static void print_11u_advert(const uint8_t type
, uint8_t len
,
1087 const uint8_t *data
,
1088 const struct print_ies_data
*ie_buffer
)
1090 /* See Section 7.3.2.93 in the 802.11u spec. */
1091 /* TODO: This code below does not decode private protocol IDs */
1094 while (idx
< (len
- 1)) {
1095 uint8_t qri
= data
[idx
];
1096 uint8_t proto_id
= data
[idx
+ 1];
1097 printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri
));
1098 printf("\t\t\tQuery Response Length Limit: %i\n",
1101 printf("\t\t\tPAME-BI\n");
1104 printf("\t\t\tANQP\n"); break;
1106 printf("\t\t\tMIH Information Service\n"); break;
1108 printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
1110 printf("\t\t\tEmergency Alert System (EAS)\n"); break;
1112 printf("\t\t\tVendor Specific\n"); break;
1114 printf("\t\t\tReserved: %i\n", proto_id
); break;
1120 static void print_11u_rcon(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1121 const struct print_ies_data
*ie_buffer
)
1123 /* See Section 7.3.2.96 in the 802.11u spec. */
1125 int ln0
= data
[1] & 0xf;
1126 int ln1
= ((data
[1] & 0xf0) >> 4);
1131 ln2
= len
- 2 - ln0
- ln1
;
1133 printf("\t\tANQP OIs: %i\n", data
[0]);
1136 printf("\t\tOI 1: ");
1137 if (2 + ln0
> len
) {
1138 printf("Invalid IE length.\n");
1140 for (idx
= 0; idx
< ln0
; idx
++) {
1141 printf("%02hx", data
[2 + idx
]);
1148 printf("\t\tOI 2: ");
1149 if (2 + ln0
+ ln1
> len
) {
1150 printf("Invalid IE length.\n");
1152 for (idx
= 0; idx
< ln1
; idx
++) {
1153 printf("%02hx", data
[2 + ln0
+ idx
]);
1160 printf("\t\tOI 3: ");
1161 if (2 + ln0
+ ln1
+ ln2
> len
) {
1162 printf("Invalid IE length.\n");
1164 for (idx
= 0; idx
< ln2
; idx
++) {
1165 printf("%02hx", data
[2 + ln0
+ ln1
+ idx
]);
1172 static const char *ht_secondary_offset
[4] = {
1179 static void print_ht_op(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1180 const struct print_ies_data
*ie_buffer
)
1182 static const char *protection
[4] = {
1188 static const char *sta_chan_width
[2] = {
1194 printf("\t\t * primary channel: %d\n", data
[0]);
1195 printf("\t\t * secondary channel offset: %s\n",
1196 ht_secondary_offset
[data
[1] & 0x3]);
1197 printf("\t\t * STA channel width: %s\n", sta_chan_width
[(data
[1] & 0x4)>>2]);
1198 printf("\t\t * RIFS: %d\n", (data
[1] & 0x8)>>3);
1199 printf("\t\t * HT protection: %s\n", protection
[data
[2] & 0x3]);
1200 printf("\t\t * non-GF present: %d\n", (data
[2] & 0x4) >> 2);
1201 printf("\t\t * OBSS non-GF present: %d\n", (data
[2] & 0x10) >> 4);
1202 printf("\t\t * dual beacon: %d\n", (data
[4] & 0x40) >> 6);
1203 printf("\t\t * dual CTS protection: %d\n", (data
[4] & 0x80) >> 7);
1204 printf("\t\t * STBC beacon: %d\n", data
[5] & 0x1);
1205 printf("\t\t * L-SIG TXOP Prot: %d\n", (data
[5] & 0x2) >> 1);
1206 printf("\t\t * PCO active: %d\n", (data
[5] & 0x4) >> 2);
1207 printf("\t\t * PCO phase: %d\n", (data
[5] & 0x8) >> 3);
1210 static void print_capabilities(const uint8_t type
, uint8_t len
,
1211 const uint8_t *data
,
1212 const struct print_ies_data
*ie_buffer
)
1214 int i
, base
, bit
, si_duration
= 0, max_amsdu
= 0;
1215 bool s_psmp_support
= false, is_vht_cap
= false;
1216 unsigned char *ie
= ie_buffer
->ie
;
1217 int ielen
= ie_buffer
->ielen
;
1219 while (ielen
>= 2 && ielen
>= ie
[1]) {
1228 for (i
= 0; i
< len
; i
++) {
1231 for (bit
= 0; bit
< 8; bit
++) {
1232 if (!(data
[i
] & (1 << bit
)))
1237 #define CAPA(bit, name) case bit: printf(" " name); break
1239 /* if the capability 'cap' exists add 'val' to 'sum'
1240 * otherwise print 'Reserved' */
1241 #define ADD_BIT_VAL(bit, cap, sum, val) case (bit): do { \
1243 printf(" Reserved"); \
1250 switch (bit
+ base
) {
1251 CAPA(0, "HT Information Exchange Supported");
1252 CAPA(1, "reserved (On-demand Beacon)");
1253 CAPA(2, "Extended Channel Switching");
1254 CAPA(3, "reserved (Wave Indication)");
1255 CAPA(4, "PSMP Capability");
1256 CAPA(5, "reserved (Service Interval Granularity)");
1259 s_psmp_support
= true;
1260 printf(" S-PSMP Capability");
1264 CAPA(8, "Diagnostics");
1265 CAPA(9, "Multicast Diagnostics");
1266 CAPA(10, "Location Tracking");
1268 CAPA(12, "Proxy ARP Service");
1269 CAPA(13, "Collocated Interference Reporting");
1270 CAPA(14, "Civic Location");
1271 CAPA(15, "Geospatial Location");
1273 CAPA(17, "WNM-Sleep Mode");
1274 CAPA(18, "TIM Broadcast");
1275 CAPA(19, "BSS Transition");
1276 CAPA(20, "QoS Traffic Capability");
1277 CAPA(21, "AC Station Count");
1278 CAPA(22, "Multiple BSSID");
1279 CAPA(23, "Timing Measurement");
1280 CAPA(24, "Channel Usage");
1281 CAPA(25, "SSID List");
1283 CAPA(27, "UTC TSF Offset");
1284 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1285 CAPA(29, "TDLS Peer PSM Support");
1286 CAPA(30, "TDLS channel switching");
1287 CAPA(31, "Interworking");
1288 CAPA(32, "QoS Map");
1290 CAPA(34, "SSPN Interface");
1291 CAPA(35, "Reserved");
1292 CAPA(36, "MSGCF Capability");
1293 CAPA(37, "TDLS Support");
1294 CAPA(38, "TDLS Prohibited");
1295 CAPA(39, "TDLS Channel Switching Prohibited");
1296 CAPA(40, "Reject Unadmitted Frame");
1298 ADD_BIT_VAL(41, s_psmp_support
, si_duration
, 1);
1299 ADD_BIT_VAL(42, s_psmp_support
, si_duration
, 2);
1300 ADD_BIT_VAL(43, s_psmp_support
, si_duration
, 4);
1302 CAPA(44, "Identifier Location");
1303 CAPA(45, "U-APSD Coexistence");
1304 CAPA(46, "WNM-Notification");
1305 CAPA(47, "Reserved");
1306 CAPA(48, "UTF-8 SSID");
1307 CAPA(49, "QMFActivated");
1308 CAPA(50, "QMFReconfigurationActivated");
1309 CAPA(51, "Robust AV Streaming");
1310 CAPA(52, "Advanced GCR");
1311 CAPA(53, "Mesh GCR");
1313 CAPA(55, "QLoad Report");
1314 CAPA(56, "Alternate EDCA");
1315 CAPA(57, "Unprotected TXOP Negotiation");
1316 CAPA(58, "Protected TXOP egotiation");
1317 CAPA(59, "Reserved");
1318 CAPA(60, "Protected QLoad Report");
1319 CAPA(61, "TDLS Wider Bandwidth");
1320 CAPA(62, "Operating Mode Notification");
1322 ADD_BIT_VAL(63, is_vht_cap
, max_amsdu
, 1);
1323 ADD_BIT_VAL(64, is_vht_cap
, max_amsdu
, 2);
1325 CAPA(65, "Channel Schedule Management");
1326 CAPA(66, "Geodatabase Inband Enabling Signal");
1327 CAPA(67, "Network Channel Control");
1328 CAPA(68, "White Space Map");
1329 CAPA(69, "Channel Availability Query");
1330 CAPA(70, "FTM Responder");
1331 CAPA(71, "FTM Initiator");
1332 CAPA(72, "Reserved");
1333 CAPA(73, "Extended Spectrum Management Capable");
1334 CAPA(74, "Reserved");
1345 printf("\n\t\t * Service Interval Granularity is %d ms",
1346 (si_duration
+ 1) * 5);
1349 printf("\n\t\t * Max Number Of MSDUs In A-MSDU is ");
1350 switch (max_amsdu
) {
1352 printf("unlimited");
1371 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1372 const struct print_ies_data
*ie_buffer
)
1374 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1376 data
[0], data
[1], data
[2], data
[3]);
1378 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
1382 static void print_ibssatim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1383 const struct print_ies_data
*ie_buffer
)
1385 printf(" %d TUs\n", (data
[1] << 8) + data
[0]);
1388 static void print_vht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1389 const struct print_ies_data
*ie_buffer
)
1392 print_vht_info(data
[0] | (data
[1] << 8) |
1393 (data
[2] << 16) | (data
[3] << 24),
1397 static void print_vht_oper(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1398 const struct print_ies_data
*ie_buffer
)
1400 const char *chandwidths
[] = {
1401 [0] = "20 or 40 MHz",
1408 printf("\t\t * channel width: %d (%s)\n", data
[0],
1409 data
[0] < ARRAY_SIZE(chandwidths
) ? chandwidths
[data
[0]] : "unknown");
1410 printf("\t\t * center freq segment 1: %d\n", data
[1]);
1411 printf("\t\t * center freq segment 2: %d\n", data
[2]);
1412 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data
[4], data
[3]);
1415 static void print_obss_scan_params(const uint8_t type
, uint8_t len
,
1416 const uint8_t *data
,
1417 const struct print_ies_data
*ie_buffer
)
1420 printf("\t\t * passive dwell: %d TUs\n", (data
[1] << 8) | data
[0]);
1421 printf("\t\t * active dwell: %d TUs\n", (data
[3] << 8) | data
[2]);
1422 printf("\t\t * channel width trigger scan interval: %d s\n", (data
[5] << 8) | data
[4]);
1423 printf("\t\t * scan passive total per channel: %d TUs\n", (data
[7] << 8) | data
[6]);
1424 printf("\t\t * scan active total per channel: %d TUs\n", (data
[9] << 8) | data
[8]);
1425 printf("\t\t * BSS width channel transition delay factor: %d\n", (data
[11] << 8) | data
[10]);
1426 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1427 ((data
[13] << 8) | data
[12]) / 100, ((data
[13] << 8) | data
[12]) % 100);
1430 static void print_secchan_offs(const uint8_t type
, uint8_t len
,
1431 const uint8_t *data
,
1432 const struct print_ies_data
*ie_buffer
)
1434 if (data
[0] < ARRAY_SIZE(ht_secondary_offset
))
1435 printf(" %s (%d)\n", ht_secondary_offset
[data
[0]], data
[0]);
1437 printf(" %d\n", data
[0]);
1440 static void print_bss_load(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1441 const struct print_ies_data
*ie_buffer
)
1444 printf("\t\t * station count: %d\n", (data
[1] << 8) | data
[0]);
1445 printf("\t\t * channel utilisation: %d/255\n", data
[2]);
1446 printf("\t\t * available admission capacity: %d [*32us]\n", (data
[4] << 8) | data
[3]);
1449 static void print_mesh_conf(const uint8_t type
, uint8_t len
,
1450 const uint8_t *data
,
1451 const struct print_ies_data
*ie_buffer
)
1454 printf("\t\t * Active Path Selection Protocol ID: %d\n", data
[0]);
1455 printf("\t\t * Active Path Selection Metric ID: %d\n", data
[1]);
1456 printf("\t\t * Congestion Control Mode ID: %d\n", data
[2]);
1457 printf("\t\t * Synchronization Method ID: %d\n", data
[3]);
1458 printf("\t\t * Authentication Protocol ID: %d\n", data
[4]);
1459 printf("\t\t * Mesh Formation Info:\n");
1460 printf("\t\t\t Number of Peerings: %d\n", (data
[5] & 0x7E) >> 1);
1462 printf("\t\t\t Connected to Mesh Gate\n");
1464 printf("\t\t\t Connected to AS\n");
1465 printf("\t\t * Mesh Capability\n");
1467 printf("\t\t\t Accepting Additional Mesh Peerings\n");
1469 printf("\t\t\t MCCA Supported\n");
1471 printf("\t\t\t MCCA Enabled\n");
1473 printf("\t\t\t Forwarding\n");
1475 printf("\t\t\t MBCA Supported\n");
1477 printf("\t\t\t TBTT Adjusting\n");
1479 printf("\t\t\t Mesh Power Save Level\n");
1484 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1485 const struct print_ies_data
*ie_buffer
);
1486 uint8_t minlen
, maxlen
;
1490 static void print_ie(const struct ie_print
*p
, const uint8_t type
, uint8_t len
,
1491 const uint8_t *data
,
1492 const struct print_ies_data
*ie_buffer
)
1499 printf("\t%s:", p
->name
);
1500 if (len
< p
->minlen
|| len
> p
->maxlen
) {
1502 printf(" <invalid: %d bytes:", len
);
1503 for (i
= 0; i
< len
; i
++)
1504 printf(" %.02x", data
[i
]);
1507 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
1509 printf(" <invalid: no data>\n");
1513 p
->print(type
, len
, data
, ie_buffer
);
1516 #define PRINT_IGN { \
1523 static const struct ie_print ieprinters
[] = {
1524 [0] = { "SSID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1525 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1526 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
1527 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
1528 [6] = { "IBSS ATIM window", print_ibssatim
, 2, 2, BIT(PRINT_SCAN
), },
1529 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
1530 [11] = { "BSS Load", print_bss_load
, 5, 5, BIT(PRINT_SCAN
), },
1531 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
1532 [35] = { "TPC report", print_tpcreport
, 2, 2, BIT(PRINT_SCAN
), },
1533 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1534 [45] = { "HT capabilities", print_ht_capa
, 26, 26, BIT(PRINT_SCAN
), },
1535 [47] = { "ERP D4.0", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1536 [74] = { "Overlapping BSS scan params", print_obss_scan_params
, 14, 255, BIT(PRINT_SCAN
), },
1537 [61] = { "HT operation", print_ht_op
, 22, 22, BIT(PRINT_SCAN
), },
1538 [62] = { "Secondary Channel Offset", print_secchan_offs
, 1, 1, BIT(PRINT_SCAN
), },
1539 [191] = { "VHT capabilities", print_vht_capa
, 12, 255, BIT(PRINT_SCAN
), },
1540 [192] = { "VHT operation", print_vht_oper
, 5, 255, BIT(PRINT_SCAN
), },
1541 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
1542 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1543 [113] = { "MESH Configuration", print_mesh_conf
, 7, 7, BIT(PRINT_SCAN
), },
1544 [114] = { "MESH ID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1545 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
1546 [107] = { "802.11u Interworking", print_interworking
, 0, 255, BIT(PRINT_SCAN
), },
1547 [108] = { "802.11u Advertisement", print_11u_advert
, 0, 255, BIT(PRINT_SCAN
), },
1548 [111] = { "802.11u Roaming Consortium", print_11u_rcon
, 0, 255, BIT(PRINT_SCAN
), },
1551 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1552 const struct print_ies_data
*ie_buffer
)
1554 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
1557 static void print_wifi_osen(const uint8_t type
, uint8_t len
,
1558 const uint8_t *data
,
1559 const struct print_ies_data
*ie_buffer
)
1561 print_osen_ie("OSEN", "OSEN", len
, data
);
1564 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
1567 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
1573 printf("Parameter: not version 1: ");
1577 printf("\t * Parameter version 1");
1582 printf("\n\t\t * u-APSD");
1586 for (i
= 0; i
< 4; i
++) {
1587 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
1590 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
1591 (1 << (data
[1] >> 4)) - 1);
1592 printf(", AIFSN %d", data
[0] & 0xf);
1593 if (data
[2] | data
[3])
1594 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
1602 printf("invalid: ");
1606 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1607 const struct print_ies_data
*ie_buffer
)
1613 printf(" information:");
1616 if (print_wifi_wmm_param(data
+ 1, len
- 1))
1620 printf(" type %d:", data
[0]);
1624 for(i
= 1; i
< len
; i
++)
1625 printf(" %.02x", data
[i
]);
1629 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
1633 return "Default (PIN)";
1635 return "User-specified";
1637 return "Machine-specified";
1641 return "PushButton";
1643 return "Registrar-specified";
1649 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1650 const struct print_ies_data
*ie_buffer
)
1653 __u16 subtype
, sublen
;
1656 subtype
= (data
[0] << 8) + data
[1];
1657 sublen
= (data
[2] << 8) + data
[3];
1663 tab_on_first(&first
);
1664 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
1667 tab_on_first(&first
);
1668 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
1672 tab_on_first(&first
);
1674 printf("\t * Device Password ID: (invalid "
1675 "length %d)\n", sublen
);
1678 id
= data
[4] << 8 | data
[5];
1679 printf("\t * Device Password ID: %u (%s)\n",
1680 id
, wifi_wps_dev_passwd_id(id
));
1684 tab_on_first(&first
);
1685 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
1688 tab_on_first(&first
);
1689 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
1692 tab_on_first(&first
);
1693 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
1697 tab_on_first(&first
);
1698 printf("\t * Response Type: %d%s\n",
1699 val
, val
== 3 ? " (AP)" : "");
1704 tab_on_first(&first
);
1705 printf("\t * RF Bands: 0x%x\n", val
);
1710 tab_on_first(&first
);
1711 printf("\t * Selected Registrar: 0x%x\n", val
);
1715 tab_on_first(&first
);
1716 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
1720 tab_on_first(&first
);
1721 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1723 val
== 1 ? " (Unconfigured)" : "",
1724 val
== 2 ? " (Configured)" : "");
1728 tab_on_first(&first
);
1729 printf("\t * UUID: ");
1731 printf("(invalid, length=%d)\n", sublen
);
1734 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1735 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1736 data
[4], data
[5], data
[6], data
[7],
1737 data
[8], data
[9], data
[10], data
[11],
1738 data
[12], data
[13], data
[14], data
[15],
1739 data
[16], data
[17], data
[18], data
[19]);
1742 tab_on_first(&first
);
1744 printf("\t * Primary Device Type: (invalid "
1745 "length %d)\n", sublen
);
1748 printf("\t * Primary Device Type: "
1749 "%u-%02x%02x%02x%02x-%u\n",
1750 data
[4] << 8 | data
[5],
1751 data
[6], data
[7], data
[8], data
[9],
1752 data
[10] << 8 | data
[11]);
1757 tab_on_first(&first
);
1758 printf("\t * AP setup locked: 0x%.2x\n", val
);
1763 __u16 meth
= (data
[4] << 8) + data
[5];
1765 tab_on_first(&first
);
1766 printf("\t * %sConfig methods:",
1767 subtype
== 0x1053 ? "Selected Registrar ": "");
1768 #define T(bit, name) do { \
1769 if (meth & (1<<bit)) { \
1789 const __u8
*subdata
= data
+ 4;
1790 __u16 tmplen
= sublen
;
1792 tab_on_first(&first
);
1793 printf("\t * Unknown TLV (%#.4x, %d bytes):",
1796 printf(" %.2x", *subdata
);
1810 printf("\t\t * bogus tail data (%d):", len
);
1812 printf(" %.2x", *data
);
1820 static const struct ie_print wifiprinters
[] = {
1821 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
1822 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
1823 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
1826 static inline void print_p2p(const uint8_t type
, uint8_t len
,
1827 const uint8_t *data
,
1828 const struct print_ies_data
*ie_buffer
)
1836 sublen
= (data
[2] << 8) + data
[1];
1838 if (sublen
> len
- 3)
1842 case 0x02: /* capability */
1843 tab_on_first(&first
);
1845 printf("\t * malformed capability\n");
1848 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
1851 case 0x0d: /* device info */
1852 if (sublen
< 6 + 2 + 8 + 1) {
1853 printf("\t * malformed device info\n");
1857 case 0x00: /* status */
1858 case 0x01: /* minor reason */
1859 case 0x03: /* device ID */
1860 case 0x04: /* GO intent */
1861 case 0x05: /* configuration timeout */
1862 case 0x06: /* listen channel */
1863 case 0x07: /* group BSSID */
1864 case 0x08: /* ext listen timing */
1865 case 0x09: /* intended interface address */
1866 case 0x0a: /* manageability */
1867 case 0x0b: /* channel list */
1868 case 0x0c: /* NoA */
1869 case 0x0e: /* group info */
1870 case 0x0f: /* group ID */
1871 case 0x10: /* interface */
1872 case 0x11: /* operating channel */
1873 case 0x12: /* invitation flags */
1874 case 0xdd: /* vendor specific */
1876 const __u8
*subdata
= data
+ 4;
1877 __u16 tmplen
= sublen
;
1879 tab_on_first(&first
);
1880 printf("\t * Unknown TLV (%#.2x, %d bytes):",
1883 printf(" %.2x", *subdata
);
1897 tab_on_first(&first
);
1898 printf("\t * bogus tail data (%d):", len
);
1900 printf(" %.2x", *data
);
1908 static inline void print_hs20_ind(const uint8_t type
, uint8_t len
,
1909 const uint8_t *data
,
1910 const struct print_ies_data
*ie_buffer
)
1912 /* I can't find the spec for this...just going off what wireshark uses. */
1915 printf("\t\tDGAF: %i\n", (int)(data
[0] & 0x1));
1917 printf("\t\tUnexpected length: %i\n", len
);
1920 static void print_wifi_owe_tarns(const uint8_t type
, uint8_t len
,
1921 const uint8_t *data
,
1922 const struct print_ies_data
*ie_buffer
)
1931 mac_addr_n2a(mac_addr
, data
);
1932 printf("\t\tBSSID: %s\n", mac_addr
);
1935 if (ssid_len
> len
- 7)
1937 printf("\t\tSSID: ");
1938 print_ssid_escaped(ssid_len
, data
+ 7);
1941 /* optional elements */
1942 if (len
>= ssid_len
+ 9) {
1943 printf("\t\tBand Info: %u\n", data
[ssid_len
+ 7]);
1944 printf("\t\tChannel Info: %u\n", data
[ssid_len
+ 8]);
1948 static const struct ie_print wfa_printers
[] = {
1949 [9] = { "P2P", print_p2p
, 2, 255, BIT(PRINT_SCAN
), },
1950 [16] = { "HotSpot 2.0 Indication", print_hs20_ind
, 1, 255, BIT(PRINT_SCAN
), },
1951 [18] = { "HotSpot 2.0 OSEN", print_wifi_osen
, 1, 255, BIT(PRINT_SCAN
), },
1952 [28] = { "OWE Transition Mode", print_wifi_owe_tarns
, 7, 255, BIT(PRINT_SCAN
), },
1955 static void print_vendor(unsigned char len
, unsigned char *data
,
1956 bool unknown
, enum print_ie_type ptype
)
1961 printf("\tVendor specific: <too short> data:");
1962 for(i
= 0; i
< len
; i
++)
1963 printf(" %.02x", data
[i
]);
1968 if (len
>= 4 && memcmp(data
, ms_oui
, 3) == 0) {
1969 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
1970 wifiprinters
[data
[3]].name
&&
1971 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
1972 print_ie(&wifiprinters
[data
[3]],
1973 data
[3], len
- 4, data
+ 4,
1979 printf("\tMS/WiFi %#.2x, data:", data
[3]);
1980 for(i
= 0; i
< len
- 4; i
++)
1981 printf(" %.02x", data
[i
+ 4]);
1986 if (len
>= 4 && memcmp(data
, wfa_oui
, 3) == 0) {
1987 if (data
[3] < ARRAY_SIZE(wfa_printers
) &&
1988 wfa_printers
[data
[3]].name
&&
1989 wfa_printers
[data
[3]].flags
& BIT(ptype
)) {
1990 print_ie(&wfa_printers
[data
[3]],
1991 data
[3], len
- 4, data
+ 4,
1997 printf("\tWFA %#.2x, data:", data
[3]);
1998 for(i
= 0; i
< len
- 4; i
++)
1999 printf(" %.02x", data
[i
+ 4]);
2007 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
2008 data
[0], data
[1], data
[2]);
2009 for (i
= 3; i
< len
; i
++)
2010 printf(" %.2x", data
[i
]);
2014 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
2015 enum print_ie_type ptype
)
2017 struct print_ies_data ie_buffer
= {
2021 while (ielen
>= 2 && ielen
>= ie
[1]) {
2022 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
2023 ieprinters
[ie
[0]].name
&&
2024 ieprinters
[ie
[0]].flags
& BIT(ptype
)) {
2025 print_ie(&ieprinters
[ie
[0]],
2026 ie
[0], ie
[1], ie
+ 2, &ie_buffer
);
2027 } else if (ie
[0] == 221 /* vendor */) {
2028 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
2029 } else if (unknown
) {
2032 printf("\tUnknown IE (%d):", ie
[0]);
2033 for (i
=0; i
<ie
[1]; i
++)
2034 printf(" %.2x", ie
[2+i
]);
2042 static void print_capa_dmg(__u16 capa
)
2044 switch (capa
& WLAN_CAPABILITY_DMG_TYPE_MASK
) {
2045 case WLAN_CAPABILITY_DMG_TYPE_AP
:
2048 case WLAN_CAPABILITY_DMG_TYPE_PBSS
:
2051 case WLAN_CAPABILITY_DMG_TYPE_IBSS
:
2052 printf(" DMG_IBSS");
2056 if (capa
& WLAN_CAPABILITY_DMG_CBAP_ONLY
)
2057 printf(" CBAP_Only");
2058 if (capa
& WLAN_CAPABILITY_DMG_CBAP_SOURCE
)
2059 printf(" CBAP_Src");
2060 if (capa
& WLAN_CAPABILITY_DMG_PRIVACY
)
2062 if (capa
& WLAN_CAPABILITY_DMG_ECPAC
)
2064 if (capa
& WLAN_CAPABILITY_DMG_SPECTRUM_MGMT
)
2065 printf(" SpectrumMgmt");
2066 if (capa
& WLAN_CAPABILITY_DMG_RADIO_MEASURE
)
2067 printf(" RadioMeasure");
2070 static void print_capa_non_dmg(__u16 capa
)
2072 if (capa
& WLAN_CAPABILITY_ESS
)
2074 if (capa
& WLAN_CAPABILITY_IBSS
)
2076 if (capa
& WLAN_CAPABILITY_CF_POLLABLE
)
2077 printf(" CfPollable");
2078 if (capa
& WLAN_CAPABILITY_CF_POLL_REQUEST
)
2079 printf(" CfPollReq");
2080 if (capa
& WLAN_CAPABILITY_PRIVACY
)
2082 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
2083 printf(" ShortPreamble");
2084 if (capa
& WLAN_CAPABILITY_PBCC
)
2086 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
2087 printf(" ChannelAgility");
2088 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
2089 printf(" SpectrumMgmt");
2090 if (capa
& WLAN_CAPABILITY_QOS
)
2092 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
2093 printf(" ShortSlotTime");
2094 if (capa
& WLAN_CAPABILITY_APSD
)
2096 if (capa
& WLAN_CAPABILITY_RADIO_MEASURE
)
2097 printf(" RadioMeasure");
2098 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
2099 printf(" DSSS-OFDM");
2100 if (capa
& WLAN_CAPABILITY_DEL_BACK
)
2101 printf(" DelayedBACK");
2102 if (capa
& WLAN_CAPABILITY_IMM_BACK
)
2103 printf(" ImmediateBACK");
2106 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
2108 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
2109 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
2110 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
2111 char mac_addr
[20], dev
[20];
2112 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
2113 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
2114 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
2115 [NL80211_BSS_BSSID
] = { },
2116 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
2117 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
2118 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
2119 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
2120 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
2121 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
2122 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
2123 [NL80211_BSS_BEACON_IES
] = { },
2125 struct scan_params
*params
= arg
;
2126 int show
= params
->show_both_ie_sets
? 2 : 1;
2127 bool is_dmg
= false;
2129 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
2130 genlmsg_attrlen(gnlh
, 0), NULL
);
2132 if (!tb
[NL80211_ATTR_BSS
]) {
2133 fprintf(stderr
, "bss info missing!\n");
2136 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
2137 tb
[NL80211_ATTR_BSS
],
2139 fprintf(stderr
, "failed to parse nested attributes!\n");
2143 if (!bss
[NL80211_BSS_BSSID
])
2146 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
2147 printf("BSS %s", mac_addr
);
2148 if (tb
[NL80211_ATTR_IFINDEX
]) {
2149 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
2150 printf("(on %s)", dev
);
2153 if (bss
[NL80211_BSS_STATUS
]) {
2154 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
2155 case NL80211_BSS_STATUS_AUTHENTICATED
:
2156 printf(" -- authenticated");
2158 case NL80211_BSS_STATUS_ASSOCIATED
:
2159 printf(" -- associated");
2161 case NL80211_BSS_STATUS_IBSS_JOINED
:
2162 printf(" -- joined");
2165 printf(" -- unknown status: %d",
2166 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
2172 if (bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]) {
2173 unsigned long long bt
;
2174 bt
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]);
2175 printf("\tlast seen: %llu.%.3llus [boottime]\n", bt
/1000000000, (bt
%1000000000)/1000000);
2178 if (bss
[NL80211_BSS_TSF
]) {
2179 unsigned long long tsf
;
2180 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
2181 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
2182 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
2183 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
2185 if (bss
[NL80211_BSS_FREQUENCY
]) {
2186 int freq
= nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]);
2187 printf("\tfreq: %d\n", freq
);
2191 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
2192 printf("\tbeacon interval: %d TUs\n",
2193 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
2194 if (bss
[NL80211_BSS_CAPABILITY
]) {
2195 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
2196 printf("\tcapability:");
2198 print_capa_dmg(capa
);
2200 print_capa_non_dmg(capa
);
2201 printf(" (0x%.4x)\n", capa
);
2203 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
2204 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
2205 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
2207 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
2208 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
2209 printf("\tsignal: %d/100\n", s
);
2211 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
2212 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
2213 printf("\tlast seen: %d ms ago\n", age
);
2216 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
2217 struct nlattr
*ies
= bss
[NL80211_BSS_INFORMATION_ELEMENTS
];
2218 struct nlattr
*bcnies
= bss
[NL80211_BSS_BEACON_IES
];
2220 if (bss
[NL80211_BSS_PRESP_DATA
] ||
2221 (bcnies
&& (nla_len(ies
) != nla_len(bcnies
) ||
2222 memcmp(nla_data(ies
), nla_data(bcnies
),
2224 printf("\tInformation elements from Probe Response "
2226 print_ies(nla_data(ies
), nla_len(ies
),
2227 params
->unknown
, params
->type
);
2229 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
2230 printf("\tInformation elements from Beacon frame:\n");
2231 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
2232 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
2233 params
->unknown
, params
->type
);
2239 static struct scan_params scan_params
;
2241 static int handle_scan_dump(struct nl80211_state
*state
,
2243 int argc
, char **argv
,
2249 memset(&scan_params
, 0, sizeof(scan_params
));
2251 if (argc
== 1 && !strcmp(argv
[0], "-u"))
2252 scan_params
.unknown
= true;
2253 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
2254 scan_params
.show_both_ie_sets
= true;
2256 scan_params
.type
= PRINT_SCAN
;
2258 register_handler(print_bss_handler
, &scan_params
);
2262 static int handle_scan_combined(struct nl80211_state
*state
,
2264 int argc
, char **argv
,
2268 static char *dump_argv
[] = {
2274 static const __u32 cmds
[] = {
2275 NL80211_CMD_NEW_SCAN_RESULTS
,
2276 NL80211_CMD_SCAN_ABORTED
,
2278 int trig_argc
, dump_argc
, err
;
2281 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
2283 dump_argv
[3] = "-u";
2284 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
2286 dump_argv
[3] = "-b";
2290 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
2291 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
2294 trig_argv
[0] = argv
[0];
2295 trig_argv
[1] = "scan";
2296 trig_argv
[2] = "trigger";
2298 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
2299 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
2300 err
= handle_cmd(state
, id
, trig_argc
, trig_argv
);
2306 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
2308 * This code has a bug, which requires creating a separate
2309 * nl80211 socket to fix:
2310 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
2311 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
2312 * before (!) we listen to it, because we only start listening
2313 * after we send our scan request.
2315 * Doing it the other way around has a race condition as well,
2316 * if you first open the events socket you may get a notification
2317 * for a previous scan.
2319 * The only proper way to fix this would be to listen to events
2320 * before sending the command, and for the kernel to send the
2321 * scan request along with the event, so that you can match up
2322 * whether the scan you requested was finished or aborted (this
2323 * may result in processing a scan that another application
2324 * requested, but that doesn't seem to be a problem).
2326 * Alas, the kernel doesn't do that (yet).
2329 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
2330 NL80211_CMD_SCAN_ABORTED
) {
2331 printf("scan aborted!\n");
2335 dump_argv
[0] = argv
[0];
2336 return handle_cmd(state
, id
, dump_argc
, dump_argv
);
2338 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,
2339 CIB_NETDEV
, handle_scan_combined
,
2340 "Scan on the given frequencies and probe for the given SSIDs\n"
2341 "(or wildcard if not given) unless passive scanning is requested.\n"
2342 "If -u is specified print unknown data in the scan results.\n"
2343 "Specified (vendor) IEs must be well-formed.");
2344 COMMAND(scan
, dump
, "[-u]",
2345 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
2346 "Dump the current scan results. If -u is specified, print unknown\n"
2347 "data in scan results.");
2348 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]",
2349 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
2350 "Trigger a scan on the given frequencies with probing for the given\n"
2351 "SSIDs (or wildcard if not given) unless passive scanning is requested.\n"
2352 "Duration(in TUs), if specified, will be used to set dwell times.\n");
2355 static int handle_scan_abort(struct nl80211_state
*state
,
2357 int argc
, char **argv
,
2362 COMMAND(scan
, abort
, "",
2363 NL80211_CMD_ABORT_SCAN
, 0, CIB_NETDEV
, handle_scan_abort
,
2364 "Abort ongoing scan");
2366 static int handle_start_sched_scan(struct nl80211_state
*state
,
2368 int argc
, char **argv
, enum id_input id
)
2370 return parse_sched_scan(msg
, &argc
, &argv
);
2373 static int handle_stop_sched_scan(struct nl80211_state
*state
,
2374 struct nl_msg
*msg
, int argc
, char **argv
,
2383 COMMAND(scan
, sched_start
,
2385 NL80211_CMD_START_SCHED_SCAN
, 0, CIB_NETDEV
, handle_start_sched_scan
,
2386 "Start a scheduled scan at the specified interval on the given frequencies\n"
2387 "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2388 "scanning is requested. If matches are specified, only matching results\n"
2389 "will be returned.");
2390 COMMAND(scan
, sched_stop
, "",
2391 NL80211_CMD_STOP_SCHED_SCAN
, 0, CIB_NETDEV
, handle_stop_sched_scan
,
2392 "Stop an ongoing scheduled scan.");