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
;
417 bool passive
= false, have_ssids
= false, have_freqs
= false;
418 size_t ies_len
= 0, meshid_len
= 0;
419 unsigned char *ies
= NULL
, *meshid
= NULL
, *tmpies
;
420 unsigned int flags
= 0;
422 ssids
= nlmsg_alloc();
426 freqs
= nlmsg_alloc();
432 for (i
= 0; i
< argc
; i
++) {
435 if (strcmp(argv
[i
], "freq") == 0) {
439 } else if (strcmp(argv
[i
], "ies") == 0) {
442 } else if (strcmp(argv
[i
], "lowpri") == 0) {
443 flags
|= NL80211_SCAN_FLAG_LOW_PRIORITY
;
445 } else if (strcmp(argv
[i
], "flush") == 0) {
446 flags
|= NL80211_SCAN_FLAG_FLUSH
;
448 } else if (strcmp(argv
[i
], "ap-force") == 0) {
449 flags
|= NL80211_SCAN_FLAG_AP
;
451 } else if (strncmp(argv
[i
], "randomise", 9) == 0 ||
452 strncmp(argv
[i
], "randomize", 9) == 0) {
453 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
454 err
= parse_random_mac_addr(msg
, argv
[i
]);
456 goto nla_put_failure
;
458 } else if (strcmp(argv
[i
], "ssid") == 0) {
462 } else if (strcmp(argv
[i
], "passive") == 0) {
466 } else if (strcmp(argv
[i
], "meshid") == 0) {
475 freq
= strtoul(argv
[i
], &eptr
, 10);
476 if (eptr
!= argv
[i
] + strlen(argv
[i
])) {
477 /* failed to parse as number -- maybe a tag? */
482 NLA_PUT_U32(freqs
, i
, freq
);
485 ies
= parse_hex(argv
[i
], &ies_len
);
487 goto nla_put_failure
;
491 NLA_PUT(ssids
, i
, strlen(argv
[i
]), argv
[i
]);
494 meshid_len
= strlen(argv
[i
]);
495 meshid
= (unsigned char *) malloc(meshid_len
+ 2);
497 goto nla_put_failure
;
498 meshid
[0] = 114; /* mesh element id */
499 meshid
[1] = meshid_len
;
500 memcpy(&meshid
[2], argv
[i
], meshid_len
);
508 tmpies
= (unsigned char *) malloc(ies_len
+ meshid_len
);
512 goto nla_put_failure
;
515 memcpy(tmpies
, ies
, ies_len
);
519 memcpy(&tmpies
[ies_len
], meshid
, meshid_len
);
522 if (nla_put(msg
, NL80211_ATTR_IE
, ies_len
+ meshid_len
, tmpies
) < 0) {
524 goto nla_put_failure
;
530 NLA_PUT(ssids
, 1, 0, "");
532 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
535 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
537 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
546 static void tab_on_first(bool *first
)
554 static void print_ssid(const uint8_t type
, uint8_t len
, const uint8_t *data
)
557 print_ssid_escaped(len
, data
);
561 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
562 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
564 static void print_supprates(const uint8_t type
, uint8_t len
, const uint8_t *data
)
570 for (i
= 0; i
< len
; i
++) {
571 int r
= data
[i
] & 0x7f;
573 if (r
== BSS_MEMBERSHIP_SELECTOR_VHT_PHY
&& data
[i
] & 0x80)
575 else if (r
== BSS_MEMBERSHIP_SELECTOR_HT_PHY
&& data
[i
] & 0x80)
578 printf("%d.%d", r
/2, 5*(r
&1));
580 printf("%s ", data
[i
] & 0x80 ? "*" : "");
585 static void print_ds(const uint8_t type
, uint8_t len
, const uint8_t *data
)
587 printf(" channel %d\n", data
[0]);
590 static const char *country_env_str(char environment
)
592 switch (environment
) {
594 return "Indoor only";
596 return "Outdoor only";
598 return "Indoor/Outdoor";
604 static void print_country(const uint8_t type
, uint8_t len
, const uint8_t *data
)
606 printf(" %.*s", 2, data
);
608 printf("\tEnvironment: %s\n", country_env_str(data
[2]));
614 printf("\t\tNo country IE triplets present\n");
620 union ieee80211_country_ie_triplet
*triplet
= (void *) data
;
622 if (triplet
->ext
.reg_extension_id
>= IEEE80211_COUNTRY_EXTENSION_ID
) {
623 printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
624 triplet
->ext
.reg_extension_id
,
625 triplet
->ext
.reg_class
,
626 triplet
->ext
.coverage_class
,
627 triplet
->ext
.coverage_class
* 450);
635 if (triplet
->chans
.first_channel
<= 14)
636 end_channel
= triplet
->chans
.first_channel
+ (triplet
->chans
.num_channels
- 1);
638 end_channel
= triplet
->chans
.first_channel
+ (4 * (triplet
->chans
.num_channels
- 1));
640 printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet
->chans
.first_channel
, end_channel
, triplet
->chans
.max_power
);
649 static void print_powerconstraint(const uint8_t type
, uint8_t len
, const uint8_t *data
)
651 printf(" %d dB\n", data
[0]);
654 static void print_tpcreport(const uint8_t type
, uint8_t len
, const uint8_t *data
)
656 printf(" TX power: %d dBm\n", data
[0]);
657 /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
660 static void print_erp(const uint8_t type
, uint8_t len
, const uint8_t *data
)
663 printf(" <no flags>");
665 printf(" NonERP_Present");
667 printf(" Use_Protection");
669 printf(" Barker_Preamble_Mode");
673 static void print_cipher(const uint8_t *data
)
675 if (memcmp(data
, ms_oui
, 3) == 0) {
678 printf("Use group cipher suite");
693 printf("%.02x-%.02x-%.02x:%d",
694 data
[0], data
[1] ,data
[2], data
[3]);
697 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
700 printf("Use group cipher suite");
715 printf("AES-128-CMAC");
724 printf("%.02x-%.02x-%.02x:%d",
725 data
[0], data
[1] ,data
[2], data
[3]);
729 printf("%.02x-%.02x-%.02x:%d",
730 data
[0], data
[1] ,data
[2], data
[3]);
733 static void print_auth(const uint8_t *data
)
735 if (memcmp(data
, ms_oui
, 3) == 0) {
738 printf("IEEE 802.1X");
744 printf("%.02x-%.02x-%.02x:%d",
745 data
[0], data
[1] ,data
[2], data
[3]);
748 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
751 printf("IEEE 802.1X");
757 printf("FT/IEEE 802.1X");
763 printf("IEEE 802.1X/SHA-256");
766 printf("PSK/SHA-256");
772 printf("%.02x-%.02x-%.02x:%d",
773 data
[0], data
[1] ,data
[2], data
[3]);
776 } else if (memcmp(data
, wfa_oui
, 3) == 0) {
782 printf("%.02x-%.02x-%.02x:%d",
783 data
[0], data
[1] ,data
[2], data
[3]);
787 printf("%.02x-%.02x-%.02x:%d",
788 data
[0], data
[1] ,data
[2], data
[3]);
791 static void _print_rsn_ie(const char *defcipher
, const char *defauth
,
792 uint8_t len
, const uint8_t *data
, int is_osen
)
800 version
= data
[0] + (data
[1] << 8);
801 tab_on_first(&first
);
802 printf("\t * Version: %d\n", version
);
809 tab_on_first(&first
);
810 printf("\t * Group cipher: %s\n", defcipher
);
811 printf("\t * Pairwise ciphers: %s\n", defcipher
);
815 tab_on_first(&first
);
816 printf("\t * Group cipher: ");
824 tab_on_first(&first
);
825 printf("\t * Pairwise ciphers: %s\n", defcipher
);
829 count
= data
[0] | (data
[1] << 8);
830 if (2 + (count
* 4) > len
)
833 tab_on_first(&first
);
834 printf("\t * Pairwise ciphers:");
835 for (i
= 0; i
< count
; i
++) {
837 print_cipher(data
+ 2 + (i
* 4));
841 data
+= 2 + (count
* 4);
842 len
-= 2 + (count
* 4);
845 tab_on_first(&first
);
846 printf("\t * Authentication suites: %s\n", defauth
);
850 count
= data
[0] | (data
[1] << 8);
851 if (2 + (count
* 4) > len
)
854 tab_on_first(&first
);
855 printf("\t * Authentication suites:");
856 for (i
= 0; i
< count
; i
++) {
858 print_auth(data
+ 2 + (i
* 4));
862 data
+= 2 + (count
* 4);
863 len
-= 2 + (count
* 4);
866 capa
= data
[0] | (data
[1] << 8);
867 tab_on_first(&first
);
868 printf("\t * Capabilities:");
872 printf(" NoPairwise");
873 switch ((capa
& 0x000c) >> 2) {
875 printf(" 1-PTKSA-RC");
878 printf(" 2-PTKSA-RC");
881 printf(" 4-PTKSA-RC");
884 printf(" 16-PTKSA-RC");
887 switch ((capa
& 0x0030) >> 4) {
889 printf(" 1-GTKSA-RC");
892 printf(" 2-GTKSA-RC");
895 printf(" 4-GTKSA-RC");
898 printf(" 16-GTKSA-RC");
902 printf(" MFP-required");
904 printf(" MFP-capable");
906 printf(" Peerkey-enabled");
908 printf(" SPP-AMSDU-capable");
910 printf(" SPP-AMSDU-required");
911 printf(" (0x%.4x)\n", capa
);
917 int pmkid_count
= data
[0] | (data
[1] << 8);
919 if (len
>= 2 + 16 * pmkid_count
) {
920 tab_on_first(&first
);
921 printf("\t * %d PMKIDs\n", pmkid_count
);
922 /* not printing PMKID values */
923 data
+= 2 + 16 * pmkid_count
;
924 len
-= 2 + 16 * pmkid_count
;
930 tab_on_first(&first
);
931 printf("\t * Group mgmt cipher suite: ");
940 printf("\t\t * bogus tail data (%d):", len
);
942 printf(" %.2x", *data
);
950 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
951 uint8_t len
, const uint8_t *data
)
953 _print_rsn_ie(defcipher
, defauth
, len
, data
, 0);
956 static void print_osen_ie(const char *defcipher
, const char *defauth
,
957 uint8_t len
, const uint8_t *data
)
960 _print_rsn_ie(defcipher
, defauth
, len
, data
, 1);
963 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
)
965 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
968 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
971 print_ht_capability(data
[0] | (data
[1] << 8));
972 print_ampdu_length(data
[2] & 3);
973 print_ampdu_spacing((data
[2] >> 2) & 7);
974 print_ht_mcs(data
+ 3);
977 static const char* ntype_11u(uint8_t t
)
980 case 0: return "Private";
981 case 1: return "Private with Guest";
982 case 2: return "Chargeable Public";
983 case 3: return "Free Public";
984 case 4: return "Personal Device";
985 case 5: return "Emergency Services Only";
986 case 14: return "Test or Experimental";
987 case 15: return "Wildcard";
988 default: return "Reserved";
992 static const char* vgroup_11u(uint8_t t
)
995 case 0: return "Unspecified";
996 case 1: return "Assembly";
997 case 2: return "Business";
998 case 3: return "Educational";
999 case 4: return "Factory and Industrial";
1000 case 5: return "Institutional";
1001 case 6: return "Mercantile";
1002 case 7: return "Residential";
1003 case 8: return "Storage";
1004 case 9: return "Utility and Miscellaneous";
1005 case 10: return "Vehicular";
1006 case 11: return "Outdoor";
1007 default: return "Reserved";
1011 static void print_interworking(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1013 /* See Section 7.3.2.92 in the 802.11u spec. */
1016 uint8_t ano
= data
[0];
1017 printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano
));
1018 printf("\t\t\tNetwork Type: %i (%s)\n",
1019 (int)(ano
& 0xf), ntype_11u(ano
& 0xf));
1021 printf("\t\t\tInternet\n");
1023 printf("\t\t\tASRA\n");
1025 printf("\t\t\tESR\n");
1027 printf("\t\t\tUESA\n");
1029 if ((len
== 3) || (len
== 9)) {
1030 printf("\t\tVenue Group: %i (%s)\n",
1031 (int)(data
[1]), vgroup_11u(data
[1]));
1032 printf("\t\tVenue Type: %i\n", (int)(data
[2]));
1035 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
1036 data
[3], data
[4], data
[5], data
[6], data
[7], data
[8]);
1038 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
1039 data
[1], data
[2], data
[3], data
[4], data
[5], data
[6]);
1042 static void print_11u_advert(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1044 /* See Section 7.3.2.93 in the 802.11u spec. */
1045 /* TODO: This code below does not decode private protocol IDs */
1048 while (idx
< (len
- 1)) {
1049 uint8_t qri
= data
[idx
];
1050 uint8_t proto_id
= data
[idx
+ 1];
1051 printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri
));
1052 printf("\t\t\tQuery Response Length Limit: %i\n",
1055 printf("\t\t\tPAME-BI\n");
1058 printf("\t\t\tANQP\n"); break;
1060 printf("\t\t\tMIH Information Service\n"); break;
1062 printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
1064 printf("\t\t\tEmergency Alert System (EAS)\n"); break;
1066 printf("\t\t\tVendor Specific\n"); break;
1068 printf("\t\t\tReserved: %i\n", proto_id
); break;
1074 static void print_11u_rcon(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1076 /* See Section 7.3.2.96 in the 802.11u spec. */
1078 int ln0
= data
[1] & 0xf;
1079 int ln1
= ((data
[1] & 0xf0) >> 4);
1084 ln2
= len
- 2 - ln0
- ln1
;
1086 printf("\t\tANQP OIs: %i\n", data
[0]);
1089 printf("\t\tOI 1: ");
1090 if (2 + ln0
> len
) {
1091 printf("Invalid IE length.\n");
1093 for (idx
= 0; idx
< ln0
; idx
++) {
1094 printf("%02hx", data
[2 + idx
]);
1101 printf("\t\tOI 2: ");
1102 if (2 + ln0
+ ln1
> len
) {
1103 printf("Invalid IE length.\n");
1105 for (idx
= 0; idx
< ln1
; idx
++) {
1106 printf("%02hx", data
[2 + ln0
+ idx
]);
1113 printf("\t\tOI 3: ");
1114 if (2 + ln0
+ ln1
+ ln2
> len
) {
1115 printf("Invalid IE length.\n");
1117 for (idx
= 0; idx
< ln2
; idx
++) {
1118 printf("%02hx", data
[2 + ln0
+ ln1
+ idx
]);
1125 static const char *ht_secondary_offset
[4] = {
1132 static void print_ht_op(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1134 static const char *protection
[4] = {
1140 static const char *sta_chan_width
[2] = {
1146 printf("\t\t * primary channel: %d\n", data
[0]);
1147 printf("\t\t * secondary channel offset: %s\n",
1148 ht_secondary_offset
[data
[1] & 0x3]);
1149 printf("\t\t * STA channel width: %s\n", sta_chan_width
[(data
[1] & 0x4)>>2]);
1150 printf("\t\t * RIFS: %d\n", (data
[1] & 0x8)>>3);
1151 printf("\t\t * HT protection: %s\n", protection
[data
[2] & 0x3]);
1152 printf("\t\t * non-GF present: %d\n", (data
[2] & 0x4) >> 2);
1153 printf("\t\t * OBSS non-GF present: %d\n", (data
[2] & 0x10) >> 4);
1154 printf("\t\t * dual beacon: %d\n", (data
[4] & 0x40) >> 6);
1155 printf("\t\t * dual CTS protection: %d\n", (data
[4] & 0x80) >> 7);
1156 printf("\t\t * STBC beacon: %d\n", data
[5] & 0x1);
1157 printf("\t\t * L-SIG TXOP Prot: %d\n", (data
[5] & 0x2) >> 1);
1158 printf("\t\t * PCO active: %d\n", (data
[5] & 0x4) >> 2);
1159 printf("\t\t * PCO phase: %d\n", (data
[5] & 0x8) >> 3);
1162 static void print_capabilities(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1168 for (i
= 0; i
< len
; i
++) {
1171 for (bit
= 0; bit
< 8; bit
++) {
1172 if (!(data
[i
] & (1 << bit
)))
1180 #define CAPA(bit, name) case bit: printf(" " name); break
1182 switch (bit
+ base
) {
1183 CAPA(0, "HT Information Exchange Supported");
1184 CAPA(1, "reserved (On-demand Beacon)");
1185 CAPA(2, "Extended Channel Switching");
1186 CAPA(3, "reserved (Wave Indication)");
1187 CAPA(4, "PSMP Capability");
1188 CAPA(5, "reserved (Service Interval Granularity)");
1189 CAPA(6, "S-PSMP Capability");
1191 CAPA(8, "Diagnostics");
1192 CAPA(9, "Multicast Diagnostics");
1193 CAPA(10, "Location Tracking");
1195 CAPA(12, "Proxy ARP Service");
1196 CAPA(13, "Collocated Interference Reporting");
1197 CAPA(14, "Civic Location");
1198 CAPA(15, "Geospatial Location");
1200 CAPA(17, "WNM-Sleep Mode");
1201 CAPA(18, "TIM Broadcast");
1202 CAPA(19, "BSS Transition");
1203 CAPA(20, "QoS Traffic Capability");
1204 CAPA(21, "AC Station Count");
1205 CAPA(22, "Multiple BSSID");
1206 CAPA(23, "Timing Measurement");
1207 CAPA(24, "Channel Usage");
1208 CAPA(25, "SSID List");
1210 CAPA(27, "UTC TSF Offset");
1211 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1212 CAPA(29, "TDLS Peer PSM Support");
1213 CAPA(30, "TDLS channel switching");
1214 CAPA(31, "Interworking");
1215 CAPA(32, "QoS Map");
1217 CAPA(34, "SSPN Interface");
1218 CAPA(35, "Reserved");
1219 CAPA(36, "MSGCF Capability");
1220 CAPA(37, "TDLS Support");
1221 CAPA(38, "TDLS Prohibited");
1222 CAPA(39, "TDLS Channel Switching Prohibited");
1223 CAPA(40, "Reject Unadmitted Frame");
1224 CAPA(44, "Identifier Location");
1225 CAPA(45, "U-APSD Coexistence");
1226 CAPA(46, "WNM-Notification");
1227 CAPA(47, "Reserved");
1228 CAPA(48, "UTF-8 SSID");
1229 CAPA(70, "FTM Responder");
1230 CAPA(71, "FTM Initiator");
1242 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1244 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1246 data
[0], data
[1], data
[2], data
[3]);
1248 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
1252 static void print_ibssatim(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1254 printf(" %d TUs", (data
[1] << 8) + data
[0]);
1257 static void print_vht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1260 print_vht_info(data
[0] | (data
[1] << 8) |
1261 (data
[2] << 16) | (data
[3] << 24),
1265 static void print_vht_oper(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1267 const char *chandwidths
[] = {
1268 [0] = "20 or 40 MHz",
1275 printf("\t\t * channel width: %d (%s)\n", data
[0],
1276 data
[0] < ARRAY_SIZE(chandwidths
) ? chandwidths
[data
[0]] : "unknown");
1277 printf("\t\t * center freq segment 1: %d\n", data
[1]);
1278 printf("\t\t * center freq segment 2: %d\n", data
[2]);
1279 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data
[4], data
[3]);
1282 static void print_obss_scan_params(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1285 printf("\t\t * passive dwell: %d TUs\n", (data
[1] << 8) | data
[0]);
1286 printf("\t\t * active dwell: %d TUs\n", (data
[3] << 8) | data
[2]);
1287 printf("\t\t * channel width trigger scan interval: %d s\n", (data
[5] << 8) | data
[4]);
1288 printf("\t\t * scan passive total per channel: %d TUs\n", (data
[7] << 8) | data
[6]);
1289 printf("\t\t * scan active total per channel: %d TUs\n", (data
[9] << 8) | data
[8]);
1290 printf("\t\t * BSS width channel transition delay factor: %d\n", (data
[11] << 8) | data
[10]);
1291 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1292 ((data
[13] << 8) | data
[12]) / 100, ((data
[13] << 8) | data
[12]) % 100);
1295 static void print_secchan_offs(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1297 if (data
[0] < ARRAY_SIZE(ht_secondary_offset
))
1298 printf(" %s (%d)\n", ht_secondary_offset
[data
[0]], data
[0]);
1300 printf(" %d\n", data
[0]);
1303 static void print_bss_load(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1306 printf("\t\t * station count: %d\n", (data
[1] << 8) | data
[0]);
1307 printf("\t\t * channel utilisation: %d/255\n", data
[2]);
1308 printf("\t\t * available admission capacity: %d [*32us]\n", (data
[4] << 8) | data
[3]);
1311 static void print_mesh_conf(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1314 printf("\t\t * Active Path Selection Protocol ID: %d\n", data
[0]);
1315 printf("\t\t * Active Path Selection Metric ID: %d\n", data
[1]);
1316 printf("\t\t * Congestion Control Mode ID: %d\n", data
[2]);
1317 printf("\t\t * Synchronization Method ID: %d\n", data
[3]);
1318 printf("\t\t * Authentication Protocol ID: %d\n", data
[4]);
1319 printf("\t\t * Mesh Formation Info:\n");
1320 printf("\t\t\t Number of Peerings: %d\n", (data
[5] & 0x7E) >> 1);
1322 printf("\t\t\t Connected to Mesh Gate\n");
1324 printf("\t\t\t Connected to AS\n");
1325 printf("\t\t * Mesh Capability\n");
1327 printf("\t\t\t Accepting Additional Mesh Peerings\n");
1329 printf("\t\t\t MCCA Supported\n");
1331 printf("\t\t\t MCCA Enabled\n");
1333 printf("\t\t\t Forwarding\n");
1335 printf("\t\t\t MBCA Supported\n");
1337 printf("\t\t\t TBTT Adjusting\n");
1339 printf("\t\t\t Mesh Power Save Level\n");
1344 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
);
1345 uint8_t minlen
, maxlen
;
1349 static void print_ie(const struct ie_print
*p
, const uint8_t type
,
1350 uint8_t len
, const uint8_t *data
)
1357 printf("\t%s:", p
->name
);
1358 if (len
< p
->minlen
|| len
> p
->maxlen
) {
1360 printf(" <invalid: %d bytes:", len
);
1361 for (i
= 0; i
< len
; i
++)
1362 printf(" %.02x", data
[i
]);
1365 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
1367 printf(" <invalid: no data>\n");
1371 p
->print(type
, len
, data
);
1374 #define PRINT_IGN { \
1381 static const struct ie_print ieprinters
[] = {
1382 [0] = { "SSID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1383 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1384 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
1385 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
1386 [6] = { "IBSS ATIM window", print_ibssatim
, 2, 2, BIT(PRINT_SCAN
), },
1387 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
1388 [11] = { "BSS Load", print_bss_load
, 5, 5, BIT(PRINT_SCAN
), },
1389 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
1390 [35] = { "TPC report", print_tpcreport
, 2, 2, BIT(PRINT_SCAN
), },
1391 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1392 [45] = { "HT capabilities", print_ht_capa
, 26, 26, BIT(PRINT_SCAN
), },
1393 [47] = { "ERP D4.0", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1394 [74] = { "Overlapping BSS scan params", print_obss_scan_params
, 14, 255, BIT(PRINT_SCAN
), },
1395 [61] = { "HT operation", print_ht_op
, 22, 22, BIT(PRINT_SCAN
), },
1396 [62] = { "Secondary Channel Offset", print_secchan_offs
, 1, 1, BIT(PRINT_SCAN
), },
1397 [191] = { "VHT capabilities", print_vht_capa
, 12, 255, BIT(PRINT_SCAN
), },
1398 [192] = { "VHT operation", print_vht_oper
, 5, 255, BIT(PRINT_SCAN
), },
1399 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
1400 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1401 [113] = { "MESH Configuration", print_mesh_conf
, 7, 7, BIT(PRINT_SCAN
), },
1402 [114] = { "MESH ID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1403 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
1404 [107] = { "802.11u Interworking", print_interworking
, 0, 255, BIT(PRINT_SCAN
), },
1405 [108] = { "802.11u Advertisement", print_11u_advert
, 0, 255, BIT(PRINT_SCAN
), },
1406 [111] = { "802.11u Roaming Consortium", print_11u_rcon
, 0, 255, BIT(PRINT_SCAN
), },
1409 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1411 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
1414 static void print_wifi_osen(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1416 print_osen_ie("OSEN", "OSEN", len
, data
);
1419 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
1422 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
1428 printf("Parameter: not version 1: ");
1432 printf("\t * Parameter version 1");
1437 printf("\n\t\t * u-APSD");
1441 for (i
= 0; i
< 4; i
++) {
1442 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
1445 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
1446 (1 << (data
[1] >> 4)) - 1);
1447 printf(", AIFSN %d", data
[0] & 0xf);
1448 if (data
[2] | data
[3])
1449 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
1457 printf("invalid: ");
1461 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1467 printf(" information:");
1470 if (print_wifi_wmm_param(data
+ 1, len
- 1))
1474 printf(" type %d:", data
[0]);
1478 for(i
= 1; i
< len
; i
++)
1479 printf(" %.02x", data
[i
]);
1483 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
1487 return "Default (PIN)";
1489 return "User-specified";
1491 return "Machine-specified";
1495 return "PushButton";
1497 return "Registrar-specified";
1503 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1506 __u16 subtype
, sublen
;
1509 subtype
= (data
[0] << 8) + data
[1];
1510 sublen
= (data
[2] << 8) + data
[3];
1516 tab_on_first(&first
);
1517 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
1520 tab_on_first(&first
);
1521 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
1525 tab_on_first(&first
);
1527 printf("\t * Device Password ID: (invalid "
1528 "length %d)\n", sublen
);
1531 id
= data
[4] << 8 | data
[5];
1532 printf("\t * Device Password ID: %u (%s)\n",
1533 id
, wifi_wps_dev_passwd_id(id
));
1537 tab_on_first(&first
);
1538 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
1541 tab_on_first(&first
);
1542 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
1545 tab_on_first(&first
);
1546 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
1550 tab_on_first(&first
);
1551 printf("\t * Response Type: %d%s\n",
1552 val
, val
== 3 ? " (AP)" : "");
1557 tab_on_first(&first
);
1558 printf("\t * RF Bands: 0x%x\n", val
);
1563 tab_on_first(&first
);
1564 printf("\t * Selected Registrar: 0x%x\n", val
);
1568 tab_on_first(&first
);
1569 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
1573 tab_on_first(&first
);
1574 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1576 val
== 1 ? " (Unconfigured)" : "",
1577 val
== 2 ? " (Configured)" : "");
1581 tab_on_first(&first
);
1582 printf("\t * UUID: ");
1584 printf("(invalid, length=%d)\n", sublen
);
1587 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1588 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1589 data
[4], data
[5], data
[6], data
[7],
1590 data
[8], data
[9], data
[10], data
[11],
1591 data
[12], data
[13], data
[14], data
[15],
1592 data
[16], data
[17], data
[18], data
[19]);
1595 tab_on_first(&first
);
1597 printf("\t * Primary Device Type: (invalid "
1598 "length %d)\n", sublen
);
1601 printf("\t * Primary Device Type: "
1602 "%u-%02x%02x%02x%02x-%u\n",
1603 data
[4] << 8 | data
[5],
1604 data
[6], data
[7], data
[8], data
[9],
1605 data
[10] << 8 | data
[11]);
1610 tab_on_first(&first
);
1611 printf("\t * AP setup locked: 0x%.2x\n", val
);
1616 __u16 meth
= (data
[4] << 8) + data
[5];
1618 tab_on_first(&first
);
1619 printf("\t * %sConfig methods:",
1620 subtype
== 0x1053 ? "Selected Registrar ": "");
1621 #define T(bit, name) do { \
1622 if (meth & (1<<bit)) { \
1642 const __u8
*subdata
= data
+ 4;
1643 __u16 tmplen
= sublen
;
1645 tab_on_first(&first
);
1646 printf("\t * Unknown TLV (%#.4x, %d bytes):",
1649 printf(" %.2x", *subdata
);
1663 printf("\t\t * bogus tail data (%d):", len
);
1665 printf(" %.2x", *data
);
1673 static const struct ie_print wifiprinters
[] = {
1674 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
1675 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
1676 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
1679 static inline void print_p2p(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1687 sublen
= (data
[2] << 8) + data
[1];
1689 if (sublen
> len
- 3)
1693 case 0x02: /* capability */
1694 tab_on_first(&first
);
1696 printf("\t * malformed capability\n");
1699 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
1702 case 0x0d: /* device info */
1703 if (sublen
< 6 + 2 + 8 + 1) {
1704 printf("\t * malformed device info\n");
1707 /* fall through for now */
1708 case 0x00: /* status */
1709 case 0x01: /* minor reason */
1710 case 0x03: /* device ID */
1711 case 0x04: /* GO intent */
1712 case 0x05: /* configuration timeout */
1713 case 0x06: /* listen channel */
1714 case 0x07: /* group BSSID */
1715 case 0x08: /* ext listen timing */
1716 case 0x09: /* intended interface address */
1717 case 0x0a: /* manageability */
1718 case 0x0b: /* channel list */
1719 case 0x0c: /* NoA */
1720 case 0x0e: /* group info */
1721 case 0x0f: /* group ID */
1722 case 0x10: /* interface */
1723 case 0x11: /* operating channel */
1724 case 0x12: /* invitation flags */
1725 case 0xdd: /* vendor specific */
1727 const __u8
*subdata
= data
+ 4;
1728 __u16 tmplen
= sublen
;
1730 tab_on_first(&first
);
1731 printf("\t * Unknown TLV (%#.2x, %d bytes):",
1734 printf(" %.2x", *subdata
);
1748 tab_on_first(&first
);
1749 printf("\t * bogus tail data (%d):", len
);
1751 printf(" %.2x", *data
);
1759 static inline void print_hs20_ind(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1761 /* I can't find the spec for this...just going off what wireshark uses. */
1764 printf("\t\tDGAF: %i\n", (int)(data
[0] & 0x1));
1766 printf("\t\tUnexpected length: %i\n", len
);
1769 static const struct ie_print wfa_printers
[] = {
1770 [9] = { "P2P", print_p2p
, 2, 255, BIT(PRINT_SCAN
), },
1771 [16] = { "HotSpot 2.0 Indication", print_hs20_ind
, 1, 255, BIT(PRINT_SCAN
), },
1772 [18] = { "HotSpot 2.0 OSEN", print_wifi_osen
, 1, 255, BIT(PRINT_SCAN
), },
1775 static void print_vendor(unsigned char len
, unsigned char *data
,
1776 bool unknown
, enum print_ie_type ptype
)
1781 printf("\tVendor specific: <too short> data:");
1782 for(i
= 0; i
< len
; i
++)
1783 printf(" %.02x", data
[i
]);
1788 if (len
>= 4 && memcmp(data
, ms_oui
, 3) == 0) {
1789 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
1790 wifiprinters
[data
[3]].name
&&
1791 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
1792 print_ie(&wifiprinters
[data
[3]], data
[3], len
- 4, data
+ 4);
1797 printf("\tMS/WiFi %#.2x, data:", data
[3]);
1798 for(i
= 0; i
< len
- 4; i
++)
1799 printf(" %.02x", data
[i
+ 4]);
1804 if (len
>= 4 && memcmp(data
, wfa_oui
, 3) == 0) {
1805 if (data
[3] < ARRAY_SIZE(wfa_printers
) &&
1806 wfa_printers
[data
[3]].name
&&
1807 wfa_printers
[data
[3]].flags
& BIT(ptype
)) {
1808 print_ie(&wfa_printers
[data
[3]], data
[3], len
- 4, data
+ 4);
1813 printf("\tWFA %#.2x, data:", data
[3]);
1814 for(i
= 0; i
< len
- 4; i
++)
1815 printf(" %.02x", data
[i
+ 4]);
1823 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
1824 data
[0], data
[1], data
[2]);
1825 for (i
= 3; i
< len
; i
++)
1826 printf(" %.2x", data
[i
]);
1830 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
1831 enum print_ie_type ptype
)
1833 while (ielen
>= 2 && ielen
>= ie
[1]) {
1834 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
1835 ieprinters
[ie
[0]].name
&&
1836 ieprinters
[ie
[0]].flags
& BIT(ptype
)) {
1837 print_ie(&ieprinters
[ie
[0]], ie
[0], ie
[1], ie
+ 2);
1838 } else if (ie
[0] == 221 /* vendor */) {
1839 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
1840 } else if (unknown
) {
1843 printf("\tUnknown IE (%d):", ie
[0]);
1844 for (i
=0; i
<ie
[1]; i
++)
1845 printf(" %.2x", ie
[2+i
]);
1853 static void print_capa_dmg(__u16 capa
)
1855 switch (capa
& WLAN_CAPABILITY_DMG_TYPE_MASK
) {
1856 case WLAN_CAPABILITY_DMG_TYPE_AP
:
1859 case WLAN_CAPABILITY_DMG_TYPE_PBSS
:
1862 case WLAN_CAPABILITY_DMG_TYPE_IBSS
:
1863 printf(" DMG_IBSS");
1867 if (capa
& WLAN_CAPABILITY_DMG_CBAP_ONLY
)
1868 printf(" CBAP_Only");
1869 if (capa
& WLAN_CAPABILITY_DMG_CBAP_SOURCE
)
1870 printf(" CBAP_Src");
1871 if (capa
& WLAN_CAPABILITY_DMG_PRIVACY
)
1873 if (capa
& WLAN_CAPABILITY_DMG_ECPAC
)
1875 if (capa
& WLAN_CAPABILITY_DMG_SPECTRUM_MGMT
)
1876 printf(" SpectrumMgmt");
1877 if (capa
& WLAN_CAPABILITY_DMG_RADIO_MEASURE
)
1878 printf(" RadioMeasure");
1881 static void print_capa_non_dmg(__u16 capa
)
1883 if (capa
& WLAN_CAPABILITY_ESS
)
1885 if (capa
& WLAN_CAPABILITY_IBSS
)
1887 if (capa
& WLAN_CAPABILITY_CF_POLLABLE
)
1888 printf(" CfPollable");
1889 if (capa
& WLAN_CAPABILITY_CF_POLL_REQUEST
)
1890 printf(" CfPollReq");
1891 if (capa
& WLAN_CAPABILITY_PRIVACY
)
1893 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
1894 printf(" ShortPreamble");
1895 if (capa
& WLAN_CAPABILITY_PBCC
)
1897 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
1898 printf(" ChannelAgility");
1899 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
1900 printf(" SpectrumMgmt");
1901 if (capa
& WLAN_CAPABILITY_QOS
)
1903 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
1904 printf(" ShortSlotTime");
1905 if (capa
& WLAN_CAPABILITY_APSD
)
1907 if (capa
& WLAN_CAPABILITY_RADIO_MEASURE
)
1908 printf(" RadioMeasure");
1909 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
1910 printf(" DSSS-OFDM");
1911 if (capa
& WLAN_CAPABILITY_DEL_BACK
)
1912 printf(" DelayedBACK");
1913 if (capa
& WLAN_CAPABILITY_IMM_BACK
)
1914 printf(" ImmediateBACK");
1917 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
1919 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
1920 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
1921 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
1922 char mac_addr
[20], dev
[20];
1923 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
1924 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
1925 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
1926 [NL80211_BSS_BSSID
] = { },
1927 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
1928 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
1929 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
1930 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
1931 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
1932 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
1933 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
1934 [NL80211_BSS_BEACON_IES
] = { },
1936 struct scan_params
*params
= arg
;
1937 int show
= params
->show_both_ie_sets
? 2 : 1;
1938 bool is_dmg
= false;
1940 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
1941 genlmsg_attrlen(gnlh
, 0), NULL
);
1943 if (!tb
[NL80211_ATTR_BSS
]) {
1944 fprintf(stderr
, "bss info missing!\n");
1947 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
1948 tb
[NL80211_ATTR_BSS
],
1950 fprintf(stderr
, "failed to parse nested attributes!\n");
1954 if (!bss
[NL80211_BSS_BSSID
])
1957 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
1958 printf("BSS %s", mac_addr
);
1959 if (tb
[NL80211_ATTR_IFINDEX
]) {
1960 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
1961 printf("(on %s)", dev
);
1964 if (bss
[NL80211_BSS_STATUS
]) {
1965 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
1966 case NL80211_BSS_STATUS_AUTHENTICATED
:
1967 printf(" -- authenticated");
1969 case NL80211_BSS_STATUS_ASSOCIATED
:
1970 printf(" -- associated");
1972 case NL80211_BSS_STATUS_IBSS_JOINED
:
1973 printf(" -- joined");
1976 printf(" -- unknown status: %d",
1977 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
1983 if (bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]) {
1984 unsigned long long bt
;
1985 bt
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]);
1986 printf("\tlast seen: %llu.%.3llus [boottime]\n", bt
/1000000000, (bt
%1000000000)/1000000);
1989 if (bss
[NL80211_BSS_TSF
]) {
1990 unsigned long long tsf
;
1991 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
1992 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
1993 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
1994 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
1996 if (bss
[NL80211_BSS_FREQUENCY
]) {
1997 int freq
= nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]);
1998 printf("\tfreq: %d\n", freq
);
2002 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
2003 printf("\tbeacon interval: %d TUs\n",
2004 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
2005 if (bss
[NL80211_BSS_CAPABILITY
]) {
2006 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
2007 printf("\tcapability:");
2009 print_capa_dmg(capa
);
2011 print_capa_non_dmg(capa
);
2012 printf(" (0x%.4x)\n", capa
);
2014 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
2015 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
2016 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
2018 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
2019 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
2020 printf("\tsignal: %d/100\n", s
);
2022 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
2023 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
2024 printf("\tlast seen: %d ms ago\n", age
);
2027 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
2028 if (bss
[NL80211_BSS_BEACON_IES
])
2029 printf("\tInformation elements from Probe Response "
2031 print_ies(nla_data(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
2032 nla_len(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
2033 params
->unknown
, params
->type
);
2035 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
2036 printf("\tInformation elements from Beacon frame:\n");
2037 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
2038 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
2039 params
->unknown
, params
->type
);
2045 static struct scan_params scan_params
;
2047 static int handle_scan_dump(struct nl80211_state
*state
,
2049 int argc
, char **argv
,
2055 memset(&scan_params
, 0, sizeof(scan_params
));
2057 if (argc
== 1 && !strcmp(argv
[0], "-u"))
2058 scan_params
.unknown
= true;
2059 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
2060 scan_params
.show_both_ie_sets
= true;
2062 scan_params
.type
= PRINT_SCAN
;
2064 register_handler(print_bss_handler
,
2069 static int handle_scan_combined(struct nl80211_state
*state
,
2071 int argc
, char **argv
,
2075 static char *dump_argv
[] = {
2081 static const __u32 cmds
[] = {
2082 NL80211_CMD_NEW_SCAN_RESULTS
,
2083 NL80211_CMD_SCAN_ABORTED
,
2085 int trig_argc
, dump_argc
, err
;
2088 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
2090 dump_argv
[3] = "-u";
2091 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
2093 dump_argv
[3] = "-b";
2097 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
2098 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
2101 trig_argv
[0] = argv
[0];
2102 trig_argv
[1] = "scan";
2103 trig_argv
[2] = "trigger";
2105 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
2106 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
2107 err
= handle_cmd(state
, id
, trig_argc
, trig_argv
);
2113 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
2115 * This code has a bug, which requires creating a separate
2116 * nl80211 socket to fix:
2117 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
2118 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
2119 * before (!) we listen to it, because we only start listening
2120 * after we send our scan request.
2122 * Doing it the other way around has a race condition as well,
2123 * if you first open the events socket you may get a notification
2124 * for a previous scan.
2126 * The only proper way to fix this would be to listen to events
2127 * before sending the command, and for the kernel to send the
2128 * scan request along with the event, so that you can match up
2129 * whether the scan you requested was finished or aborted (this
2130 * may result in processing a scan that another application
2131 * requested, but that doesn't seem to be a problem).
2133 * Alas, the kernel doesn't do that (yet).
2136 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
2137 NL80211_CMD_SCAN_ABORTED
) {
2138 printf("scan aborted!\n");
2142 dump_argv
[0] = argv
[0];
2143 return handle_cmd(state
, id
, dump_argc
, dump_argv
);
2145 TOPLEVEL(scan
, "[-u] [freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]", 0, 0,
2146 CIB_NETDEV
, handle_scan_combined
,
2147 "Scan on the given frequencies and probe for the given SSIDs\n"
2148 "(or wildcard if not given) unless passive scanning is requested.\n"
2149 "If -u is specified print unknown data in the scan results.\n"
2150 "Specified (vendor) IEs must be well-formed.");
2151 COMMAND(scan
, dump
, "[-u]",
2152 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
2153 "Dump the current scan results. If -u is specified, print unknown\n"
2154 "data in scan results.");
2155 COMMAND(scan
, trigger
, "[freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]",
2156 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
2157 "Trigger a scan on the given frequencies with probing for the given\n"
2158 "SSIDs (or wildcard if not given) unless passive scanning is requested.");
2161 static int handle_start_sched_scan(struct nl80211_state
*state
,
2163 int argc
, char **argv
, enum id_input id
)
2165 return parse_sched_scan(msg
, &argc
, &argv
);
2168 static int handle_stop_sched_scan(struct nl80211_state
*state
,
2169 struct nl_msg
*msg
, int argc
, char **argv
,
2178 COMMAND(scan
, sched_start
,
2180 NL80211_CMD_START_SCHED_SCAN
, 0, CIB_NETDEV
, handle_start_sched_scan
,
2181 "Start a scheduled scan at the specified interval on the given frequencies\n"
2182 "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2183 "scanning is requested. If matches are specified, only matching results\n"
2184 "will be returned.");
2185 COMMAND(scan
, sched_stop
, "",
2186 NL80211_CMD_STOP_SCHED_SCAN
, 0, CIB_NETDEV
, handle_stop_sched_scan
,
2187 "Stop an ongoing scheduled scan.");