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) {
479 /* fall through - this is an error */
485 freq
= strtoul(argv
[i
], &eptr
, 10);
486 if (eptr
!= argv
[i
] + strlen(argv
[i
])) {
487 /* failed to parse as number -- maybe a tag? */
492 NLA_PUT_U32(freqs
, i
, freq
);
495 ies
= parse_hex(argv
[i
], &ies_len
);
497 goto nla_put_failure
;
501 NLA_PUT(ssids
, i
, strlen(argv
[i
]), argv
[i
]);
504 meshid_len
= strlen(argv
[i
]);
505 meshid
= (unsigned char *) malloc(meshid_len
+ 2);
507 goto nla_put_failure
;
508 meshid
[0] = 114; /* mesh element id */
509 meshid
[1] = meshid_len
;
510 memcpy(&meshid
[2], argv
[i
], meshid_len
);
515 duration
= strtoul(argv
[i
], &eptr
, 10);
522 tmpies
= (unsigned char *) malloc(ies_len
+ meshid_len
);
526 goto nla_put_failure
;
529 memcpy(tmpies
, ies
, ies_len
);
533 memcpy(&tmpies
[ies_len
], meshid
, meshid_len
);
536 if (nla_put(msg
, NL80211_ATTR_IE
, ies_len
+ meshid_len
, tmpies
) < 0) {
538 goto nla_put_failure
;
544 NLA_PUT(ssids
, 1, 0, "");
546 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
549 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
551 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
553 NLA_PUT_U16(msg
, NL80211_ATTR_MEASUREMENT_DURATION
, duration
);
554 if (duration_mandatory
) {
557 NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY
);
560 goto nla_put_failure
;
571 static void tab_on_first(bool *first
)
579 struct print_ies_data
{
584 static void print_ssid(const uint8_t type
, uint8_t len
, const uint8_t *data
,
585 const struct print_ies_data
*ie_buffer
)
588 print_ssid_escaped(len
, data
);
592 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
593 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
595 static void print_supprates(const uint8_t type
, uint8_t len
,
597 const struct print_ies_data
*ie_buffer
)
603 for (i
= 0; i
< len
; i
++) {
604 int r
= data
[i
] & 0x7f;
606 if (r
== BSS_MEMBERSHIP_SELECTOR_VHT_PHY
&& data
[i
] & 0x80)
608 else if (r
== BSS_MEMBERSHIP_SELECTOR_HT_PHY
&& data
[i
] & 0x80)
611 printf("%d.%d", r
/2, 5*(r
&1));
613 printf("%s ", data
[i
] & 0x80 ? "*" : "");
618 static void print_ds(const uint8_t type
, uint8_t len
, const uint8_t *data
,
619 const struct print_ies_data
*ie_buffer
)
621 printf(" channel %d\n", data
[0]);
624 static const char *country_env_str(char environment
)
626 switch (environment
) {
628 return "Indoor only";
630 return "Outdoor only";
632 return "Indoor/Outdoor";
638 static void print_country(const uint8_t type
, uint8_t len
, const uint8_t *data
,
639 const struct print_ies_data
*ie_buffer
)
641 printf(" %.*s", 2, data
);
643 printf("\tEnvironment: %s\n", country_env_str(data
[2]));
649 printf("\t\tNo country IE triplets present\n");
655 union ieee80211_country_ie_triplet
*triplet
= (void *) data
;
657 if (triplet
->ext
.reg_extension_id
>= IEEE80211_COUNTRY_EXTENSION_ID
) {
658 printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
659 triplet
->ext
.reg_extension_id
,
660 triplet
->ext
.reg_class
,
661 triplet
->ext
.coverage_class
,
662 triplet
->ext
.coverage_class
* 450);
670 if (triplet
->chans
.first_channel
<= 14)
671 end_channel
= triplet
->chans
.first_channel
+ (triplet
->chans
.num_channels
- 1);
673 end_channel
= triplet
->chans
.first_channel
+ (4 * (triplet
->chans
.num_channels
- 1));
675 printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet
->chans
.first_channel
, end_channel
, triplet
->chans
.max_power
);
684 static void print_powerconstraint(const uint8_t type
, uint8_t len
,
686 const struct print_ies_data
*ie_buffer
)
688 printf(" %d dB\n", data
[0]);
691 static void print_tpcreport(const uint8_t type
, uint8_t len
,
693 const struct print_ies_data
*ie_buffer
)
695 printf(" TX power: %d dBm\n", data
[0]);
696 /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
699 static void print_erp(const uint8_t type
, uint8_t len
, const uint8_t *data
,
700 const struct print_ies_data
*ie_buffer
)
703 printf(" <no flags>");
705 printf(" NonERP_Present");
707 printf(" Use_Protection");
709 printf(" Barker_Preamble_Mode");
713 static void print_cipher(const uint8_t *data
)
715 if (memcmp(data
, ms_oui
, 3) == 0) {
718 printf("Use group cipher suite");
733 printf("%.02x-%.02x-%.02x:%d",
734 data
[0], data
[1] ,data
[2], data
[3]);
737 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
740 printf("Use group cipher suite");
755 printf("AES-128-CMAC");
764 printf("%.02x-%.02x-%.02x:%d",
765 data
[0], data
[1] ,data
[2], data
[3]);
769 printf("%.02x-%.02x-%.02x:%d",
770 data
[0], data
[1] ,data
[2], data
[3]);
773 static void print_auth(const uint8_t *data
)
775 if (memcmp(data
, ms_oui
, 3) == 0) {
778 printf("IEEE 802.1X");
784 printf("%.02x-%.02x-%.02x:%d",
785 data
[0], data
[1] ,data
[2], data
[3]);
788 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
791 printf("IEEE 802.1X");
797 printf("FT/IEEE 802.1X");
803 printf("IEEE 802.1X/SHA-256");
806 printf("PSK/SHA-256");
818 printf("IEEE 802.1X/SUITE-B");
821 printf("IEEE 802.1X/SUITE-B-192");
824 printf("FT/IEEE 802.1X/SHA-384");
827 printf("FILS/SHA-256");
830 printf("FILS/SHA-384");
833 printf("FT/FILS/SHA-256");
836 printf("FT/FILS/SHA-384");
842 printf("%.02x-%.02x-%.02x:%d",
843 data
[0], data
[1] ,data
[2], data
[3]);
846 } else if (memcmp(data
, wfa_oui
, 3) == 0) {
855 printf("%.02x-%.02x-%.02x:%d",
856 data
[0], data
[1] ,data
[2], data
[3]);
860 printf("%.02x-%.02x-%.02x:%d",
861 data
[0], data
[1] ,data
[2], data
[3]);
864 static void _print_rsn_ie(const char *defcipher
, const char *defauth
,
865 uint8_t len
, const uint8_t *data
, int is_osen
)
873 version
= data
[0] + (data
[1] << 8);
874 tab_on_first(&first
);
875 printf("\t * Version: %d\n", version
);
882 tab_on_first(&first
);
883 printf("\t * Group cipher: %s\n", defcipher
);
884 printf("\t * Pairwise ciphers: %s\n", defcipher
);
888 tab_on_first(&first
);
889 printf("\t * Group cipher: ");
897 tab_on_first(&first
);
898 printf("\t * Pairwise ciphers: %s\n", defcipher
);
902 count
= data
[0] | (data
[1] << 8);
903 if (2 + (count
* 4) > len
)
906 tab_on_first(&first
);
907 printf("\t * Pairwise ciphers:");
908 for (i
= 0; i
< count
; i
++) {
910 print_cipher(data
+ 2 + (i
* 4));
914 data
+= 2 + (count
* 4);
915 len
-= 2 + (count
* 4);
918 tab_on_first(&first
);
919 printf("\t * Authentication suites: %s\n", defauth
);
923 count
= data
[0] | (data
[1] << 8);
924 if (2 + (count
* 4) > len
)
927 tab_on_first(&first
);
928 printf("\t * Authentication suites:");
929 for (i
= 0; i
< count
; i
++) {
931 print_auth(data
+ 2 + (i
* 4));
935 data
+= 2 + (count
* 4);
936 len
-= 2 + (count
* 4);
939 capa
= data
[0] | (data
[1] << 8);
940 tab_on_first(&first
);
941 printf("\t * Capabilities:");
945 printf(" NoPairwise");
946 switch ((capa
& 0x000c) >> 2) {
948 printf(" 1-PTKSA-RC");
951 printf(" 2-PTKSA-RC");
954 printf(" 4-PTKSA-RC");
957 printf(" 16-PTKSA-RC");
960 switch ((capa
& 0x0030) >> 4) {
962 printf(" 1-GTKSA-RC");
965 printf(" 2-GTKSA-RC");
968 printf(" 4-GTKSA-RC");
971 printf(" 16-GTKSA-RC");
975 printf(" MFP-required");
977 printf(" MFP-capable");
979 printf(" Peerkey-enabled");
981 printf(" SPP-AMSDU-capable");
983 printf(" SPP-AMSDU-required");
984 printf(" (0x%.4x)\n", capa
);
990 int pmkid_count
= data
[0] | (data
[1] << 8);
992 if (len
>= 2 + 16 * pmkid_count
) {
993 tab_on_first(&first
);
994 printf("\t * %d PMKIDs\n", pmkid_count
);
995 /* not printing PMKID values */
996 data
+= 2 + 16 * pmkid_count
;
997 len
-= 2 + 16 * pmkid_count
;
1003 tab_on_first(&first
);
1004 printf("\t * Group mgmt cipher suite: ");
1013 printf("\t\t * bogus tail data (%d):", len
);
1015 printf(" %.2x", *data
);
1023 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
1024 uint8_t len
, const uint8_t *data
)
1026 _print_rsn_ie(defcipher
, defauth
, len
, data
, 0);
1029 static void print_osen_ie(const char *defcipher
, const char *defauth
,
1030 uint8_t len
, const uint8_t *data
)
1033 _print_rsn_ie(defcipher
, defauth
, len
, data
, 1);
1036 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1037 const struct print_ies_data
*ie_buffer
)
1039 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
1042 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1043 const struct print_ies_data
*ie_buffer
)
1046 print_ht_capability(data
[0] | (data
[1] << 8));
1047 print_ampdu_length(data
[2] & 3);
1048 print_ampdu_spacing((data
[2] >> 2) & 7);
1049 print_ht_mcs(data
+ 3);
1052 static const char* ntype_11u(uint8_t t
)
1055 case 0: return "Private";
1056 case 1: return "Private with Guest";
1057 case 2: return "Chargeable Public";
1058 case 3: return "Free Public";
1059 case 4: return "Personal Device";
1060 case 5: return "Emergency Services Only";
1061 case 14: return "Test or Experimental";
1062 case 15: return "Wildcard";
1063 default: return "Reserved";
1067 static const char* vgroup_11u(uint8_t t
)
1070 case 0: return "Unspecified";
1071 case 1: return "Assembly";
1072 case 2: return "Business";
1073 case 3: return "Educational";
1074 case 4: return "Factory and Industrial";
1075 case 5: return "Institutional";
1076 case 6: return "Mercantile";
1077 case 7: return "Residential";
1078 case 8: return "Storage";
1079 case 9: return "Utility and Miscellaneous";
1080 case 10: return "Vehicular";
1081 case 11: return "Outdoor";
1082 default: return "Reserved";
1086 static void print_interworking(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.92 in the 802.11u spec. */
1093 uint8_t ano
= data
[0];
1094 printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano
));
1095 printf("\t\t\tNetwork Type: %i (%s)\n",
1096 (int)(ano
& 0xf), ntype_11u(ano
& 0xf));
1098 printf("\t\t\tInternet\n");
1100 printf("\t\t\tASRA\n");
1102 printf("\t\t\tESR\n");
1104 printf("\t\t\tUESA\n");
1106 if ((len
== 3) || (len
== 9)) {
1107 printf("\t\tVenue Group: %i (%s)\n",
1108 (int)(data
[1]), vgroup_11u(data
[1]));
1109 printf("\t\tVenue Type: %i\n", (int)(data
[2]));
1112 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
1113 data
[3], data
[4], data
[5], data
[6], data
[7], data
[8]);
1115 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
1116 data
[1], data
[2], data
[3], data
[4], data
[5], data
[6]);
1119 static void print_11u_advert(const uint8_t type
, uint8_t len
,
1120 const uint8_t *data
,
1121 const struct print_ies_data
*ie_buffer
)
1123 /* See Section 7.3.2.93 in the 802.11u spec. */
1124 /* TODO: This code below does not decode private protocol IDs */
1127 while (idx
< (len
- 1)) {
1128 uint8_t qri
= data
[idx
];
1129 uint8_t proto_id
= data
[idx
+ 1];
1130 printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri
));
1131 printf("\t\t\tQuery Response Length Limit: %i\n",
1134 printf("\t\t\tPAME-BI\n");
1137 printf("\t\t\tANQP\n"); break;
1139 printf("\t\t\tMIH Information Service\n"); break;
1141 printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
1143 printf("\t\t\tEmergency Alert System (EAS)\n"); break;
1145 printf("\t\t\tVendor Specific\n"); break;
1147 printf("\t\t\tReserved: %i\n", proto_id
); break;
1153 static void print_11u_rcon(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1154 const struct print_ies_data
*ie_buffer
)
1156 /* See Section 7.3.2.96 in the 802.11u spec. */
1158 int ln0
= data
[1] & 0xf;
1159 int ln1
= ((data
[1] & 0xf0) >> 4);
1164 ln2
= len
- 2 - ln0
- ln1
;
1166 printf("\t\tANQP OIs: %i\n", data
[0]);
1169 printf("\t\tOI 1: ");
1170 if (2 + ln0
> len
) {
1171 printf("Invalid IE length.\n");
1173 for (idx
= 0; idx
< ln0
; idx
++) {
1174 printf("%02hx", data
[2 + idx
]);
1181 printf("\t\tOI 2: ");
1182 if (2 + ln0
+ ln1
> len
) {
1183 printf("Invalid IE length.\n");
1185 for (idx
= 0; idx
< ln1
; idx
++) {
1186 printf("%02hx", data
[2 + ln0
+ idx
]);
1193 printf("\t\tOI 3: ");
1194 if (2 + ln0
+ ln1
+ ln2
> len
) {
1195 printf("Invalid IE length.\n");
1197 for (idx
= 0; idx
< ln2
; idx
++) {
1198 printf("%02hx", data
[2 + ln0
+ ln1
+ idx
]);
1205 static const char *ht_secondary_offset
[4] = {
1212 static void print_ht_op(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1213 const struct print_ies_data
*ie_buffer
)
1215 static const char *protection
[4] = {
1221 static const char *sta_chan_width
[2] = {
1227 printf("\t\t * primary channel: %d\n", data
[0]);
1228 printf("\t\t * secondary channel offset: %s\n",
1229 ht_secondary_offset
[data
[1] & 0x3]);
1230 printf("\t\t * STA channel width: %s\n", sta_chan_width
[(data
[1] & 0x4)>>2]);
1231 printf("\t\t * RIFS: %d\n", (data
[1] & 0x8)>>3);
1232 printf("\t\t * HT protection: %s\n", protection
[data
[2] & 0x3]);
1233 printf("\t\t * non-GF present: %d\n", (data
[2] & 0x4) >> 2);
1234 printf("\t\t * OBSS non-GF present: %d\n", (data
[2] & 0x10) >> 4);
1235 printf("\t\t * dual beacon: %d\n", (data
[4] & 0x40) >> 6);
1236 printf("\t\t * dual CTS protection: %d\n", (data
[4] & 0x80) >> 7);
1237 printf("\t\t * STBC beacon: %d\n", data
[5] & 0x1);
1238 printf("\t\t * L-SIG TXOP Prot: %d\n", (data
[5] & 0x2) >> 1);
1239 printf("\t\t * PCO active: %d\n", (data
[5] & 0x4) >> 2);
1240 printf("\t\t * PCO phase: %d\n", (data
[5] & 0x8) >> 3);
1243 static void print_capabilities(const uint8_t type
, uint8_t len
,
1244 const uint8_t *data
,
1245 const struct print_ies_data
*ie_buffer
)
1247 int i
, base
, bit
, si_duration
= 0, max_amsdu
= 0;
1248 bool s_psmp_support
= false, is_vht_cap
= false;
1249 unsigned char *ie
= ie_buffer
->ie
;
1250 int ielen
= ie_buffer
->ielen
;
1252 while (ielen
>= 2 && ielen
>= ie
[1]) {
1261 for (i
= 0; i
< len
; i
++) {
1264 for (bit
= 0; bit
< 8; bit
++) {
1265 if (!(data
[i
] & (1 << bit
)))
1270 #define CAPA(bit, name) case bit: printf(" " name); break
1272 /* if the capability 'cap' exists add 'val' to 'sum'
1273 * otherwise print 'Reserved' */
1274 #define ADD_BIT_VAL(bit, cap, sum, val) case (bit): do { \
1276 printf(" Reserved"); \
1283 switch (bit
+ base
) {
1284 CAPA(0, "HT Information Exchange Supported");
1285 CAPA(1, "reserved (On-demand Beacon)");
1286 CAPA(2, "Extended Channel Switching");
1287 CAPA(3, "reserved (Wave Indication)");
1288 CAPA(4, "PSMP Capability");
1289 CAPA(5, "reserved (Service Interval Granularity)");
1292 s_psmp_support
= true;
1293 printf(" S-PSMP Capability");
1297 CAPA(8, "Diagnostics");
1298 CAPA(9, "Multicast Diagnostics");
1299 CAPA(10, "Location Tracking");
1301 CAPA(12, "Proxy ARP Service");
1302 CAPA(13, "Collocated Interference Reporting");
1303 CAPA(14, "Civic Location");
1304 CAPA(15, "Geospatial Location");
1306 CAPA(17, "WNM-Sleep Mode");
1307 CAPA(18, "TIM Broadcast");
1308 CAPA(19, "BSS Transition");
1309 CAPA(20, "QoS Traffic Capability");
1310 CAPA(21, "AC Station Count");
1311 CAPA(22, "Multiple BSSID");
1312 CAPA(23, "Timing Measurement");
1313 CAPA(24, "Channel Usage");
1314 CAPA(25, "SSID List");
1316 CAPA(27, "UTC TSF Offset");
1317 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1318 CAPA(29, "TDLS Peer PSM Support");
1319 CAPA(30, "TDLS channel switching");
1320 CAPA(31, "Interworking");
1321 CAPA(32, "QoS Map");
1323 CAPA(34, "SSPN Interface");
1324 CAPA(35, "Reserved");
1325 CAPA(36, "MSGCF Capability");
1326 CAPA(37, "TDLS Support");
1327 CAPA(38, "TDLS Prohibited");
1328 CAPA(39, "TDLS Channel Switching Prohibited");
1329 CAPA(40, "Reject Unadmitted Frame");
1331 ADD_BIT_VAL(41, s_psmp_support
, si_duration
, 1);
1332 ADD_BIT_VAL(42, s_psmp_support
, si_duration
, 2);
1333 ADD_BIT_VAL(43, s_psmp_support
, si_duration
, 4);
1335 CAPA(44, "Identifier Location");
1336 CAPA(45, "U-APSD Coexistence");
1337 CAPA(46, "WNM-Notification");
1338 CAPA(47, "Reserved");
1339 CAPA(48, "UTF-8 SSID");
1340 CAPA(49, "QMFActivated");
1341 CAPA(50, "QMFReconfigurationActivated");
1342 CAPA(51, "Robust AV Streaming");
1343 CAPA(52, "Advanced GCR");
1344 CAPA(53, "Mesh GCR");
1346 CAPA(55, "QLoad Report");
1347 CAPA(56, "Alternate EDCA");
1348 CAPA(57, "Unprotected TXOP Negotiation");
1349 CAPA(58, "Protected TXOP egotiation");
1350 CAPA(59, "Reserved");
1351 CAPA(60, "Protected QLoad Report");
1352 CAPA(61, "TDLS Wider Bandwidth");
1353 CAPA(62, "Operating Mode Notification");
1355 ADD_BIT_VAL(63, is_vht_cap
, max_amsdu
, 1);
1356 ADD_BIT_VAL(64, is_vht_cap
, max_amsdu
, 2);
1358 CAPA(65, "Channel Schedule Management");
1359 CAPA(66, "Geodatabase Inband Enabling Signal");
1360 CAPA(67, "Network Channel Control");
1361 CAPA(68, "White Space Map");
1362 CAPA(69, "Channel Availability Query");
1363 CAPA(70, "FTM Responder");
1364 CAPA(71, "FTM Initiator");
1365 CAPA(72, "Reserved");
1366 CAPA(73, "Extended Spectrum Management Capable");
1367 CAPA(74, "Reserved");
1378 printf("\n\t\t * Service Interval Granularity is %d ms",
1379 (si_duration
+ 1) * 5);
1382 printf("\n\t\t * Max Number Of MSDUs In A-MSDU is ");
1383 switch (max_amsdu
) {
1385 printf("unlimited");
1404 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1405 const struct print_ies_data
*ie_buffer
)
1407 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1409 data
[0], data
[1], data
[2], data
[3]);
1411 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
1415 static void print_ibssatim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1416 const struct print_ies_data
*ie_buffer
)
1418 printf(" %d TUs", (data
[1] << 8) + data
[0]);
1421 static void print_vht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1422 const struct print_ies_data
*ie_buffer
)
1425 print_vht_info(data
[0] | (data
[1] << 8) |
1426 (data
[2] << 16) | (data
[3] << 24),
1430 static void print_vht_oper(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1431 const struct print_ies_data
*ie_buffer
)
1433 const char *chandwidths
[] = {
1434 [0] = "20 or 40 MHz",
1441 printf("\t\t * channel width: %d (%s)\n", data
[0],
1442 data
[0] < ARRAY_SIZE(chandwidths
) ? chandwidths
[data
[0]] : "unknown");
1443 printf("\t\t * center freq segment 1: %d\n", data
[1]);
1444 printf("\t\t * center freq segment 2: %d\n", data
[2]);
1445 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data
[4], data
[3]);
1448 static void print_obss_scan_params(const uint8_t type
, uint8_t len
,
1449 const uint8_t *data
,
1450 const struct print_ies_data
*ie_buffer
)
1453 printf("\t\t * passive dwell: %d TUs\n", (data
[1] << 8) | data
[0]);
1454 printf("\t\t * active dwell: %d TUs\n", (data
[3] << 8) | data
[2]);
1455 printf("\t\t * channel width trigger scan interval: %d s\n", (data
[5] << 8) | data
[4]);
1456 printf("\t\t * scan passive total per channel: %d TUs\n", (data
[7] << 8) | data
[6]);
1457 printf("\t\t * scan active total per channel: %d TUs\n", (data
[9] << 8) | data
[8]);
1458 printf("\t\t * BSS width channel transition delay factor: %d\n", (data
[11] << 8) | data
[10]);
1459 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1460 ((data
[13] << 8) | data
[12]) / 100, ((data
[13] << 8) | data
[12]) % 100);
1463 static void print_secchan_offs(const uint8_t type
, uint8_t len
,
1464 const uint8_t *data
,
1465 const struct print_ies_data
*ie_buffer
)
1467 if (data
[0] < ARRAY_SIZE(ht_secondary_offset
))
1468 printf(" %s (%d)\n", ht_secondary_offset
[data
[0]], data
[0]);
1470 printf(" %d\n", data
[0]);
1473 static void print_bss_load(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1474 const struct print_ies_data
*ie_buffer
)
1477 printf("\t\t * station count: %d\n", (data
[1] << 8) | data
[0]);
1478 printf("\t\t * channel utilisation: %d/255\n", data
[2]);
1479 printf("\t\t * available admission capacity: %d [*32us]\n", (data
[4] << 8) | data
[3]);
1482 static void print_mesh_conf(const uint8_t type
, uint8_t len
,
1483 const uint8_t *data
,
1484 const struct print_ies_data
*ie_buffer
)
1487 printf("\t\t * Active Path Selection Protocol ID: %d\n", data
[0]);
1488 printf("\t\t * Active Path Selection Metric ID: %d\n", data
[1]);
1489 printf("\t\t * Congestion Control Mode ID: %d\n", data
[2]);
1490 printf("\t\t * Synchronization Method ID: %d\n", data
[3]);
1491 printf("\t\t * Authentication Protocol ID: %d\n", data
[4]);
1492 printf("\t\t * Mesh Formation Info:\n");
1493 printf("\t\t\t Number of Peerings: %d\n", (data
[5] & 0x7E) >> 1);
1495 printf("\t\t\t Connected to Mesh Gate\n");
1497 printf("\t\t\t Connected to AS\n");
1498 printf("\t\t * Mesh Capability\n");
1500 printf("\t\t\t Accepting Additional Mesh Peerings\n");
1502 printf("\t\t\t MCCA Supported\n");
1504 printf("\t\t\t MCCA Enabled\n");
1506 printf("\t\t\t Forwarding\n");
1508 printf("\t\t\t MBCA Supported\n");
1510 printf("\t\t\t TBTT Adjusting\n");
1512 printf("\t\t\t Mesh Power Save Level\n");
1517 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1518 const struct print_ies_data
*ie_buffer
);
1519 uint8_t minlen
, maxlen
;
1523 static void print_ie(const struct ie_print
*p
, const uint8_t type
, uint8_t len
,
1524 const uint8_t *data
,
1525 const struct print_ies_data
*ie_buffer
)
1532 printf("\t%s:", p
->name
);
1533 if (len
< p
->minlen
|| len
> p
->maxlen
) {
1535 printf(" <invalid: %d bytes:", len
);
1536 for (i
= 0; i
< len
; i
++)
1537 printf(" %.02x", data
[i
]);
1540 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
1542 printf(" <invalid: no data>\n");
1546 p
->print(type
, len
, data
, ie_buffer
);
1549 #define PRINT_IGN { \
1556 static const struct ie_print ieprinters
[] = {
1557 [0] = { "SSID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1558 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1559 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
1560 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
1561 [6] = { "IBSS ATIM window", print_ibssatim
, 2, 2, BIT(PRINT_SCAN
), },
1562 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
1563 [11] = { "BSS Load", print_bss_load
, 5, 5, BIT(PRINT_SCAN
), },
1564 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
1565 [35] = { "TPC report", print_tpcreport
, 2, 2, BIT(PRINT_SCAN
), },
1566 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1567 [45] = { "HT capabilities", print_ht_capa
, 26, 26, BIT(PRINT_SCAN
), },
1568 [47] = { "ERP D4.0", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1569 [74] = { "Overlapping BSS scan params", print_obss_scan_params
, 14, 255, BIT(PRINT_SCAN
), },
1570 [61] = { "HT operation", print_ht_op
, 22, 22, BIT(PRINT_SCAN
), },
1571 [62] = { "Secondary Channel Offset", print_secchan_offs
, 1, 1, BIT(PRINT_SCAN
), },
1572 [191] = { "VHT capabilities", print_vht_capa
, 12, 255, BIT(PRINT_SCAN
), },
1573 [192] = { "VHT operation", print_vht_oper
, 5, 255, BIT(PRINT_SCAN
), },
1574 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
1575 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1576 [113] = { "MESH Configuration", print_mesh_conf
, 7, 7, BIT(PRINT_SCAN
), },
1577 [114] = { "MESH ID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1578 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
1579 [107] = { "802.11u Interworking", print_interworking
, 0, 255, BIT(PRINT_SCAN
), },
1580 [108] = { "802.11u Advertisement", print_11u_advert
, 0, 255, BIT(PRINT_SCAN
), },
1581 [111] = { "802.11u Roaming Consortium", print_11u_rcon
, 0, 255, BIT(PRINT_SCAN
), },
1584 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1585 const struct print_ies_data
*ie_buffer
)
1587 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
1590 static void print_wifi_osen(const uint8_t type
, uint8_t len
,
1591 const uint8_t *data
,
1592 const struct print_ies_data
*ie_buffer
)
1594 print_osen_ie("OSEN", "OSEN", len
, data
);
1597 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
1600 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
1606 printf("Parameter: not version 1: ");
1610 printf("\t * Parameter version 1");
1615 printf("\n\t\t * u-APSD");
1619 for (i
= 0; i
< 4; i
++) {
1620 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
1623 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
1624 (1 << (data
[1] >> 4)) - 1);
1625 printf(", AIFSN %d", data
[0] & 0xf);
1626 if (data
[2] | data
[3])
1627 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
1635 printf("invalid: ");
1639 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1640 const struct print_ies_data
*ie_buffer
)
1646 printf(" information:");
1649 if (print_wifi_wmm_param(data
+ 1, len
- 1))
1653 printf(" type %d:", data
[0]);
1657 for(i
= 1; i
< len
; i
++)
1658 printf(" %.02x", data
[i
]);
1662 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
1666 return "Default (PIN)";
1668 return "User-specified";
1670 return "Machine-specified";
1674 return "PushButton";
1676 return "Registrar-specified";
1682 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1683 const struct print_ies_data
*ie_buffer
)
1686 __u16 subtype
, sublen
;
1689 subtype
= (data
[0] << 8) + data
[1];
1690 sublen
= (data
[2] << 8) + data
[3];
1696 tab_on_first(&first
);
1697 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
1700 tab_on_first(&first
);
1701 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
1705 tab_on_first(&first
);
1707 printf("\t * Device Password ID: (invalid "
1708 "length %d)\n", sublen
);
1711 id
= data
[4] << 8 | data
[5];
1712 printf("\t * Device Password ID: %u (%s)\n",
1713 id
, wifi_wps_dev_passwd_id(id
));
1717 tab_on_first(&first
);
1718 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
1721 tab_on_first(&first
);
1722 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
1725 tab_on_first(&first
);
1726 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
1730 tab_on_first(&first
);
1731 printf("\t * Response Type: %d%s\n",
1732 val
, val
== 3 ? " (AP)" : "");
1737 tab_on_first(&first
);
1738 printf("\t * RF Bands: 0x%x\n", val
);
1743 tab_on_first(&first
);
1744 printf("\t * Selected Registrar: 0x%x\n", val
);
1748 tab_on_first(&first
);
1749 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
1753 tab_on_first(&first
);
1754 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1756 val
== 1 ? " (Unconfigured)" : "",
1757 val
== 2 ? " (Configured)" : "");
1761 tab_on_first(&first
);
1762 printf("\t * UUID: ");
1764 printf("(invalid, length=%d)\n", sublen
);
1767 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1768 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1769 data
[4], data
[5], data
[6], data
[7],
1770 data
[8], data
[9], data
[10], data
[11],
1771 data
[12], data
[13], data
[14], data
[15],
1772 data
[16], data
[17], data
[18], data
[19]);
1775 tab_on_first(&first
);
1777 printf("\t * Primary Device Type: (invalid "
1778 "length %d)\n", sublen
);
1781 printf("\t * Primary Device Type: "
1782 "%u-%02x%02x%02x%02x-%u\n",
1783 data
[4] << 8 | data
[5],
1784 data
[6], data
[7], data
[8], data
[9],
1785 data
[10] << 8 | data
[11]);
1790 tab_on_first(&first
);
1791 printf("\t * AP setup locked: 0x%.2x\n", val
);
1796 __u16 meth
= (data
[4] << 8) + data
[5];
1798 tab_on_first(&first
);
1799 printf("\t * %sConfig methods:",
1800 subtype
== 0x1053 ? "Selected Registrar ": "");
1801 #define T(bit, name) do { \
1802 if (meth & (1<<bit)) { \
1822 const __u8
*subdata
= data
+ 4;
1823 __u16 tmplen
= sublen
;
1825 tab_on_first(&first
);
1826 printf("\t * Unknown TLV (%#.4x, %d bytes):",
1829 printf(" %.2x", *subdata
);
1843 printf("\t\t * bogus tail data (%d):", len
);
1845 printf(" %.2x", *data
);
1853 static const struct ie_print wifiprinters
[] = {
1854 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
1855 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
1856 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
1859 static inline void print_p2p(const uint8_t type
, uint8_t len
,
1860 const uint8_t *data
,
1861 const struct print_ies_data
*ie_buffer
)
1869 sublen
= (data
[2] << 8) + data
[1];
1871 if (sublen
> len
- 3)
1875 case 0x02: /* capability */
1876 tab_on_first(&first
);
1878 printf("\t * malformed capability\n");
1881 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
1884 case 0x0d: /* device info */
1885 if (sublen
< 6 + 2 + 8 + 1) {
1886 printf("\t * malformed device info\n");
1890 case 0x00: /* status */
1891 case 0x01: /* minor reason */
1892 case 0x03: /* device ID */
1893 case 0x04: /* GO intent */
1894 case 0x05: /* configuration timeout */
1895 case 0x06: /* listen channel */
1896 case 0x07: /* group BSSID */
1897 case 0x08: /* ext listen timing */
1898 case 0x09: /* intended interface address */
1899 case 0x0a: /* manageability */
1900 case 0x0b: /* channel list */
1901 case 0x0c: /* NoA */
1902 case 0x0e: /* group info */
1903 case 0x0f: /* group ID */
1904 case 0x10: /* interface */
1905 case 0x11: /* operating channel */
1906 case 0x12: /* invitation flags */
1907 case 0xdd: /* vendor specific */
1909 const __u8
*subdata
= data
+ 4;
1910 __u16 tmplen
= sublen
;
1912 tab_on_first(&first
);
1913 printf("\t * Unknown TLV (%#.2x, %d bytes):",
1916 printf(" %.2x", *subdata
);
1930 tab_on_first(&first
);
1931 printf("\t * bogus tail data (%d):", len
);
1933 printf(" %.2x", *data
);
1941 static inline void print_hs20_ind(const uint8_t type
, uint8_t len
,
1942 const uint8_t *data
,
1943 const struct print_ies_data
*ie_buffer
)
1945 /* I can't find the spec for this...just going off what wireshark uses. */
1948 printf("\t\tDGAF: %i\n", (int)(data
[0] & 0x1));
1950 printf("\t\tUnexpected length: %i\n", len
);
1953 static void print_wifi_owe_tarns(const uint8_t type
, uint8_t len
,
1954 const uint8_t *data
,
1955 const struct print_ies_data
*ie_buffer
)
1964 mac_addr_n2a(mac_addr
, data
);
1965 printf("\t\tBSSID: %s\n", mac_addr
);
1968 if (ssid_len
> len
- 7)
1970 printf("\t\tSSID: ");
1971 print_ssid_escaped(ssid_len
, data
+ 7);
1974 /* optional elements */
1975 if (len
>= ssid_len
+ 9) {
1976 printf("\t\tBand Info: %u\n", data
[ssid_len
+ 7]);
1977 printf("\t\tChannel Info: %u\n", data
[ssid_len
+ 8]);
1981 static const struct ie_print wfa_printers
[] = {
1982 [9] = { "P2P", print_p2p
, 2, 255, BIT(PRINT_SCAN
), },
1983 [16] = { "HotSpot 2.0 Indication", print_hs20_ind
, 1, 255, BIT(PRINT_SCAN
), },
1984 [18] = { "HotSpot 2.0 OSEN", print_wifi_osen
, 1, 255, BIT(PRINT_SCAN
), },
1985 [28] = { "OWE Transition Mode", print_wifi_owe_tarns
, 7, 255, BIT(PRINT_SCAN
), },
1988 static void print_vendor(unsigned char len
, unsigned char *data
,
1989 bool unknown
, enum print_ie_type ptype
)
1994 printf("\tVendor specific: <too short> data:");
1995 for(i
= 0; i
< len
; i
++)
1996 printf(" %.02x", data
[i
]);
2001 if (len
>= 4 && memcmp(data
, ms_oui
, 3) == 0) {
2002 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
2003 wifiprinters
[data
[3]].name
&&
2004 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
2005 print_ie(&wifiprinters
[data
[3]],
2006 data
[3], len
- 4, data
+ 4,
2012 printf("\tMS/WiFi %#.2x, data:", data
[3]);
2013 for(i
= 0; i
< len
- 4; i
++)
2014 printf(" %.02x", data
[i
+ 4]);
2019 if (len
>= 4 && memcmp(data
, wfa_oui
, 3) == 0) {
2020 if (data
[3] < ARRAY_SIZE(wfa_printers
) &&
2021 wfa_printers
[data
[3]].name
&&
2022 wfa_printers
[data
[3]].flags
& BIT(ptype
)) {
2023 print_ie(&wfa_printers
[data
[3]],
2024 data
[3], len
- 4, data
+ 4,
2030 printf("\tWFA %#.2x, data:", data
[3]);
2031 for(i
= 0; i
< len
- 4; i
++)
2032 printf(" %.02x", data
[i
+ 4]);
2040 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
2041 data
[0], data
[1], data
[2]);
2042 for (i
= 3; i
< len
; i
++)
2043 printf(" %.2x", data
[i
]);
2047 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
2048 enum print_ie_type ptype
)
2050 struct print_ies_data ie_buffer
= {
2054 while (ielen
>= 2 && ielen
>= ie
[1]) {
2055 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
2056 ieprinters
[ie
[0]].name
&&
2057 ieprinters
[ie
[0]].flags
& BIT(ptype
)) {
2058 print_ie(&ieprinters
[ie
[0]],
2059 ie
[0], ie
[1], ie
+ 2, &ie_buffer
);
2060 } else if (ie
[0] == 221 /* vendor */) {
2061 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
2062 } else if (unknown
) {
2065 printf("\tUnknown IE (%d):", ie
[0]);
2066 for (i
=0; i
<ie
[1]; i
++)
2067 printf(" %.2x", ie
[2+i
]);
2075 static void print_capa_dmg(__u16 capa
)
2077 switch (capa
& WLAN_CAPABILITY_DMG_TYPE_MASK
) {
2078 case WLAN_CAPABILITY_DMG_TYPE_AP
:
2081 case WLAN_CAPABILITY_DMG_TYPE_PBSS
:
2084 case WLAN_CAPABILITY_DMG_TYPE_IBSS
:
2085 printf(" DMG_IBSS");
2089 if (capa
& WLAN_CAPABILITY_DMG_CBAP_ONLY
)
2090 printf(" CBAP_Only");
2091 if (capa
& WLAN_CAPABILITY_DMG_CBAP_SOURCE
)
2092 printf(" CBAP_Src");
2093 if (capa
& WLAN_CAPABILITY_DMG_PRIVACY
)
2095 if (capa
& WLAN_CAPABILITY_DMG_ECPAC
)
2097 if (capa
& WLAN_CAPABILITY_DMG_SPECTRUM_MGMT
)
2098 printf(" SpectrumMgmt");
2099 if (capa
& WLAN_CAPABILITY_DMG_RADIO_MEASURE
)
2100 printf(" RadioMeasure");
2103 static void print_capa_non_dmg(__u16 capa
)
2105 if (capa
& WLAN_CAPABILITY_ESS
)
2107 if (capa
& WLAN_CAPABILITY_IBSS
)
2109 if (capa
& WLAN_CAPABILITY_CF_POLLABLE
)
2110 printf(" CfPollable");
2111 if (capa
& WLAN_CAPABILITY_CF_POLL_REQUEST
)
2112 printf(" CfPollReq");
2113 if (capa
& WLAN_CAPABILITY_PRIVACY
)
2115 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
2116 printf(" ShortPreamble");
2117 if (capa
& WLAN_CAPABILITY_PBCC
)
2119 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
2120 printf(" ChannelAgility");
2121 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
2122 printf(" SpectrumMgmt");
2123 if (capa
& WLAN_CAPABILITY_QOS
)
2125 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
2126 printf(" ShortSlotTime");
2127 if (capa
& WLAN_CAPABILITY_APSD
)
2129 if (capa
& WLAN_CAPABILITY_RADIO_MEASURE
)
2130 printf(" RadioMeasure");
2131 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
2132 printf(" DSSS-OFDM");
2133 if (capa
& WLAN_CAPABILITY_DEL_BACK
)
2134 printf(" DelayedBACK");
2135 if (capa
& WLAN_CAPABILITY_IMM_BACK
)
2136 printf(" ImmediateBACK");
2139 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
2141 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
2142 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
2143 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
2144 char mac_addr
[20], dev
[20];
2145 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
2146 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
2147 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
2148 [NL80211_BSS_BSSID
] = { },
2149 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
2150 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
2151 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
2152 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
2153 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
2154 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
2155 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
2156 [NL80211_BSS_BEACON_IES
] = { },
2158 struct scan_params
*params
= arg
;
2159 int show
= params
->show_both_ie_sets
? 2 : 1;
2160 bool is_dmg
= false;
2162 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
2163 genlmsg_attrlen(gnlh
, 0), NULL
);
2165 if (!tb
[NL80211_ATTR_BSS
]) {
2166 fprintf(stderr
, "bss info missing!\n");
2169 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
2170 tb
[NL80211_ATTR_BSS
],
2172 fprintf(stderr
, "failed to parse nested attributes!\n");
2176 if (!bss
[NL80211_BSS_BSSID
])
2179 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
2180 printf("BSS %s", mac_addr
);
2181 if (tb
[NL80211_ATTR_IFINDEX
]) {
2182 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
2183 printf("(on %s)", dev
);
2186 if (bss
[NL80211_BSS_STATUS
]) {
2187 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
2188 case NL80211_BSS_STATUS_AUTHENTICATED
:
2189 printf(" -- authenticated");
2191 case NL80211_BSS_STATUS_ASSOCIATED
:
2192 printf(" -- associated");
2194 case NL80211_BSS_STATUS_IBSS_JOINED
:
2195 printf(" -- joined");
2198 printf(" -- unknown status: %d",
2199 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
2205 if (bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]) {
2206 unsigned long long bt
;
2207 bt
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]);
2208 printf("\tlast seen: %llu.%.3llus [boottime]\n", bt
/1000000000, (bt
%1000000000)/1000000);
2211 if (bss
[NL80211_BSS_TSF
]) {
2212 unsigned long long tsf
;
2213 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
2214 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
2215 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
2216 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
2218 if (bss
[NL80211_BSS_FREQUENCY
]) {
2219 int freq
= nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]);
2220 printf("\tfreq: %d\n", freq
);
2224 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
2225 printf("\tbeacon interval: %d TUs\n",
2226 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
2227 if (bss
[NL80211_BSS_CAPABILITY
]) {
2228 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
2229 printf("\tcapability:");
2231 print_capa_dmg(capa
);
2233 print_capa_non_dmg(capa
);
2234 printf(" (0x%.4x)\n", capa
);
2236 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
2237 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
2238 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
2240 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
2241 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
2242 printf("\tsignal: %d/100\n", s
);
2244 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
2245 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
2246 printf("\tlast seen: %d ms ago\n", age
);
2249 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
2250 struct nlattr
*ies
= bss
[NL80211_BSS_INFORMATION_ELEMENTS
];
2251 struct nlattr
*bcnies
= bss
[NL80211_BSS_BEACON_IES
];
2253 if (bss
[NL80211_BSS_PRESP_DATA
] ||
2254 (bcnies
&& (nla_len(ies
) != nla_len(bcnies
) ||
2255 memcmp(nla_data(ies
), nla_data(bcnies
),
2257 printf("\tInformation elements from Probe Response "
2259 print_ies(nla_data(ies
), nla_len(ies
),
2260 params
->unknown
, params
->type
);
2262 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
2263 printf("\tInformation elements from Beacon frame:\n");
2264 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
2265 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
2266 params
->unknown
, params
->type
);
2272 static struct scan_params scan_params
;
2274 static int handle_scan_dump(struct nl80211_state
*state
,
2276 int argc
, char **argv
,
2282 memset(&scan_params
, 0, sizeof(scan_params
));
2284 if (argc
== 1 && !strcmp(argv
[0], "-u"))
2285 scan_params
.unknown
= true;
2286 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
2287 scan_params
.show_both_ie_sets
= true;
2289 scan_params
.type
= PRINT_SCAN
;
2291 register_handler(print_bss_handler
, &scan_params
);
2295 static int handle_scan_combined(struct nl80211_state
*state
,
2297 int argc
, char **argv
,
2301 static char *dump_argv
[] = {
2307 static const __u32 cmds
[] = {
2308 NL80211_CMD_NEW_SCAN_RESULTS
,
2309 NL80211_CMD_SCAN_ABORTED
,
2311 int trig_argc
, dump_argc
, err
;
2314 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
2316 dump_argv
[3] = "-u";
2317 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
2319 dump_argv
[3] = "-b";
2323 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
2324 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
2327 trig_argv
[0] = argv
[0];
2328 trig_argv
[1] = "scan";
2329 trig_argv
[2] = "trigger";
2331 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
2332 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
2333 err
= handle_cmd(state
, id
, trig_argc
, trig_argv
);
2339 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
2341 * This code has a bug, which requires creating a separate
2342 * nl80211 socket to fix:
2343 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
2344 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
2345 * before (!) we listen to it, because we only start listening
2346 * after we send our scan request.
2348 * Doing it the other way around has a race condition as well,
2349 * if you first open the events socket you may get a notification
2350 * for a previous scan.
2352 * The only proper way to fix this would be to listen to events
2353 * before sending the command, and for the kernel to send the
2354 * scan request along with the event, so that you can match up
2355 * whether the scan you requested was finished or aborted (this
2356 * may result in processing a scan that another application
2357 * requested, but that doesn't seem to be a problem).
2359 * Alas, the kernel doesn't do that (yet).
2362 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
2363 NL80211_CMD_SCAN_ABORTED
) {
2364 printf("scan aborted!\n");
2368 dump_argv
[0] = argv
[0];
2369 return handle_cmd(state
, id
, dump_argc
, dump_argv
);
2371 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,
2372 CIB_NETDEV
, handle_scan_combined
,
2373 "Scan on the given frequencies and probe for the given SSIDs\n"
2374 "(or wildcard if not given) unless passive scanning is requested.\n"
2375 "If -u is specified print unknown data in the scan results.\n"
2376 "Specified (vendor) IEs must be well-formed.");
2377 COMMAND(scan
, dump
, "[-u]",
2378 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
2379 "Dump the current scan results. If -u is specified, print unknown\n"
2380 "data in scan results.");
2381 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]",
2382 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
2383 "Trigger a scan on the given frequencies with probing for the given\n"
2384 "SSIDs (or wildcard if not given) unless passive scanning is requested.\n"
2385 "Duration(in TUs), if specified, will be used to set dwell times.\n");
2388 static int handle_scan_abort(struct nl80211_state
*state
,
2390 int argc
, char **argv
,
2395 COMMAND(scan
, abort
, "",
2396 NL80211_CMD_ABORT_SCAN
, 0, CIB_NETDEV
, handle_scan_abort
,
2397 "Abort ongoing scan");
2399 static int handle_start_sched_scan(struct nl80211_state
*state
,
2401 int argc
, char **argv
, enum id_input id
)
2403 return parse_sched_scan(msg
, &argc
, &argv
);
2406 static int handle_stop_sched_scan(struct nl80211_state
*state
,
2407 struct nl_msg
*msg
, int argc
, char **argv
,
2416 COMMAND(scan
, sched_start
,
2418 NL80211_CMD_START_SCHED_SCAN
, 0, CIB_NETDEV
, handle_start_sched_scan
,
2419 "Start a scheduled scan at the specified interval on the given frequencies\n"
2420 "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2421 "scanning is requested. If matches are specified, only matching results\n"
2422 "will be returned.");
2423 COMMAND(scan
, sched_stop
, "",
2424 NL80211_CMD_STOP_SCHED_SCAN
, 0, CIB_NETDEV
, handle_stop_sched_scan
,
2425 "Stop an ongoing scheduled scan.");