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 static int parse_random_mac_addr(struct nl_msg
*msg
, char *arg
)
74 char *a_addr
, *a_mask
, *sep
;
75 unsigned char addr
[ETH_ALEN
], mask
[ETH_ALEN
];
76 char *addrs
= arg
+ 9;
82 sep
= strchr(addrs
, '/');
90 if (mac_addr_a2n(addr
, a_addr
) || mac_addr_a2n(mask
, a_mask
))
93 NLA_PUT(msg
, NL80211_ATTR_MAC
, ETH_ALEN
, addr
);
94 NLA_PUT(msg
, NL80211_ATTR_MAC_MASK
, ETH_ALEN
, mask
);
101 int parse_sched_scan(struct nl_msg
*msg
, int *argc
, char ***argv
)
103 struct nl_msg
*matchset
= NULL
, *freqs
= NULL
, *ssids
= NULL
;
104 struct nl_msg
*scan_plans
= NULL
;
105 struct nlattr
*match
= NULL
, *plan
= NULL
;
112 } parse_state
= ND_TOPLEVEL
;
114 char *end
, **v
= *argv
;
116 unsigned int freq
, interval
= 0, delay
= 0, iterations
= 0;
117 bool have_matchset
= false, have_freqs
= false, have_ssids
= false;
118 bool have_active
= false, have_passive
= false, have_plans
= false;
121 matchset
= nlmsg_alloc();
127 freqs
= nlmsg_alloc();
133 ssids
= nlmsg_alloc();
139 scan_plans
= nlmsg_alloc();
146 switch (parse_state
) {
148 if (!strcmp(v
[0], "interval")) {
152 goto nla_put_failure
;
155 if (interval
|| have_plans
) {
157 goto nla_put_failure
;
159 interval
= strtoul(v
[0], &end
, 10);
160 if (*end
|| !interval
) {
162 goto nla_put_failure
;
165 NL80211_ATTR_SCHED_SCAN_INTERVAL
,
167 } else if (!strcmp(v
[0], "scan_plans")) {
168 parse_state
= ND_PLANS
;
169 if (have_plans
|| interval
) {
171 goto nla_put_failure
;
176 } else if (!strcmp(v
[0], "delay")) {
180 goto nla_put_failure
;
185 goto nla_put_failure
;
187 delay
= strtoul(v
[0], &end
, 10);
190 goto nla_put_failure
;
193 NL80211_ATTR_SCHED_SCAN_DELAY
,
195 } else if (!strcmp(v
[0], "matches")) {
196 parse_state
= ND_MATCH
;
199 goto nla_put_failure
;
203 } else if (!strcmp(v
[0], "freqs")) {
204 parse_state
= ND_FREQS
;
207 goto nla_put_failure
;
212 } else if (!strcmp(v
[0], "active")) {
213 parse_state
= ND_ACTIVE
;
214 if (have_active
|| have_passive
) {
216 goto nla_put_failure
;
221 } else if (!strcmp(v
[0], "passive")) {
222 if (have_active
|| have_passive
) {
224 goto nla_put_failure
;
228 } else if (!strncmp(v
[0], "randomise", 9) ||
229 !strncmp(v
[0], "randomize", 9)) {
230 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
232 err
= parse_random_mac_addr(msg
, v
[0]);
234 goto nla_put_failure
;
237 /* this element is not for us, so
238 * return to continue parsing.
240 goto nla_put_failure
;
246 if (!strcmp(v
[0], "ssid")) {
250 goto nla_put_failure
;
253 /* TODO: for now we can only have an
254 * SSID in the match, so we can start
255 * the match nest here.
257 match
= nla_nest_start(matchset
, i
);
260 goto nla_put_failure
;
264 NL80211_SCHED_SCAN_MATCH_ATTR_SSID
,
266 nla_nest_end(matchset
, match
);
269 have_matchset
= true;
273 /* other element that cannot be part
274 * of a match indicates the end of the
276 /* need at least one match in the matchset */
279 goto nla_put_failure
;
282 parse_state
= ND_TOPLEVEL
;
287 freq
= strtoul(v
[0], &end
, 10);
291 goto nla_put_failure
;
294 parse_state
= ND_TOPLEVEL
;
296 NLA_PUT_U32(freqs
, i
, freq
);
302 if (!strcmp(v
[0], "ssid")) {
306 goto nla_put_failure
;
310 NL80211_SCHED_SCAN_MATCH_ATTR_SSID
,
317 /* other element that cannot be part
318 * of a match indicates the end of the
320 /* need at least one item in the set */
323 goto nla_put_failure
;
326 parse_state
= ND_TOPLEVEL
;
331 interval
= strtoul(v
[0], &end
, 10);
337 goto nla_put_failure
;
341 iterations
= strtoul(iter
, &end
, 10);
342 if (*end
|| !iterations
) {
344 goto nla_put_failure
;
348 plan
= nla_nest_start(scan_plans
, i
+ 1);
351 goto nla_put_failure
;
354 NLA_PUT_U32(scan_plans
,
355 NL80211_SCHED_SCAN_PLAN_INTERVAL
,
359 NLA_PUT_U32(scan_plans
,
360 NL80211_SCHED_SCAN_PLAN_ITERATIONS
,
363 parse_state
= ND_TOPLEVEL
;
365 nla_nest_end(scan_plans
, plan
);
374 NLA_PUT(ssids
, 1, 0, "");
376 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
378 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
380 nla_put_nested(msg
, NL80211_ATTR_SCHED_SCAN_MATCH
, matchset
);
382 nla_put_nested(msg
, NL80211_ATTR_SCHED_SCAN_PLANS
, scan_plans
);
384 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
388 nla_nest_end(msg
, match
);
390 nlmsg_free(matchset
);
391 nlmsg_free(scan_plans
);
399 static int handle_scan(struct nl80211_state
*state
,
401 int argc
, char **argv
,
404 struct nl_msg
*ssids
= NULL
, *freqs
= NULL
;
418 unsigned int duration
= 0;
419 bool passive
= false, have_ssids
= false, have_freqs
= false;
420 bool duration_mandatory
= false;
421 size_t ies_len
= 0, meshid_len
= 0;
422 unsigned char *ies
= NULL
, *meshid
= NULL
, *tmpies
;
423 unsigned int flags
= 0;
425 ssids
= nlmsg_alloc();
429 freqs
= nlmsg_alloc();
435 for (i
= 0; i
< argc
; i
++) {
438 if (strcmp(argv
[i
], "freq") == 0) {
442 } else if (strcmp(argv
[i
], "ies") == 0) {
445 } else if (strcmp(argv
[i
], "lowpri") == 0) {
446 flags
|= NL80211_SCAN_FLAG_LOW_PRIORITY
;
448 } else if (strcmp(argv
[i
], "flush") == 0) {
449 flags
|= NL80211_SCAN_FLAG_FLUSH
;
451 } else if (strcmp(argv
[i
], "ap-force") == 0) {
452 flags
|= NL80211_SCAN_FLAG_AP
;
454 } else if (strcmp(argv
[i
], "duration-mandatory") == 0) {
455 duration_mandatory
= true;
457 } else if (strncmp(argv
[i
], "randomise", 9) == 0 ||
458 strncmp(argv
[i
], "randomize", 9) == 0) {
459 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
460 err
= parse_random_mac_addr(msg
, argv
[i
]);
462 goto nla_put_failure
;
464 } else if (strcmp(argv
[i
], "ssid") == 0) {
468 } else if (strcmp(argv
[i
], "passive") == 0) {
472 } else if (strcmp(argv
[i
], "meshid") == 0) {
475 } else if (strcmp(argv
[i
], "duration") == 0) {
484 freq
= strtoul(argv
[i
], &eptr
, 10);
485 if (eptr
!= argv
[i
] + strlen(argv
[i
])) {
486 /* failed to parse as number -- maybe a tag? */
491 NLA_PUT_U32(freqs
, i
, freq
);
494 ies
= parse_hex(argv
[i
], &ies_len
);
496 goto nla_put_failure
;
500 NLA_PUT(ssids
, i
, strlen(argv
[i
]), argv
[i
]);
503 meshid_len
= strlen(argv
[i
]);
504 meshid
= (unsigned char *) malloc(meshid_len
+ 2);
506 goto nla_put_failure
;
507 meshid
[0] = 114; /* mesh element id */
508 meshid
[1] = meshid_len
;
509 memcpy(&meshid
[2], argv
[i
], meshid_len
);
514 duration
= strtoul(argv
[i
], &eptr
, 10);
521 tmpies
= (unsigned char *) malloc(ies_len
+ meshid_len
);
525 goto nla_put_failure
;
528 memcpy(tmpies
, ies
, ies_len
);
532 memcpy(&tmpies
[ies_len
], meshid
, meshid_len
);
535 if (nla_put(msg
, NL80211_ATTR_IE
, ies_len
+ meshid_len
, tmpies
) < 0) {
537 goto nla_put_failure
;
543 NLA_PUT(ssids
, 1, 0, "");
545 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
548 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
550 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
552 NLA_PUT_U16(msg
, NL80211_ATTR_MEASUREMENT_DURATION
, duration
);
553 if (duration_mandatory
) {
556 NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY
);
559 goto nla_put_failure
;
570 static void tab_on_first(bool *first
)
578 struct print_ies_data
{
583 static void print_ssid(const uint8_t type
, uint8_t len
, const uint8_t *data
,
584 const struct print_ies_data
*ie_buffer
)
587 print_ssid_escaped(len
, data
);
591 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
592 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
594 static void print_supprates(const uint8_t type
, uint8_t len
,
596 const struct print_ies_data
*ie_buffer
)
602 for (i
= 0; i
< len
; i
++) {
603 int r
= data
[i
] & 0x7f;
605 if (r
== BSS_MEMBERSHIP_SELECTOR_VHT_PHY
&& data
[i
] & 0x80)
607 else if (r
== BSS_MEMBERSHIP_SELECTOR_HT_PHY
&& data
[i
] & 0x80)
610 printf("%d.%d", r
/2, 5*(r
&1));
612 printf("%s ", data
[i
] & 0x80 ? "*" : "");
617 static void print_ds(const uint8_t type
, uint8_t len
, const uint8_t *data
,
618 const struct print_ies_data
*ie_buffer
)
620 printf(" channel %d\n", data
[0]);
623 static const char *country_env_str(char environment
)
625 switch (environment
) {
627 return "Indoor only";
629 return "Outdoor only";
631 return "Indoor/Outdoor";
637 static void print_country(const uint8_t type
, uint8_t len
, const uint8_t *data
,
638 const struct print_ies_data
*ie_buffer
)
640 printf(" %.*s", 2, data
);
642 printf("\tEnvironment: %s\n", country_env_str(data
[2]));
648 printf("\t\tNo country IE triplets present\n");
654 union ieee80211_country_ie_triplet
*triplet
= (void *) data
;
656 if (triplet
->ext
.reg_extension_id
>= IEEE80211_COUNTRY_EXTENSION_ID
) {
657 printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
658 triplet
->ext
.reg_extension_id
,
659 triplet
->ext
.reg_class
,
660 triplet
->ext
.coverage_class
,
661 triplet
->ext
.coverage_class
* 450);
669 if (triplet
->chans
.first_channel
<= 14)
670 end_channel
= triplet
->chans
.first_channel
+ (triplet
->chans
.num_channels
- 1);
672 end_channel
= triplet
->chans
.first_channel
+ (4 * (triplet
->chans
.num_channels
- 1));
674 printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet
->chans
.first_channel
, end_channel
, triplet
->chans
.max_power
);
683 static void print_powerconstraint(const uint8_t type
, uint8_t len
,
685 const struct print_ies_data
*ie_buffer
)
687 printf(" %d dB\n", data
[0]);
690 static void print_tpcreport(const uint8_t type
, uint8_t len
,
692 const struct print_ies_data
*ie_buffer
)
694 printf(" TX power: %d dBm\n", data
[0]);
695 /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
698 static void print_erp(const uint8_t type
, uint8_t len
, const uint8_t *data
,
699 const struct print_ies_data
*ie_buffer
)
702 printf(" <no flags>");
704 printf(" NonERP_Present");
706 printf(" Use_Protection");
708 printf(" Barker_Preamble_Mode");
712 static void print_cipher(const uint8_t *data
)
714 if (memcmp(data
, ms_oui
, 3) == 0) {
717 printf("Use group cipher suite");
732 printf("%.02x-%.02x-%.02x:%d",
733 data
[0], data
[1] ,data
[2], data
[3]);
736 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
739 printf("Use group cipher suite");
754 printf("AES-128-CMAC");
763 printf("%.02x-%.02x-%.02x:%d",
764 data
[0], data
[1] ,data
[2], data
[3]);
768 printf("%.02x-%.02x-%.02x:%d",
769 data
[0], data
[1] ,data
[2], data
[3]);
772 static void print_auth(const uint8_t *data
)
774 if (memcmp(data
, ms_oui
, 3) == 0) {
777 printf("IEEE 802.1X");
783 printf("%.02x-%.02x-%.02x:%d",
784 data
[0], data
[1] ,data
[2], data
[3]);
787 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
790 printf("IEEE 802.1X");
796 printf("FT/IEEE 802.1X");
802 printf("IEEE 802.1X/SHA-256");
805 printf("PSK/SHA-256");
811 printf("%.02x-%.02x-%.02x:%d",
812 data
[0], data
[1] ,data
[2], data
[3]);
815 } else if (memcmp(data
, wfa_oui
, 3) == 0) {
821 printf("%.02x-%.02x-%.02x:%d",
822 data
[0], data
[1] ,data
[2], data
[3]);
826 printf("%.02x-%.02x-%.02x:%d",
827 data
[0], data
[1] ,data
[2], data
[3]);
830 static void _print_rsn_ie(const char *defcipher
, const char *defauth
,
831 uint8_t len
, const uint8_t *data
, int is_osen
)
839 version
= data
[0] + (data
[1] << 8);
840 tab_on_first(&first
);
841 printf("\t * Version: %d\n", version
);
848 tab_on_first(&first
);
849 printf("\t * Group cipher: %s\n", defcipher
);
850 printf("\t * Pairwise ciphers: %s\n", defcipher
);
854 tab_on_first(&first
);
855 printf("\t * Group cipher: ");
863 tab_on_first(&first
);
864 printf("\t * Pairwise ciphers: %s\n", defcipher
);
868 count
= data
[0] | (data
[1] << 8);
869 if (2 + (count
* 4) > len
)
872 tab_on_first(&first
);
873 printf("\t * Pairwise ciphers:");
874 for (i
= 0; i
< count
; i
++) {
876 print_cipher(data
+ 2 + (i
* 4));
880 data
+= 2 + (count
* 4);
881 len
-= 2 + (count
* 4);
884 tab_on_first(&first
);
885 printf("\t * Authentication suites: %s\n", defauth
);
889 count
= data
[0] | (data
[1] << 8);
890 if (2 + (count
* 4) > len
)
893 tab_on_first(&first
);
894 printf("\t * Authentication suites:");
895 for (i
= 0; i
< count
; i
++) {
897 print_auth(data
+ 2 + (i
* 4));
901 data
+= 2 + (count
* 4);
902 len
-= 2 + (count
* 4);
905 capa
= data
[0] | (data
[1] << 8);
906 tab_on_first(&first
);
907 printf("\t * Capabilities:");
911 printf(" NoPairwise");
912 switch ((capa
& 0x000c) >> 2) {
914 printf(" 1-PTKSA-RC");
917 printf(" 2-PTKSA-RC");
920 printf(" 4-PTKSA-RC");
923 printf(" 16-PTKSA-RC");
926 switch ((capa
& 0x0030) >> 4) {
928 printf(" 1-GTKSA-RC");
931 printf(" 2-GTKSA-RC");
934 printf(" 4-GTKSA-RC");
937 printf(" 16-GTKSA-RC");
941 printf(" MFP-required");
943 printf(" MFP-capable");
945 printf(" Peerkey-enabled");
947 printf(" SPP-AMSDU-capable");
949 printf(" SPP-AMSDU-required");
950 printf(" (0x%.4x)\n", capa
);
956 int pmkid_count
= data
[0] | (data
[1] << 8);
958 if (len
>= 2 + 16 * pmkid_count
) {
959 tab_on_first(&first
);
960 printf("\t * %d PMKIDs\n", pmkid_count
);
961 /* not printing PMKID values */
962 data
+= 2 + 16 * pmkid_count
;
963 len
-= 2 + 16 * pmkid_count
;
969 tab_on_first(&first
);
970 printf("\t * Group mgmt cipher suite: ");
979 printf("\t\t * bogus tail data (%d):", len
);
981 printf(" %.2x", *data
);
989 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
990 uint8_t len
, const uint8_t *data
)
992 _print_rsn_ie(defcipher
, defauth
, len
, data
, 0);
995 static void print_osen_ie(const char *defcipher
, const char *defauth
,
996 uint8_t len
, const uint8_t *data
)
999 _print_rsn_ie(defcipher
, defauth
, len
, data
, 1);
1002 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1003 const struct print_ies_data
*ie_buffer
)
1005 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
1008 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1009 const struct print_ies_data
*ie_buffer
)
1012 print_ht_capability(data
[0] | (data
[1] << 8));
1013 print_ampdu_length(data
[2] & 3);
1014 print_ampdu_spacing((data
[2] >> 2) & 7);
1015 print_ht_mcs(data
+ 3);
1018 static const char* ntype_11u(uint8_t t
)
1021 case 0: return "Private";
1022 case 1: return "Private with Guest";
1023 case 2: return "Chargeable Public";
1024 case 3: return "Free Public";
1025 case 4: return "Personal Device";
1026 case 5: return "Emergency Services Only";
1027 case 14: return "Test or Experimental";
1028 case 15: return "Wildcard";
1029 default: return "Reserved";
1033 static const char* vgroup_11u(uint8_t t
)
1036 case 0: return "Unspecified";
1037 case 1: return "Assembly";
1038 case 2: return "Business";
1039 case 3: return "Educational";
1040 case 4: return "Factory and Industrial";
1041 case 5: return "Institutional";
1042 case 6: return "Mercantile";
1043 case 7: return "Residential";
1044 case 8: return "Storage";
1045 case 9: return "Utility and Miscellaneous";
1046 case 10: return "Vehicular";
1047 case 11: return "Outdoor";
1048 default: return "Reserved";
1052 static void print_interworking(const uint8_t type
, uint8_t len
,
1053 const uint8_t *data
,
1054 const struct print_ies_data
*ie_buffer
)
1056 /* See Section 7.3.2.92 in the 802.11u spec. */
1059 uint8_t ano
= data
[0];
1060 printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano
));
1061 printf("\t\t\tNetwork Type: %i (%s)\n",
1062 (int)(ano
& 0xf), ntype_11u(ano
& 0xf));
1064 printf("\t\t\tInternet\n");
1066 printf("\t\t\tASRA\n");
1068 printf("\t\t\tESR\n");
1070 printf("\t\t\tUESA\n");
1072 if ((len
== 3) || (len
== 9)) {
1073 printf("\t\tVenue Group: %i (%s)\n",
1074 (int)(data
[1]), vgroup_11u(data
[1]));
1075 printf("\t\tVenue Type: %i\n", (int)(data
[2]));
1078 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
1079 data
[3], data
[4], data
[5], data
[6], data
[7], data
[8]);
1081 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
1082 data
[1], data
[2], data
[3], data
[4], data
[5], data
[6]);
1085 static void print_11u_advert(const uint8_t type
, uint8_t len
,
1086 const uint8_t *data
,
1087 const struct print_ies_data
*ie_buffer
)
1089 /* See Section 7.3.2.93 in the 802.11u spec. */
1090 /* TODO: This code below does not decode private protocol IDs */
1093 while (idx
< (len
- 1)) {
1094 uint8_t qri
= data
[idx
];
1095 uint8_t proto_id
= data
[idx
+ 1];
1096 printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri
));
1097 printf("\t\t\tQuery Response Length Limit: %i\n",
1100 printf("\t\t\tPAME-BI\n");
1103 printf("\t\t\tANQP\n"); break;
1105 printf("\t\t\tMIH Information Service\n"); break;
1107 printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
1109 printf("\t\t\tEmergency Alert System (EAS)\n"); break;
1111 printf("\t\t\tVendor Specific\n"); break;
1113 printf("\t\t\tReserved: %i\n", proto_id
); break;
1119 static void print_11u_rcon(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1120 const struct print_ies_data
*ie_buffer
)
1122 /* See Section 7.3.2.96 in the 802.11u spec. */
1124 int ln0
= data
[1] & 0xf;
1125 int ln1
= ((data
[1] & 0xf0) >> 4);
1130 ln2
= len
- 2 - ln0
- ln1
;
1132 printf("\t\tANQP OIs: %i\n", data
[0]);
1135 printf("\t\tOI 1: ");
1136 if (2 + ln0
> len
) {
1137 printf("Invalid IE length.\n");
1139 for (idx
= 0; idx
< ln0
; idx
++) {
1140 printf("%02hx", data
[2 + idx
]);
1147 printf("\t\tOI 2: ");
1148 if (2 + ln0
+ ln1
> len
) {
1149 printf("Invalid IE length.\n");
1151 for (idx
= 0; idx
< ln1
; idx
++) {
1152 printf("%02hx", data
[2 + ln0
+ idx
]);
1159 printf("\t\tOI 3: ");
1160 if (2 + ln0
+ ln1
+ ln2
> len
) {
1161 printf("Invalid IE length.\n");
1163 for (idx
= 0; idx
< ln2
; idx
++) {
1164 printf("%02hx", data
[2 + ln0
+ ln1
+ idx
]);
1171 static const char *ht_secondary_offset
[4] = {
1178 static void print_ht_op(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1179 const struct print_ies_data
*ie_buffer
)
1181 static const char *protection
[4] = {
1187 static const char *sta_chan_width
[2] = {
1193 printf("\t\t * primary channel: %d\n", data
[0]);
1194 printf("\t\t * secondary channel offset: %s\n",
1195 ht_secondary_offset
[data
[1] & 0x3]);
1196 printf("\t\t * STA channel width: %s\n", sta_chan_width
[(data
[1] & 0x4)>>2]);
1197 printf("\t\t * RIFS: %d\n", (data
[1] & 0x8)>>3);
1198 printf("\t\t * HT protection: %s\n", protection
[data
[2] & 0x3]);
1199 printf("\t\t * non-GF present: %d\n", (data
[2] & 0x4) >> 2);
1200 printf("\t\t * OBSS non-GF present: %d\n", (data
[2] & 0x10) >> 4);
1201 printf("\t\t * dual beacon: %d\n", (data
[4] & 0x40) >> 6);
1202 printf("\t\t * dual CTS protection: %d\n", (data
[4] & 0x80) >> 7);
1203 printf("\t\t * STBC beacon: %d\n", data
[5] & 0x1);
1204 printf("\t\t * L-SIG TXOP Prot: %d\n", (data
[5] & 0x2) >> 1);
1205 printf("\t\t * PCO active: %d\n", (data
[5] & 0x4) >> 2);
1206 printf("\t\t * PCO phase: %d\n", (data
[5] & 0x8) >> 3);
1209 static void print_capabilities(const uint8_t type
, uint8_t len
,
1210 const uint8_t *data
,
1211 const struct print_ies_data
*ie_buffer
)
1213 int i
, base
, bit
, si_duration
= 0, max_amsdu
= 0;
1214 bool s_psmp_support
= false, is_vht_cap
= false;
1215 unsigned char *ie
= ie_buffer
->ie
;
1216 int ielen
= ie_buffer
->ielen
;
1218 while (ielen
>= 2 && ielen
>= ie
[1]) {
1227 for (i
= 0; i
< len
; i
++) {
1230 for (bit
= 0; bit
< 8; bit
++) {
1231 if (!(data
[i
] & (1 << bit
)))
1236 #define CAPA(bit, name) case bit: printf(" " name); break
1238 /* if the capability 'cap' exists add 'val' to 'sum'
1239 * otherwise print 'Reserved' */
1240 #define ADD_BIT_VAL(bit, cap, sum, val) case (bit): do { \
1242 printf(" Reserved"); \
1249 switch (bit
+ base
) {
1250 CAPA(0, "HT Information Exchange Supported");
1251 CAPA(1, "reserved (On-demand Beacon)");
1252 CAPA(2, "Extended Channel Switching");
1253 CAPA(3, "reserved (Wave Indication)");
1254 CAPA(4, "PSMP Capability");
1255 CAPA(5, "reserved (Service Interval Granularity)");
1258 s_psmp_support
= true;
1259 printf(" S-PSMP Capability");
1263 CAPA(8, "Diagnostics");
1264 CAPA(9, "Multicast Diagnostics");
1265 CAPA(10, "Location Tracking");
1267 CAPA(12, "Proxy ARP Service");
1268 CAPA(13, "Collocated Interference Reporting");
1269 CAPA(14, "Civic Location");
1270 CAPA(15, "Geospatial Location");
1272 CAPA(17, "WNM-Sleep Mode");
1273 CAPA(18, "TIM Broadcast");
1274 CAPA(19, "BSS Transition");
1275 CAPA(20, "QoS Traffic Capability");
1276 CAPA(21, "AC Station Count");
1277 CAPA(22, "Multiple BSSID");
1278 CAPA(23, "Timing Measurement");
1279 CAPA(24, "Channel Usage");
1280 CAPA(25, "SSID List");
1282 CAPA(27, "UTC TSF Offset");
1283 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1284 CAPA(29, "TDLS Peer PSM Support");
1285 CAPA(30, "TDLS channel switching");
1286 CAPA(31, "Interworking");
1287 CAPA(32, "QoS Map");
1289 CAPA(34, "SSPN Interface");
1290 CAPA(35, "Reserved");
1291 CAPA(36, "MSGCF Capability");
1292 CAPA(37, "TDLS Support");
1293 CAPA(38, "TDLS Prohibited");
1294 CAPA(39, "TDLS Channel Switching Prohibited");
1295 CAPA(40, "Reject Unadmitted Frame");
1297 ADD_BIT_VAL(41, s_psmp_support
, si_duration
, 1);
1298 ADD_BIT_VAL(42, s_psmp_support
, si_duration
, 2);
1299 ADD_BIT_VAL(43, s_psmp_support
, si_duration
, 4);
1301 CAPA(44, "Identifier Location");
1302 CAPA(45, "U-APSD Coexistence");
1303 CAPA(46, "WNM-Notification");
1304 CAPA(47, "Reserved");
1305 CAPA(48, "UTF-8 SSID");
1306 CAPA(49, "QMFActivated");
1307 CAPA(50, "QMFReconfigurationActivated");
1308 CAPA(51, "Robust AV Streaming");
1309 CAPA(52, "Advanced GCR");
1310 CAPA(53, "Mesh GCR");
1312 CAPA(55, "QLoad Report");
1313 CAPA(56, "Alternate EDCA");
1314 CAPA(57, "Unprotected TXOP Negotiation");
1315 CAPA(58, "Protected TXOP egotiation");
1316 CAPA(59, "Reserved");
1317 CAPA(60, "Protected QLoad Report");
1318 CAPA(61, "TDLS Wider Bandwidth");
1319 CAPA(62, "Operating Mode Notification");
1321 ADD_BIT_VAL(63, is_vht_cap
, max_amsdu
, 1);
1322 ADD_BIT_VAL(64, is_vht_cap
, max_amsdu
, 2);
1324 CAPA(65, "Channel Schedule Management");
1325 CAPA(66, "Geodatabase Inband Enabling Signal");
1326 CAPA(67, "Network Channel Control");
1327 CAPA(68, "White Space Map");
1328 CAPA(69, "Channel Availability Query");
1329 CAPA(70, "FTM Responder");
1330 CAPA(71, "FTM Initiator");
1331 CAPA(72, "Reserved");
1332 CAPA(73, "Extended Spectrum Management Capable");
1333 CAPA(74, "Reserved");
1344 printf("\n\t\t * Service Interval Granularity is %d ms",
1345 (si_duration
+ 1) * 5);
1348 printf("\n\t\t * Max Number Of MSDUs In A-MSDU is ");
1349 switch (max_amsdu
) {
1351 printf("unlimited");
1370 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1371 const struct print_ies_data
*ie_buffer
)
1373 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1375 data
[0], data
[1], data
[2], data
[3]);
1377 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
1381 static void print_ibssatim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1382 const struct print_ies_data
*ie_buffer
)
1384 printf(" %d TUs", (data
[1] << 8) + data
[0]);
1387 static void print_vht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1388 const struct print_ies_data
*ie_buffer
)
1391 print_vht_info(data
[0] | (data
[1] << 8) |
1392 (data
[2] << 16) | (data
[3] << 24),
1396 static void print_vht_oper(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1397 const struct print_ies_data
*ie_buffer
)
1399 const char *chandwidths
[] = {
1400 [0] = "20 or 40 MHz",
1407 printf("\t\t * channel width: %d (%s)\n", data
[0],
1408 data
[0] < ARRAY_SIZE(chandwidths
) ? chandwidths
[data
[0]] : "unknown");
1409 printf("\t\t * center freq segment 1: %d\n", data
[1]);
1410 printf("\t\t * center freq segment 2: %d\n", data
[2]);
1411 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data
[4], data
[3]);
1414 static void print_obss_scan_params(const uint8_t type
, uint8_t len
,
1415 const uint8_t *data
,
1416 const struct print_ies_data
*ie_buffer
)
1419 printf("\t\t * passive dwell: %d TUs\n", (data
[1] << 8) | data
[0]);
1420 printf("\t\t * active dwell: %d TUs\n", (data
[3] << 8) | data
[2]);
1421 printf("\t\t * channel width trigger scan interval: %d s\n", (data
[5] << 8) | data
[4]);
1422 printf("\t\t * scan passive total per channel: %d TUs\n", (data
[7] << 8) | data
[6]);
1423 printf("\t\t * scan active total per channel: %d TUs\n", (data
[9] << 8) | data
[8]);
1424 printf("\t\t * BSS width channel transition delay factor: %d\n", (data
[11] << 8) | data
[10]);
1425 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1426 ((data
[13] << 8) | data
[12]) / 100, ((data
[13] << 8) | data
[12]) % 100);
1429 static void print_secchan_offs(const uint8_t type
, uint8_t len
,
1430 const uint8_t *data
,
1431 const struct print_ies_data
*ie_buffer
)
1433 if (data
[0] < ARRAY_SIZE(ht_secondary_offset
))
1434 printf(" %s (%d)\n", ht_secondary_offset
[data
[0]], data
[0]);
1436 printf(" %d\n", data
[0]);
1439 static void print_bss_load(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1440 const struct print_ies_data
*ie_buffer
)
1443 printf("\t\t * station count: %d\n", (data
[1] << 8) | data
[0]);
1444 printf("\t\t * channel utilisation: %d/255\n", data
[2]);
1445 printf("\t\t * available admission capacity: %d [*32us]\n", (data
[4] << 8) | data
[3]);
1448 static void print_mesh_conf(const uint8_t type
, uint8_t len
,
1449 const uint8_t *data
,
1450 const struct print_ies_data
*ie_buffer
)
1453 printf("\t\t * Active Path Selection Protocol ID: %d\n", data
[0]);
1454 printf("\t\t * Active Path Selection Metric ID: %d\n", data
[1]);
1455 printf("\t\t * Congestion Control Mode ID: %d\n", data
[2]);
1456 printf("\t\t * Synchronization Method ID: %d\n", data
[3]);
1457 printf("\t\t * Authentication Protocol ID: %d\n", data
[4]);
1458 printf("\t\t * Mesh Formation Info:\n");
1459 printf("\t\t\t Number of Peerings: %d\n", (data
[5] & 0x7E) >> 1);
1461 printf("\t\t\t Connected to Mesh Gate\n");
1463 printf("\t\t\t Connected to AS\n");
1464 printf("\t\t * Mesh Capability\n");
1466 printf("\t\t\t Accepting Additional Mesh Peerings\n");
1468 printf("\t\t\t MCCA Supported\n");
1470 printf("\t\t\t MCCA Enabled\n");
1472 printf("\t\t\t Forwarding\n");
1474 printf("\t\t\t MBCA Supported\n");
1476 printf("\t\t\t TBTT Adjusting\n");
1478 printf("\t\t\t Mesh Power Save Level\n");
1483 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1484 const struct print_ies_data
*ie_buffer
);
1485 uint8_t minlen
, maxlen
;
1489 static void print_ie(const struct ie_print
*p
, const uint8_t type
, uint8_t len
,
1490 const uint8_t *data
,
1491 const struct print_ies_data
*ie_buffer
)
1498 printf("\t%s:", p
->name
);
1499 if (len
< p
->minlen
|| len
> p
->maxlen
) {
1501 printf(" <invalid: %d bytes:", len
);
1502 for (i
= 0; i
< len
; i
++)
1503 printf(" %.02x", data
[i
]);
1506 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
1508 printf(" <invalid: no data>\n");
1512 p
->print(type
, len
, data
, ie_buffer
);
1515 #define PRINT_IGN { \
1522 static const struct ie_print ieprinters
[] = {
1523 [0] = { "SSID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1524 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1525 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
1526 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
1527 [6] = { "IBSS ATIM window", print_ibssatim
, 2, 2, BIT(PRINT_SCAN
), },
1528 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
1529 [11] = { "BSS Load", print_bss_load
, 5, 5, BIT(PRINT_SCAN
), },
1530 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
1531 [35] = { "TPC report", print_tpcreport
, 2, 2, BIT(PRINT_SCAN
), },
1532 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1533 [45] = { "HT capabilities", print_ht_capa
, 26, 26, BIT(PRINT_SCAN
), },
1534 [47] = { "ERP D4.0", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1535 [74] = { "Overlapping BSS scan params", print_obss_scan_params
, 14, 255, BIT(PRINT_SCAN
), },
1536 [61] = { "HT operation", print_ht_op
, 22, 22, BIT(PRINT_SCAN
), },
1537 [62] = { "Secondary Channel Offset", print_secchan_offs
, 1, 1, BIT(PRINT_SCAN
), },
1538 [191] = { "VHT capabilities", print_vht_capa
, 12, 255, BIT(PRINT_SCAN
), },
1539 [192] = { "VHT operation", print_vht_oper
, 5, 255, BIT(PRINT_SCAN
), },
1540 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
1541 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1542 [113] = { "MESH Configuration", print_mesh_conf
, 7, 7, BIT(PRINT_SCAN
), },
1543 [114] = { "MESH ID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1544 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
1545 [107] = { "802.11u Interworking", print_interworking
, 0, 255, BIT(PRINT_SCAN
), },
1546 [108] = { "802.11u Advertisement", print_11u_advert
, 0, 255, BIT(PRINT_SCAN
), },
1547 [111] = { "802.11u Roaming Consortium", print_11u_rcon
, 0, 255, BIT(PRINT_SCAN
), },
1550 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1551 const struct print_ies_data
*ie_buffer
)
1553 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
1556 static void print_wifi_osen(const uint8_t type
, uint8_t len
,
1557 const uint8_t *data
,
1558 const struct print_ies_data
*ie_buffer
)
1560 print_osen_ie("OSEN", "OSEN", len
, data
);
1563 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
1566 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
1572 printf("Parameter: not version 1: ");
1576 printf("\t * Parameter version 1");
1581 printf("\n\t\t * u-APSD");
1585 for (i
= 0; i
< 4; i
++) {
1586 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
1589 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
1590 (1 << (data
[1] >> 4)) - 1);
1591 printf(", AIFSN %d", data
[0] & 0xf);
1592 if (data
[2] | data
[3])
1593 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
1601 printf("invalid: ");
1605 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1606 const struct print_ies_data
*ie_buffer
)
1612 printf(" information:");
1615 if (print_wifi_wmm_param(data
+ 1, len
- 1))
1619 printf(" type %d:", data
[0]);
1623 for(i
= 1; i
< len
; i
++)
1624 printf(" %.02x", data
[i
]);
1628 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
1632 return "Default (PIN)";
1634 return "User-specified";
1636 return "Machine-specified";
1640 return "PushButton";
1642 return "Registrar-specified";
1648 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1649 const struct print_ies_data
*ie_buffer
)
1652 __u16 subtype
, sublen
;
1655 subtype
= (data
[0] << 8) + data
[1];
1656 sublen
= (data
[2] << 8) + data
[3];
1662 tab_on_first(&first
);
1663 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
1666 tab_on_first(&first
);
1667 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
1671 tab_on_first(&first
);
1673 printf("\t * Device Password ID: (invalid "
1674 "length %d)\n", sublen
);
1677 id
= data
[4] << 8 | data
[5];
1678 printf("\t * Device Password ID: %u (%s)\n",
1679 id
, wifi_wps_dev_passwd_id(id
));
1683 tab_on_first(&first
);
1684 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
1687 tab_on_first(&first
);
1688 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
1691 tab_on_first(&first
);
1692 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
1696 tab_on_first(&first
);
1697 printf("\t * Response Type: %d%s\n",
1698 val
, val
== 3 ? " (AP)" : "");
1703 tab_on_first(&first
);
1704 printf("\t * RF Bands: 0x%x\n", val
);
1709 tab_on_first(&first
);
1710 printf("\t * Selected Registrar: 0x%x\n", val
);
1714 tab_on_first(&first
);
1715 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
1719 tab_on_first(&first
);
1720 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1722 val
== 1 ? " (Unconfigured)" : "",
1723 val
== 2 ? " (Configured)" : "");
1727 tab_on_first(&first
);
1728 printf("\t * UUID: ");
1730 printf("(invalid, length=%d)\n", sublen
);
1733 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1734 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1735 data
[4], data
[5], data
[6], data
[7],
1736 data
[8], data
[9], data
[10], data
[11],
1737 data
[12], data
[13], data
[14], data
[15],
1738 data
[16], data
[17], data
[18], data
[19]);
1741 tab_on_first(&first
);
1743 printf("\t * Primary Device Type: (invalid "
1744 "length %d)\n", sublen
);
1747 printf("\t * Primary Device Type: "
1748 "%u-%02x%02x%02x%02x-%u\n",
1749 data
[4] << 8 | data
[5],
1750 data
[6], data
[7], data
[8], data
[9],
1751 data
[10] << 8 | data
[11]);
1756 tab_on_first(&first
);
1757 printf("\t * AP setup locked: 0x%.2x\n", val
);
1762 __u16 meth
= (data
[4] << 8) + data
[5];
1764 tab_on_first(&first
);
1765 printf("\t * %sConfig methods:",
1766 subtype
== 0x1053 ? "Selected Registrar ": "");
1767 #define T(bit, name) do { \
1768 if (meth & (1<<bit)) { \
1788 const __u8
*subdata
= data
+ 4;
1789 __u16 tmplen
= sublen
;
1791 tab_on_first(&first
);
1792 printf("\t * Unknown TLV (%#.4x, %d bytes):",
1795 printf(" %.2x", *subdata
);
1809 printf("\t\t * bogus tail data (%d):", len
);
1811 printf(" %.2x", *data
);
1819 static const struct ie_print wifiprinters
[] = {
1820 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
1821 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
1822 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
1825 static inline void print_p2p(const uint8_t type
, uint8_t len
,
1826 const uint8_t *data
,
1827 const struct print_ies_data
*ie_buffer
)
1835 sublen
= (data
[2] << 8) + data
[1];
1837 if (sublen
> len
- 3)
1841 case 0x02: /* capability */
1842 tab_on_first(&first
);
1844 printf("\t * malformed capability\n");
1847 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
1850 case 0x0d: /* device info */
1851 if (sublen
< 6 + 2 + 8 + 1) {
1852 printf("\t * malformed device info\n");
1855 /* fall through for now */
1856 case 0x00: /* status */
1857 case 0x01: /* minor reason */
1858 case 0x03: /* device ID */
1859 case 0x04: /* GO intent */
1860 case 0x05: /* configuration timeout */
1861 case 0x06: /* listen channel */
1862 case 0x07: /* group BSSID */
1863 case 0x08: /* ext listen timing */
1864 case 0x09: /* intended interface address */
1865 case 0x0a: /* manageability */
1866 case 0x0b: /* channel list */
1867 case 0x0c: /* NoA */
1868 case 0x0e: /* group info */
1869 case 0x0f: /* group ID */
1870 case 0x10: /* interface */
1871 case 0x11: /* operating channel */
1872 case 0x12: /* invitation flags */
1873 case 0xdd: /* vendor specific */
1875 const __u8
*subdata
= data
+ 4;
1876 __u16 tmplen
= sublen
;
1878 tab_on_first(&first
);
1879 printf("\t * Unknown TLV (%#.2x, %d bytes):",
1882 printf(" %.2x", *subdata
);
1896 tab_on_first(&first
);
1897 printf("\t * bogus tail data (%d):", len
);
1899 printf(" %.2x", *data
);
1907 static inline void print_hs20_ind(const uint8_t type
, uint8_t len
,
1908 const uint8_t *data
,
1909 const struct print_ies_data
*ie_buffer
)
1911 /* I can't find the spec for this...just going off what wireshark uses. */
1914 printf("\t\tDGAF: %i\n", (int)(data
[0] & 0x1));
1916 printf("\t\tUnexpected length: %i\n", len
);
1919 static const struct ie_print wfa_printers
[] = {
1920 [9] = { "P2P", print_p2p
, 2, 255, BIT(PRINT_SCAN
), },
1921 [16] = { "HotSpot 2.0 Indication", print_hs20_ind
, 1, 255, BIT(PRINT_SCAN
), },
1922 [18] = { "HotSpot 2.0 OSEN", print_wifi_osen
, 1, 255, BIT(PRINT_SCAN
), },
1925 static void print_vendor(unsigned char len
, unsigned char *data
,
1926 bool unknown
, enum print_ie_type ptype
)
1931 printf("\tVendor specific: <too short> data:");
1932 for(i
= 0; i
< len
; i
++)
1933 printf(" %.02x", data
[i
]);
1938 if (len
>= 4 && memcmp(data
, ms_oui
, 3) == 0) {
1939 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
1940 wifiprinters
[data
[3]].name
&&
1941 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
1942 print_ie(&wifiprinters
[data
[3]],
1943 data
[3], len
- 4, data
+ 4, 0);
1948 printf("\tMS/WiFi %#.2x, data:", data
[3]);
1949 for(i
= 0; i
< len
- 4; i
++)
1950 printf(" %.02x", data
[i
+ 4]);
1955 if (len
>= 4 && memcmp(data
, wfa_oui
, 3) == 0) {
1956 if (data
[3] < ARRAY_SIZE(wfa_printers
) &&
1957 wfa_printers
[data
[3]].name
&&
1958 wfa_printers
[data
[3]].flags
& BIT(ptype
)) {
1959 print_ie(&wfa_printers
[data
[3]],
1960 data
[3], len
- 4, data
+ 4, 0);
1965 printf("\tWFA %#.2x, data:", data
[3]);
1966 for(i
= 0; i
< len
- 4; i
++)
1967 printf(" %.02x", data
[i
+ 4]);
1975 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
1976 data
[0], data
[1], data
[2]);
1977 for (i
= 3; i
< len
; i
++)
1978 printf(" %.2x", data
[i
]);
1982 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
1983 enum print_ie_type ptype
)
1985 struct print_ies_data ie_buffer
= {
1989 while (ielen
>= 2 && ielen
>= ie
[1]) {
1990 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
1991 ieprinters
[ie
[0]].name
&&
1992 ieprinters
[ie
[0]].flags
& BIT(ptype
)) {
1993 print_ie(&ieprinters
[ie
[0]],
1994 ie
[0], ie
[1], ie
+ 2, &ie_buffer
);
1995 } else if (ie
[0] == 221 /* vendor */) {
1996 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
1997 } else if (unknown
) {
2000 printf("\tUnknown IE (%d):", ie
[0]);
2001 for (i
=0; i
<ie
[1]; i
++)
2002 printf(" %.2x", ie
[2+i
]);
2010 static void print_capa_dmg(__u16 capa
)
2012 switch (capa
& WLAN_CAPABILITY_DMG_TYPE_MASK
) {
2013 case WLAN_CAPABILITY_DMG_TYPE_AP
:
2016 case WLAN_CAPABILITY_DMG_TYPE_PBSS
:
2019 case WLAN_CAPABILITY_DMG_TYPE_IBSS
:
2020 printf(" DMG_IBSS");
2024 if (capa
& WLAN_CAPABILITY_DMG_CBAP_ONLY
)
2025 printf(" CBAP_Only");
2026 if (capa
& WLAN_CAPABILITY_DMG_CBAP_SOURCE
)
2027 printf(" CBAP_Src");
2028 if (capa
& WLAN_CAPABILITY_DMG_PRIVACY
)
2030 if (capa
& WLAN_CAPABILITY_DMG_ECPAC
)
2032 if (capa
& WLAN_CAPABILITY_DMG_SPECTRUM_MGMT
)
2033 printf(" SpectrumMgmt");
2034 if (capa
& WLAN_CAPABILITY_DMG_RADIO_MEASURE
)
2035 printf(" RadioMeasure");
2038 static void print_capa_non_dmg(__u16 capa
)
2040 if (capa
& WLAN_CAPABILITY_ESS
)
2042 if (capa
& WLAN_CAPABILITY_IBSS
)
2044 if (capa
& WLAN_CAPABILITY_CF_POLLABLE
)
2045 printf(" CfPollable");
2046 if (capa
& WLAN_CAPABILITY_CF_POLL_REQUEST
)
2047 printf(" CfPollReq");
2048 if (capa
& WLAN_CAPABILITY_PRIVACY
)
2050 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
2051 printf(" ShortPreamble");
2052 if (capa
& WLAN_CAPABILITY_PBCC
)
2054 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
2055 printf(" ChannelAgility");
2056 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
2057 printf(" SpectrumMgmt");
2058 if (capa
& WLAN_CAPABILITY_QOS
)
2060 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
2061 printf(" ShortSlotTime");
2062 if (capa
& WLAN_CAPABILITY_APSD
)
2064 if (capa
& WLAN_CAPABILITY_RADIO_MEASURE
)
2065 printf(" RadioMeasure");
2066 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
2067 printf(" DSSS-OFDM");
2068 if (capa
& WLAN_CAPABILITY_DEL_BACK
)
2069 printf(" DelayedBACK");
2070 if (capa
& WLAN_CAPABILITY_IMM_BACK
)
2071 printf(" ImmediateBACK");
2074 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
2076 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
2077 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
2078 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
2079 char mac_addr
[20], dev
[20];
2080 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
2081 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
2082 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
2083 [NL80211_BSS_BSSID
] = { },
2084 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
2085 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
2086 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
2087 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
2088 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
2089 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
2090 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
2091 [NL80211_BSS_BEACON_IES
] = { },
2093 struct scan_params
*params
= arg
;
2094 int show
= params
->show_both_ie_sets
? 2 : 1;
2095 bool is_dmg
= false;
2097 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
2098 genlmsg_attrlen(gnlh
, 0), NULL
);
2100 if (!tb
[NL80211_ATTR_BSS
]) {
2101 fprintf(stderr
, "bss info missing!\n");
2104 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
2105 tb
[NL80211_ATTR_BSS
],
2107 fprintf(stderr
, "failed to parse nested attributes!\n");
2111 if (!bss
[NL80211_BSS_BSSID
])
2114 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
2115 printf("BSS %s", mac_addr
);
2116 if (tb
[NL80211_ATTR_IFINDEX
]) {
2117 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
2118 printf("(on %s)", dev
);
2121 if (bss
[NL80211_BSS_STATUS
]) {
2122 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
2123 case NL80211_BSS_STATUS_AUTHENTICATED
:
2124 printf(" -- authenticated");
2126 case NL80211_BSS_STATUS_ASSOCIATED
:
2127 printf(" -- associated");
2129 case NL80211_BSS_STATUS_IBSS_JOINED
:
2130 printf(" -- joined");
2133 printf(" -- unknown status: %d",
2134 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
2140 if (bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]) {
2141 unsigned long long bt
;
2142 bt
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]);
2143 printf("\tlast seen: %llu.%.3llus [boottime]\n", bt
/1000000000, (bt
%1000000000)/1000000);
2146 if (bss
[NL80211_BSS_TSF
]) {
2147 unsigned long long tsf
;
2148 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
2149 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
2150 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
2151 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
2153 if (bss
[NL80211_BSS_FREQUENCY
]) {
2154 int freq
= nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]);
2155 printf("\tfreq: %d\n", freq
);
2159 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
2160 printf("\tbeacon interval: %d TUs\n",
2161 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
2162 if (bss
[NL80211_BSS_CAPABILITY
]) {
2163 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
2164 printf("\tcapability:");
2166 print_capa_dmg(capa
);
2168 print_capa_non_dmg(capa
);
2169 printf(" (0x%.4x)\n", capa
);
2171 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
2172 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
2173 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
2175 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
2176 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
2177 printf("\tsignal: %d/100\n", s
);
2179 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
2180 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
2181 printf("\tlast seen: %d ms ago\n", age
);
2184 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
2185 if (bss
[NL80211_BSS_BEACON_IES
])
2186 printf("\tInformation elements from Probe Response "
2188 print_ies(nla_data(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
2189 nla_len(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
2190 params
->unknown
, params
->type
);
2192 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
2193 printf("\tInformation elements from Beacon frame:\n");
2194 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
2195 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
2196 params
->unknown
, params
->type
);
2202 static struct scan_params scan_params
;
2204 static int handle_scan_dump(struct nl80211_state
*state
,
2206 int argc
, char **argv
,
2212 memset(&scan_params
, 0, sizeof(scan_params
));
2214 if (argc
== 1 && !strcmp(argv
[0], "-u"))
2215 scan_params
.unknown
= true;
2216 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
2217 scan_params
.show_both_ie_sets
= true;
2219 scan_params
.type
= PRINT_SCAN
;
2221 register_handler(print_bss_handler
, &scan_params
);
2225 static int handle_scan_combined(struct nl80211_state
*state
,
2227 int argc
, char **argv
,
2231 static char *dump_argv
[] = {
2237 static const __u32 cmds
[] = {
2238 NL80211_CMD_NEW_SCAN_RESULTS
,
2239 NL80211_CMD_SCAN_ABORTED
,
2241 int trig_argc
, dump_argc
, err
;
2244 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
2246 dump_argv
[3] = "-u";
2247 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
2249 dump_argv
[3] = "-b";
2253 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
2254 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
2257 trig_argv
[0] = argv
[0];
2258 trig_argv
[1] = "scan";
2259 trig_argv
[2] = "trigger";
2261 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
2262 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
2263 err
= handle_cmd(state
, id
, trig_argc
, trig_argv
);
2269 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
2271 * This code has a bug, which requires creating a separate
2272 * nl80211 socket to fix:
2273 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
2274 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
2275 * before (!) we listen to it, because we only start listening
2276 * after we send our scan request.
2278 * Doing it the other way around has a race condition as well,
2279 * if you first open the events socket you may get a notification
2280 * for a previous scan.
2282 * The only proper way to fix this would be to listen to events
2283 * before sending the command, and for the kernel to send the
2284 * scan request along with the event, so that you can match up
2285 * whether the scan you requested was finished or aborted (this
2286 * may result in processing a scan that another application
2287 * requested, but that doesn't seem to be a problem).
2289 * Alas, the kernel doesn't do that (yet).
2292 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
2293 NL80211_CMD_SCAN_ABORTED
) {
2294 printf("scan aborted!\n");
2298 dump_argv
[0] = argv
[0];
2299 return handle_cmd(state
, id
, dump_argc
, dump_argv
);
2301 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,
2302 CIB_NETDEV
, handle_scan_combined
,
2303 "Scan on the given frequencies and probe for the given SSIDs\n"
2304 "(or wildcard if not given) unless passive scanning is requested.\n"
2305 "If -u is specified print unknown data in the scan results.\n"
2306 "Specified (vendor) IEs must be well-formed.");
2307 COMMAND(scan
, dump
, "[-u]",
2308 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
2309 "Dump the current scan results. If -u is specified, print unknown\n"
2310 "data in scan results.");
2311 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]",
2312 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
2313 "Trigger a scan on the given frequencies with probing for the given\n"
2314 "SSIDs (or wildcard if not given) unless passive scanning is requested.\n"
2315 "Duration(in TUs), if specified, will be used to set dwell times.\n");
2318 static int handle_scan_abort(struct nl80211_state
*state
,
2320 int argc
, char **argv
,
2325 COMMAND(scan
, abort
, "",
2326 NL80211_CMD_ABORT_SCAN
, 0, CIB_NETDEV
, handle_scan_abort
,
2327 "Abort ongoing scan");
2329 static int handle_start_sched_scan(struct nl80211_state
*state
,
2331 int argc
, char **argv
, enum id_input id
)
2333 return parse_sched_scan(msg
, &argc
, &argv
);
2336 static int handle_stop_sched_scan(struct nl80211_state
*state
,
2337 struct nl_msg
*msg
, int argc
, char **argv
,
2346 COMMAND(scan
, sched_start
,
2348 NL80211_CMD_START_SCHED_SCAN
, 0, CIB_NETDEV
, handle_start_sched_scan
,
2349 "Start a scheduled scan at the specified interval on the given frequencies\n"
2350 "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2351 "scanning is requested. If matches are specified, only matching results\n"
2352 "will be returned.");
2353 COMMAND(scan
, sched_stop
, "",
2354 NL80211_CMD_STOP_SCHED_SCAN
, 0, CIB_NETDEV
, handle_stop_sched_scan
,
2355 "Stop an ongoing scheduled scan.");