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 nlattr
*match
= NULL
;
110 } parse_state
= ND_TOPLEVEL
;
112 char *end
, **v
= *argv
;
114 unsigned int freq
, interval
= 0, delay
= 0;
115 bool have_matchset
= false, have_freqs
= false, have_ssids
= false;
116 bool have_active
= false, have_passive
= false;
119 matchset
= nlmsg_alloc();
125 freqs
= nlmsg_alloc();
131 ssids
= nlmsg_alloc();
138 switch (parse_state
) {
140 if (!strcmp(v
[0], "interval")) {
144 goto nla_put_failure
;
149 goto nla_put_failure
;
151 interval
= strtoul(v
[0], &end
, 10);
152 if (*end
|| !interval
) {
154 goto nla_put_failure
;
157 NL80211_ATTR_SCHED_SCAN_INTERVAL
,
159 } else if (!strcmp(v
[0], "delay")) {
163 goto nla_put_failure
;
168 goto nla_put_failure
;
170 delay
= strtoul(v
[0], &end
, 10);
173 goto nla_put_failure
;
176 NL80211_ATTR_SCHED_SCAN_DELAY
,
178 } else if (!strcmp(v
[0], "matches")) {
179 parse_state
= ND_MATCH
;
182 goto nla_put_failure
;
186 } else if (!strcmp(v
[0], "freqs")) {
187 parse_state
= ND_FREQS
;
190 goto nla_put_failure
;
195 } else if (!strcmp(v
[0], "active")) {
196 parse_state
= ND_ACTIVE
;
197 if (have_active
|| have_passive
) {
199 goto nla_put_failure
;
204 } else if (!strcmp(v
[0], "passive")) {
205 if (have_active
|| have_passive
) {
207 goto nla_put_failure
;
211 } else if (!strncmp(v
[0], "randomise", 9) ||
212 !strncmp(v
[0], "randomize", 9)) {
213 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
215 err
= parse_random_mac_addr(msg
, v
[0]);
217 goto nla_put_failure
;
220 /* this element is not for us, so
221 * return to continue parsing.
223 goto nla_put_failure
;
229 if (!strcmp(v
[0], "ssid")) {
233 goto nla_put_failure
;
236 /* TODO: for now we can only have an
237 * SSID in the match, so we can start
238 * the match nest here.
240 match
= nla_nest_start(matchset
, i
);
243 goto nla_put_failure
;
247 NL80211_SCHED_SCAN_MATCH_ATTR_SSID
,
249 nla_nest_end(matchset
, match
);
252 have_matchset
= true;
256 /* other element that cannot be part
257 * of a match indicates the end of the
259 /* need at least one match in the matchset */
262 goto nla_put_failure
;
265 parse_state
= ND_TOPLEVEL
;
270 freq
= strtoul(v
[0], &end
, 10);
274 goto nla_put_failure
;
277 parse_state
= ND_TOPLEVEL
;
279 NLA_PUT_U32(freqs
, i
, freq
);
285 if (!strcmp(v
[0], "ssid")) {
289 goto nla_put_failure
;
293 NL80211_SCHED_SCAN_MATCH_ATTR_SSID
,
300 /* other element that cannot be part
301 * of a match indicates the end of the
303 /* need at least one item in the set */
306 goto nla_put_failure
;
309 parse_state
= ND_TOPLEVEL
;
316 NLA_PUT(ssids
, 1, 0, "");
318 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
320 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
322 nla_put_nested(msg
, NL80211_ATTR_SCHED_SCAN_MATCH
, matchset
);
324 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
328 nla_nest_end(msg
, match
);
330 nlmsg_free(matchset
);
338 static int handle_scan(struct nl80211_state
*state
,
340 int argc
, char **argv
,
343 struct nl_msg
*ssids
= NULL
, *freqs
= NULL
;
356 bool passive
= false, have_ssids
= false, have_freqs
= false;
357 size_t ies_len
= 0, meshid_len
= 0;
358 unsigned char *ies
= NULL
, *meshid
= NULL
, *tmpies
;
359 unsigned int flags
= 0;
361 ssids
= nlmsg_alloc();
365 freqs
= nlmsg_alloc();
371 for (i
= 0; i
< argc
; i
++) {
374 if (strcmp(argv
[i
], "freq") == 0) {
378 } else if (strcmp(argv
[i
], "ies") == 0) {
381 } else if (strcmp(argv
[i
], "lowpri") == 0) {
382 flags
|= NL80211_SCAN_FLAG_LOW_PRIORITY
;
384 } else if (strcmp(argv
[i
], "flush") == 0) {
385 flags
|= NL80211_SCAN_FLAG_FLUSH
;
387 } else if (strcmp(argv
[i
], "ap-force") == 0) {
388 flags
|= NL80211_SCAN_FLAG_AP
;
390 } else if (strncmp(argv
[i
], "randomise", 9) == 0 ||
391 strncmp(argv
[i
], "randomize", 9) == 0) {
392 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
393 err
= parse_random_mac_addr(msg
, argv
[i
]);
395 goto nla_put_failure
;
397 } else if (strcmp(argv
[i
], "ssid") == 0) {
401 } else if (strcmp(argv
[i
], "passive") == 0) {
405 } else if (strcmp(argv
[i
], "meshid") == 0) {
414 freq
= strtoul(argv
[i
], &eptr
, 10);
415 if (eptr
!= argv
[i
] + strlen(argv
[i
])) {
416 /* failed to parse as number -- maybe a tag? */
421 NLA_PUT_U32(freqs
, i
, freq
);
424 ies
= parse_hex(argv
[i
], &ies_len
);
426 goto nla_put_failure
;
430 NLA_PUT(ssids
, i
, strlen(argv
[i
]), argv
[i
]);
433 meshid_len
= strlen(argv
[i
]);
434 meshid
= (unsigned char *) malloc(meshid_len
+ 2);
436 goto nla_put_failure
;
437 meshid
[0] = 114; /* mesh element id */
438 meshid
[1] = meshid_len
;
439 memcpy(&meshid
[2], argv
[i
], meshid_len
);
447 tmpies
= (unsigned char *) malloc(ies_len
+ meshid_len
);
451 goto nla_put_failure
;
454 memcpy(tmpies
, ies
, ies_len
);
458 memcpy(&tmpies
[ies_len
], meshid
, meshid_len
);
461 if (nla_put(msg
, NL80211_ATTR_IE
, ies_len
+ meshid_len
, tmpies
) < 0) {
463 goto nla_put_failure
;
469 NLA_PUT(ssids
, 1, 0, "");
471 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
474 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
476 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
485 static void tab_on_first(bool *first
)
493 static void print_ssid(const uint8_t type
, uint8_t len
, const uint8_t *data
)
496 print_ssid_escaped(len
, data
);
500 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
501 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
503 static void print_supprates(const uint8_t type
, uint8_t len
, const uint8_t *data
)
509 for (i
= 0; i
< len
; i
++) {
510 int r
= data
[i
] & 0x7f;
512 if (r
== BSS_MEMBERSHIP_SELECTOR_VHT_PHY
&& data
[i
] & 0x80)
514 else if (r
== BSS_MEMBERSHIP_SELECTOR_HT_PHY
&& data
[i
] & 0x80)
517 printf("%d.%d", r
/2, 5*(r
&1));
519 printf("%s ", data
[i
] & 0x80 ? "*" : "");
524 static void print_ds(const uint8_t type
, uint8_t len
, const uint8_t *data
)
526 printf(" channel %d\n", data
[0]);
529 static const char *country_env_str(char environment
)
531 switch (environment
) {
533 return "Indoor only";
535 return "Outdoor only";
537 return "Indoor/Outdoor";
543 static void print_country(const uint8_t type
, uint8_t len
, const uint8_t *data
)
545 printf(" %.*s", 2, data
);
547 printf("\tEnvironment: %s\n", country_env_str(data
[2]));
553 printf("\t\tNo country IE triplets present\n");
559 union ieee80211_country_ie_triplet
*triplet
= (void *) data
;
561 if (triplet
->ext
.reg_extension_id
>= IEEE80211_COUNTRY_EXTENSION_ID
) {
562 printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
563 triplet
->ext
.reg_extension_id
,
564 triplet
->ext
.reg_class
,
565 triplet
->ext
.coverage_class
,
566 triplet
->ext
.coverage_class
* 450);
574 if (triplet
->chans
.first_channel
<= 14)
575 end_channel
= triplet
->chans
.first_channel
+ (triplet
->chans
.num_channels
- 1);
577 end_channel
= triplet
->chans
.first_channel
+ (4 * (triplet
->chans
.num_channels
- 1));
579 printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet
->chans
.first_channel
, end_channel
, triplet
->chans
.max_power
);
588 static void print_powerconstraint(const uint8_t type
, uint8_t len
, const uint8_t *data
)
590 printf(" %d dB\n", data
[0]);
593 static void print_tpcreport(const uint8_t type
, uint8_t len
, const uint8_t *data
)
595 printf(" TX power: %d dBm\n", data
[0]);
596 /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
599 static void print_erp(const uint8_t type
, uint8_t len
, const uint8_t *data
)
602 printf(" <no flags>");
604 printf(" NonERP_Present");
606 printf(" Use_Protection");
608 printf(" Barker_Preamble_Mode");
612 static void print_cipher(const uint8_t *data
)
614 if (memcmp(data
, ms_oui
, 3) == 0) {
617 printf("Use group cipher suite");
632 printf("%.02x-%.02x-%.02x:%d",
633 data
[0], data
[1] ,data
[2], data
[3]);
636 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
639 printf("Use group cipher suite");
654 printf("AES-128-CMAC");
663 printf("%.02x-%.02x-%.02x:%d",
664 data
[0], data
[1] ,data
[2], data
[3]);
668 printf("%.02x-%.02x-%.02x:%d",
669 data
[0], data
[1] ,data
[2], data
[3]);
672 static void print_auth(const uint8_t *data
)
674 if (memcmp(data
, ms_oui
, 3) == 0) {
677 printf("IEEE 802.1X");
683 printf("%.02x-%.02x-%.02x:%d",
684 data
[0], data
[1] ,data
[2], data
[3]);
687 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
690 printf("IEEE 802.1X");
696 printf("FT/IEEE 802.1X");
702 printf("IEEE 802.1X/SHA-256");
705 printf("PSK/SHA-256");
711 printf("%.02x-%.02x-%.02x:%d",
712 data
[0], data
[1] ,data
[2], data
[3]);
715 } else if (memcmp(data
, wfa_oui
, 3) == 0) {
721 printf("%.02x-%.02x-%.02x:%d",
722 data
[0], data
[1] ,data
[2], data
[3]);
726 printf("%.02x-%.02x-%.02x:%d",
727 data
[0], data
[1] ,data
[2], data
[3]);
730 static void _print_rsn_ie(const char *defcipher
, const char *defauth
,
731 uint8_t len
, const uint8_t *data
, int is_osen
)
739 version
= data
[0] + (data
[1] << 8);
740 tab_on_first(&first
);
741 printf("\t * Version: %d\n", version
);
748 tab_on_first(&first
);
749 printf("\t * Group cipher: %s\n", defcipher
);
750 printf("\t * Pairwise ciphers: %s\n", defcipher
);
754 tab_on_first(&first
);
755 printf("\t * Group cipher: ");
763 tab_on_first(&first
);
764 printf("\t * Pairwise ciphers: %s\n", defcipher
);
768 count
= data
[0] | (data
[1] << 8);
769 if (2 + (count
* 4) > len
)
772 tab_on_first(&first
);
773 printf("\t * Pairwise ciphers:");
774 for (i
= 0; i
< count
; i
++) {
776 print_cipher(data
+ 2 + (i
* 4));
780 data
+= 2 + (count
* 4);
781 len
-= 2 + (count
* 4);
784 tab_on_first(&first
);
785 printf("\t * Authentication suites: %s\n", defauth
);
789 count
= data
[0] | (data
[1] << 8);
790 if (2 + (count
* 4) > len
)
793 tab_on_first(&first
);
794 printf("\t * Authentication suites:");
795 for (i
= 0; i
< count
; i
++) {
797 print_auth(data
+ 2 + (i
* 4));
801 data
+= 2 + (count
* 4);
802 len
-= 2 + (count
* 4);
805 capa
= data
[0] | (data
[1] << 8);
806 tab_on_first(&first
);
807 printf("\t * Capabilities:");
811 printf(" NoPairwise");
812 switch ((capa
& 0x000c) >> 2) {
814 printf(" 1-PTKSA-RC");
817 printf(" 2-PTKSA-RC");
820 printf(" 4-PTKSA-RC");
823 printf(" 16-PTKSA-RC");
826 switch ((capa
& 0x0030) >> 4) {
828 printf(" 1-GTKSA-RC");
831 printf(" 2-GTKSA-RC");
834 printf(" 4-GTKSA-RC");
837 printf(" 16-GTKSA-RC");
841 printf(" MFP-required");
843 printf(" MFP-capable");
845 printf(" Peerkey-enabled");
847 printf(" SPP-AMSDU-capable");
849 printf(" SPP-AMSDU-required");
850 printf(" (0x%.4x)\n", capa
);
856 int pmkid_count
= data
[0] | (data
[1] << 8);
858 if (len
>= 2 + 16 * pmkid_count
) {
859 tab_on_first(&first
);
860 printf("\t * %d PMKIDs\n", pmkid_count
);
861 /* not printing PMKID values */
862 data
+= 2 + 16 * pmkid_count
;
863 len
-= 2 + 16 * pmkid_count
;
869 tab_on_first(&first
);
870 printf("\t * Group mgmt cipher suite: ");
879 printf("\t\t * bogus tail data (%d):", len
);
881 printf(" %.2x", *data
);
889 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
890 uint8_t len
, const uint8_t *data
)
892 _print_rsn_ie(defcipher
, defauth
, len
, data
, 0);
895 static void print_osen_ie(const char *defcipher
, const char *defauth
,
896 uint8_t len
, const uint8_t *data
)
899 _print_rsn_ie(defcipher
, defauth
, len
, data
, 1);
902 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
)
904 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
907 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
910 print_ht_capability(data
[0] | (data
[1] << 8));
911 print_ampdu_length(data
[2] & 3);
912 print_ampdu_spacing((data
[2] >> 2) & 7);
913 print_ht_mcs(data
+ 3);
916 static const char* ntype_11u(uint8_t t
)
919 case 0: return "Private";
920 case 1: return "Private with Guest";
921 case 2: return "Chargeable Public";
922 case 3: return "Free Public";
923 case 4: return "Personal Device";
924 case 5: return "Emergency Services Only";
925 case 14: return "Test or Experimental";
926 case 15: return "Wildcard";
927 default: return "Reserved";
931 static const char* vgroup_11u(uint8_t t
)
934 case 0: return "Unspecified";
935 case 1: return "Assembly";
936 case 2: return "Business";
937 case 3: return "Educational";
938 case 4: return "Factory and Industrial";
939 case 5: return "Institutional";
940 case 6: return "Mercantile";
941 case 7: return "Residential";
942 case 8: return "Storage";
943 case 9: return "Utility and Miscellaneous";
944 case 10: return "Vehicular";
945 case 11: return "Outdoor";
946 default: return "Reserved";
950 static void print_interworking(const uint8_t type
, uint8_t len
, const uint8_t *data
)
952 /* See Section 7.3.2.92 in the 802.11u spec. */
955 uint8_t ano
= data
[0];
956 printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano
));
957 printf("\t\t\tNetwork Type: %i (%s)\n",
958 (int)(ano
& 0xf), ntype_11u(ano
& 0xf));
960 printf("\t\t\tInternet\n");
962 printf("\t\t\tASRA\n");
964 printf("\t\t\tESR\n");
966 printf("\t\t\tUESA\n");
968 if ((len
== 3) || (len
== 9)) {
969 printf("\t\tVenue Group: %i (%s)\n",
970 (int)(data
[1]), vgroup_11u(data
[1]));
971 printf("\t\tVenue Type: %i\n", (int)(data
[2]));
974 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
975 data
[3], data
[4], data
[5], data
[6], data
[7], data
[8]);
977 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
978 data
[1], data
[2], data
[3], data
[4], data
[5], data
[6]);
981 static void print_11u_advert(const uint8_t type
, uint8_t len
, const uint8_t *data
)
983 /* See Section 7.3.2.93 in the 802.11u spec. */
984 /* TODO: This code below does not decode private protocol IDs */
987 while (idx
< (len
- 1)) {
988 uint8_t qri
= data
[idx
];
989 uint8_t proto_id
= data
[idx
+ 1];
990 printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri
));
991 printf("\t\t\tQuery Response Length Limit: %i\n",
994 printf("\t\t\tPAME-BI\n");
997 printf("\t\t\tANQP\n"); break;
999 printf("\t\t\tMIH Information Service\n"); break;
1001 printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
1003 printf("\t\t\tEmergency Alert System (EAS)\n"); break;
1005 printf("\t\t\tVendor Specific\n"); break;
1007 printf("\t\t\tReserved: %i\n", proto_id
); break;
1013 static void print_11u_rcon(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1015 /* See Section 7.3.2.96 in the 802.11u spec. */
1017 int ln0
= data
[1] & 0xf;
1018 int ln1
= ((data
[1] & 0xf0) >> 4);
1023 ln2
= len
- 2 - ln0
- ln1
;
1025 printf("\t\tANQP OIs: %i\n", data
[0]);
1028 printf("\t\tOI 1: ");
1029 if (2 + ln0
> len
) {
1030 printf("Invalid IE length.\n");
1032 for (idx
= 0; idx
< ln0
; idx
++) {
1033 printf("%02hx", data
[2 + idx
]);
1040 printf("\t\tOI 2: ");
1041 if (2 + ln0
+ ln1
> len
) {
1042 printf("Invalid IE length.\n");
1044 for (idx
= 0; idx
< ln1
; idx
++) {
1045 printf("%02hx", data
[2 + ln0
+ idx
]);
1052 printf("\t\tOI 3: ");
1053 if (2 + ln0
+ ln1
+ ln2
> len
) {
1054 printf("Invalid IE length.\n");
1056 for (idx
= 0; idx
< ln2
; idx
++) {
1057 printf("%02hx", data
[2 + ln0
+ ln1
+ idx
]);
1064 static const char *ht_secondary_offset
[4] = {
1071 static void print_ht_op(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1073 static const char *protection
[4] = {
1079 static const char *sta_chan_width
[2] = {
1085 printf("\t\t * primary channel: %d\n", data
[0]);
1086 printf("\t\t * secondary channel offset: %s\n",
1087 ht_secondary_offset
[data
[1] & 0x3]);
1088 printf("\t\t * STA channel width: %s\n", sta_chan_width
[(data
[1] & 0x4)>>2]);
1089 printf("\t\t * RIFS: %d\n", (data
[1] & 0x8)>>3);
1090 printf("\t\t * HT protection: %s\n", protection
[data
[2] & 0x3]);
1091 printf("\t\t * non-GF present: %d\n", (data
[2] & 0x4) >> 2);
1092 printf("\t\t * OBSS non-GF present: %d\n", (data
[2] & 0x10) >> 4);
1093 printf("\t\t * dual beacon: %d\n", (data
[4] & 0x40) >> 6);
1094 printf("\t\t * dual CTS protection: %d\n", (data
[4] & 0x80) >> 7);
1095 printf("\t\t * STBC beacon: %d\n", data
[5] & 0x1);
1096 printf("\t\t * L-SIG TXOP Prot: %d\n", (data
[5] & 0x2) >> 1);
1097 printf("\t\t * PCO active: %d\n", (data
[5] & 0x4) >> 2);
1098 printf("\t\t * PCO phase: %d\n", (data
[5] & 0x8) >> 3);
1101 static void print_capabilities(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1107 for (i
= 0; i
< len
; i
++) {
1110 for (bit
= 0; bit
< 8; bit
++) {
1111 if (!(data
[i
] & (1 << bit
)))
1119 #define CAPA(bit, name) case bit: printf(" " name); break
1121 switch (bit
+ base
) {
1122 CAPA(0, "HT Information Exchange Supported");
1123 CAPA(1, "reserved (On-demand Beacon)");
1124 CAPA(2, "Extended Channel Switching");
1125 CAPA(3, "reserved (Wave Indication)");
1126 CAPA(4, "PSMP Capability");
1127 CAPA(5, "reserved (Service Interval Granularity)");
1128 CAPA(6, "S-PSMP Capability");
1130 CAPA(8, "Diagnostics");
1131 CAPA(9, "Multicast Diagnostics");
1132 CAPA(10, "Location Tracking");
1134 CAPA(12, "Proxy ARP Service");
1135 CAPA(13, "Collocated Interference Reporting");
1136 CAPA(14, "Civic Location");
1137 CAPA(15, "Geospatial Location");
1139 CAPA(17, "WNM-Sleep Mode");
1140 CAPA(18, "TIM Broadcast");
1141 CAPA(19, "BSS Transition");
1142 CAPA(20, "QoS Traffic Capability");
1143 CAPA(21, "AC Station Count");
1144 CAPA(22, "Multiple BSSID");
1145 CAPA(23, "Timing Measurement");
1146 CAPA(24, "Channel Usage");
1147 CAPA(25, "SSID List");
1149 CAPA(27, "UTC TSF Offset");
1150 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1151 CAPA(29, "TDLS Peer PSM Support");
1152 CAPA(30, "TDLS channel switching");
1153 CAPA(31, "Interworking");
1154 CAPA(32, "QoS Map");
1156 CAPA(34, "SSPN Interface");
1157 CAPA(35, "Reserved");
1158 CAPA(36, "MSGCF Capability");
1159 CAPA(37, "TDLS Support");
1160 CAPA(38, "TDLS Prohibited");
1161 CAPA(39, "TDLS Channel Switching Prohibited");
1162 CAPA(40, "Reject Unadmitted Frame");
1163 CAPA(44, "Identifier Location");
1164 CAPA(45, "U-APSD Coexistence");
1165 CAPA(46, "WNM-Notification");
1166 CAPA(47, "Reserved");
1167 CAPA(48, "UTF-8 SSID");
1168 CAPA(70, "FTM Responder");
1169 CAPA(71, "FTM Initiator");
1181 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1183 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1185 data
[0], data
[1], data
[2], data
[3]);
1187 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
1191 static void print_ibssatim(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1193 printf(" %d TUs", (data
[1] << 8) + data
[0]);
1196 static void print_vht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1199 print_vht_info(data
[0] | (data
[1] << 8) |
1200 (data
[2] << 16) | (data
[3] << 24),
1204 static void print_vht_oper(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1206 const char *chandwidths
[] = {
1207 [0] = "20 or 40 MHz",
1214 printf("\t\t * channel width: %d (%s)\n", data
[0],
1215 data
[0] < ARRAY_SIZE(chandwidths
) ? chandwidths
[data
[0]] : "unknown");
1216 printf("\t\t * center freq segment 1: %d\n", data
[1]);
1217 printf("\t\t * center freq segment 2: %d\n", data
[2]);
1218 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data
[4], data
[3]);
1221 static void print_obss_scan_params(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1224 printf("\t\t * passive dwell: %d TUs\n", (data
[1] << 8) | data
[0]);
1225 printf("\t\t * active dwell: %d TUs\n", (data
[3] << 8) | data
[2]);
1226 printf("\t\t * channel width trigger scan interval: %d s\n", (data
[5] << 8) | data
[4]);
1227 printf("\t\t * scan passive total per channel: %d TUs\n", (data
[7] << 8) | data
[6]);
1228 printf("\t\t * scan active total per channel: %d TUs\n", (data
[9] << 8) | data
[8]);
1229 printf("\t\t * BSS width channel transition delay factor: %d\n", (data
[11] << 8) | data
[10]);
1230 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1231 ((data
[13] << 8) | data
[12]) / 100, ((data
[13] << 8) | data
[12]) % 100);
1234 static void print_secchan_offs(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1236 if (data
[0] < ARRAY_SIZE(ht_secondary_offset
))
1237 printf(" %s (%d)\n", ht_secondary_offset
[data
[0]], data
[0]);
1239 printf(" %d\n", data
[0]);
1242 static void print_bss_load(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1245 printf("\t\t * station count: %d\n", (data
[1] << 8) | data
[0]);
1246 printf("\t\t * channel utilisation: %d/255\n", data
[2]);
1247 printf("\t\t * available admission capacity: %d [*32us]\n", (data
[4] << 8) | data
[3]);
1250 static void print_mesh_conf(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1253 printf("\t\t * Active Path Selection Protocol ID: %d\n", data
[0]);
1254 printf("\t\t * Active Path Selection Metric ID: %d\n", data
[1]);
1255 printf("\t\t * Congestion Control Mode ID: %d\n", data
[2]);
1256 printf("\t\t * Synchronization Method ID: %d\n", data
[3]);
1257 printf("\t\t * Authentication Protocol ID: %d\n", data
[4]);
1258 printf("\t\t * Mesh Formation Info:\n");
1259 printf("\t\t\t Number of Peerings: %d\n", (data
[5] & 0x7E) >> 1);
1261 printf("\t\t\t Connected to Mesh Gate\n");
1263 printf("\t\t\t Connected to AS\n");
1264 printf("\t\t * Mesh Capability\n");
1266 printf("\t\t\t Accepting Additional Mesh Peerings\n");
1268 printf("\t\t\t MCCA Supported\n");
1270 printf("\t\t\t MCCA Enabled\n");
1272 printf("\t\t\t Forwarding\n");
1274 printf("\t\t\t MBCA Supported\n");
1276 printf("\t\t\t TBTT Adjusting\n");
1278 printf("\t\t\t Mesh Power Save Level\n");
1283 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
);
1284 uint8_t minlen
, maxlen
;
1288 static void print_ie(const struct ie_print
*p
, const uint8_t type
,
1289 uint8_t len
, const uint8_t *data
)
1296 printf("\t%s:", p
->name
);
1297 if (len
< p
->minlen
|| len
> p
->maxlen
) {
1299 printf(" <invalid: %d bytes:", len
);
1300 for (i
= 0; i
< len
; i
++)
1301 printf(" %.02x", data
[i
]);
1304 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
1306 printf(" <invalid: no data>\n");
1310 p
->print(type
, len
, data
);
1313 #define PRINT_IGN { \
1320 static const struct ie_print ieprinters
[] = {
1321 [0] = { "SSID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1322 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1323 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
1324 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
1325 [6] = { "IBSS ATIM window", print_ibssatim
, 2, 2, BIT(PRINT_SCAN
), },
1326 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
1327 [11] = { "BSS Load", print_bss_load
, 5, 5, BIT(PRINT_SCAN
), },
1328 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
1329 [35] = { "TPC report", print_tpcreport
, 2, 2, BIT(PRINT_SCAN
), },
1330 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1331 [45] = { "HT capabilities", print_ht_capa
, 26, 26, BIT(PRINT_SCAN
), },
1332 [47] = { "ERP D4.0", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1333 [74] = { "Overlapping BSS scan params", print_obss_scan_params
, 14, 255, BIT(PRINT_SCAN
), },
1334 [61] = { "HT operation", print_ht_op
, 22, 22, BIT(PRINT_SCAN
), },
1335 [62] = { "Secondary Channel Offset", print_secchan_offs
, 1, 1, BIT(PRINT_SCAN
), },
1336 [191] = { "VHT capabilities", print_vht_capa
, 12, 255, BIT(PRINT_SCAN
), },
1337 [192] = { "VHT operation", print_vht_oper
, 5, 255, BIT(PRINT_SCAN
), },
1338 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
1339 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1340 [113] = { "MESH Configuration", print_mesh_conf
, 7, 7, BIT(PRINT_SCAN
), },
1341 [114] = { "MESH ID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1342 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
1343 [107] = { "802.11u Interworking", print_interworking
, 0, 255, BIT(PRINT_SCAN
), },
1344 [108] = { "802.11u Advertisement", print_11u_advert
, 0, 255, BIT(PRINT_SCAN
), },
1345 [111] = { "802.11u Roaming Consortium", print_11u_rcon
, 0, 255, BIT(PRINT_SCAN
), },
1348 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1350 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
1353 static void print_wifi_osen(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1355 print_osen_ie("OSEN", "OSEN", len
, data
);
1358 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
1361 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
1367 printf("Parameter: not version 1: ");
1371 printf("\t * Parameter version 1");
1376 printf("\n\t\t * u-APSD");
1380 for (i
= 0; i
< 4; i
++) {
1381 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
1384 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
1385 (1 << (data
[1] >> 4)) - 1);
1386 printf(", AIFSN %d", data
[0] & 0xf);
1387 if (data
[2] | data
[3])
1388 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
1396 printf("invalid: ");
1400 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1406 printf(" information:");
1409 if (print_wifi_wmm_param(data
+ 1, len
- 1))
1413 printf(" type %d:", data
[0]);
1417 for(i
= 1; i
< len
; i
++)
1418 printf(" %.02x", data
[i
]);
1422 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
1426 return "Default (PIN)";
1428 return "User-specified";
1430 return "Machine-specified";
1434 return "PushButton";
1436 return "Registrar-specified";
1442 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1445 __u16 subtype
, sublen
;
1448 subtype
= (data
[0] << 8) + data
[1];
1449 sublen
= (data
[2] << 8) + data
[3];
1455 tab_on_first(&first
);
1456 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
1459 tab_on_first(&first
);
1460 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
1464 tab_on_first(&first
);
1466 printf("\t * Device Password ID: (invalid "
1467 "length %d)\n", sublen
);
1470 id
= data
[4] << 8 | data
[5];
1471 printf("\t * Device Password ID: %u (%s)\n",
1472 id
, wifi_wps_dev_passwd_id(id
));
1476 tab_on_first(&first
);
1477 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
1480 tab_on_first(&first
);
1481 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
1484 tab_on_first(&first
);
1485 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
1489 tab_on_first(&first
);
1490 printf("\t * Response Type: %d%s\n",
1491 val
, val
== 3 ? " (AP)" : "");
1496 tab_on_first(&first
);
1497 printf("\t * RF Bands: 0x%x\n", val
);
1502 tab_on_first(&first
);
1503 printf("\t * Selected Registrar: 0x%x\n", val
);
1507 tab_on_first(&first
);
1508 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
1512 tab_on_first(&first
);
1513 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1515 val
== 1 ? " (Unconfigured)" : "",
1516 val
== 2 ? " (Configured)" : "");
1520 tab_on_first(&first
);
1521 printf("\t * UUID: ");
1523 printf("(invalid, length=%d)\n", sublen
);
1526 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1527 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1528 data
[4], data
[5], data
[6], data
[7],
1529 data
[8], data
[9], data
[10], data
[11],
1530 data
[12], data
[13], data
[14], data
[15],
1531 data
[16], data
[17], data
[18], data
[19]);
1534 tab_on_first(&first
);
1536 printf("\t * Primary Device Type: (invalid "
1537 "length %d)\n", sublen
);
1540 printf("\t * Primary Device Type: "
1541 "%u-%02x%02x%02x%02x-%u\n",
1542 data
[4] << 8 | data
[5],
1543 data
[6], data
[7], data
[8], data
[9],
1544 data
[10] << 8 | data
[11]);
1549 tab_on_first(&first
);
1550 printf("\t * AP setup locked: 0x%.2x\n", val
);
1555 __u16 meth
= (data
[4] << 8) + data
[5];
1557 tab_on_first(&first
);
1558 printf("\t * %sConfig methods:",
1559 subtype
== 0x1053 ? "Selected Registrar ": "");
1560 #define T(bit, name) do { \
1561 if (meth & (1<<bit)) { \
1581 const __u8
*subdata
= data
+ 4;
1582 __u16 tmplen
= sublen
;
1584 tab_on_first(&first
);
1585 printf("\t * Unknown TLV (%#.4x, %d bytes):",
1588 printf(" %.2x", *subdata
);
1602 printf("\t\t * bogus tail data (%d):", len
);
1604 printf(" %.2x", *data
);
1612 static const struct ie_print wifiprinters
[] = {
1613 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
1614 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
1615 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
1618 static inline void print_p2p(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1626 sublen
= (data
[2] << 8) + data
[1];
1628 if (sublen
> len
- 3)
1632 case 0x02: /* capability */
1633 tab_on_first(&first
);
1635 printf("\t * malformed capability\n");
1638 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
1641 case 0x0d: /* device info */
1642 if (sublen
< 6 + 2 + 8 + 1) {
1643 printf("\t * malformed device info\n");
1646 /* fall through for now */
1647 case 0x00: /* status */
1648 case 0x01: /* minor reason */
1649 case 0x03: /* device ID */
1650 case 0x04: /* GO intent */
1651 case 0x05: /* configuration timeout */
1652 case 0x06: /* listen channel */
1653 case 0x07: /* group BSSID */
1654 case 0x08: /* ext listen timing */
1655 case 0x09: /* intended interface address */
1656 case 0x0a: /* manageability */
1657 case 0x0b: /* channel list */
1658 case 0x0c: /* NoA */
1659 case 0x0e: /* group info */
1660 case 0x0f: /* group ID */
1661 case 0x10: /* interface */
1662 case 0x11: /* operating channel */
1663 case 0x12: /* invitation flags */
1664 case 0xdd: /* vendor specific */
1666 const __u8
*subdata
= data
+ 4;
1667 __u16 tmplen
= sublen
;
1669 tab_on_first(&first
);
1670 printf("\t * Unknown TLV (%#.2x, %d bytes):",
1673 printf(" %.2x", *subdata
);
1687 tab_on_first(&first
);
1688 printf("\t * bogus tail data (%d):", len
);
1690 printf(" %.2x", *data
);
1698 static inline void print_hs20_ind(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1700 /* I can't find the spec for this...just going off what wireshark uses. */
1703 printf("\t\tDGAF: %i\n", (int)(data
[0] & 0x1));
1705 printf("\t\tUnexpected length: %i\n", len
);
1708 static const struct ie_print wfa_printers
[] = {
1709 [9] = { "P2P", print_p2p
, 2, 255, BIT(PRINT_SCAN
), },
1710 [16] = { "HotSpot 2.0 Indication", print_hs20_ind
, 1, 255, BIT(PRINT_SCAN
), },
1711 [18] = { "HotSpot 2.0 OSEN", print_wifi_osen
, 1, 255, BIT(PRINT_SCAN
), },
1714 static void print_vendor(unsigned char len
, unsigned char *data
,
1715 bool unknown
, enum print_ie_type ptype
)
1720 printf("\tVendor specific: <too short> data:");
1721 for(i
= 0; i
< len
; i
++)
1722 printf(" %.02x", data
[i
]);
1727 if (len
>= 4 && memcmp(data
, ms_oui
, 3) == 0) {
1728 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
1729 wifiprinters
[data
[3]].name
&&
1730 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
1731 print_ie(&wifiprinters
[data
[3]], data
[3], len
- 4, data
+ 4);
1736 printf("\tMS/WiFi %#.2x, data:", data
[3]);
1737 for(i
= 0; i
< len
- 4; i
++)
1738 printf(" %.02x", data
[i
+ 4]);
1743 if (len
>= 4 && memcmp(data
, wfa_oui
, 3) == 0) {
1744 if (data
[3] < ARRAY_SIZE(wfa_printers
) &&
1745 wfa_printers
[data
[3]].name
&&
1746 wfa_printers
[data
[3]].flags
& BIT(ptype
)) {
1747 print_ie(&wfa_printers
[data
[3]], data
[3], len
- 4, data
+ 4);
1752 printf("\tWFA %#.2x, data:", data
[3]);
1753 for(i
= 0; i
< len
- 4; i
++)
1754 printf(" %.02x", data
[i
+ 4]);
1762 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
1763 data
[0], data
[1], data
[2]);
1764 for (i
= 3; i
< len
; i
++)
1765 printf(" %.2x", data
[i
]);
1769 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
1770 enum print_ie_type ptype
)
1772 while (ielen
>= 2 && ielen
>= ie
[1]) {
1773 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
1774 ieprinters
[ie
[0]].name
&&
1775 ieprinters
[ie
[0]].flags
& BIT(ptype
)) {
1776 print_ie(&ieprinters
[ie
[0]], ie
[0], ie
[1], ie
+ 2);
1777 } else if (ie
[0] == 221 /* vendor */) {
1778 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
1779 } else if (unknown
) {
1782 printf("\tUnknown IE (%d):", ie
[0]);
1783 for (i
=0; i
<ie
[1]; i
++)
1784 printf(" %.2x", ie
[2+i
]);
1792 static void print_capa_dmg(__u16 capa
)
1794 switch (capa
& WLAN_CAPABILITY_DMG_TYPE_MASK
) {
1795 case WLAN_CAPABILITY_DMG_TYPE_AP
:
1798 case WLAN_CAPABILITY_DMG_TYPE_PBSS
:
1801 case WLAN_CAPABILITY_DMG_TYPE_IBSS
:
1802 printf(" DMG_IBSS");
1806 if (capa
& WLAN_CAPABILITY_DMG_CBAP_ONLY
)
1807 printf(" CBAP_Only");
1808 if (capa
& WLAN_CAPABILITY_DMG_CBAP_SOURCE
)
1809 printf(" CBAP_Src");
1810 if (capa
& WLAN_CAPABILITY_DMG_PRIVACY
)
1812 if (capa
& WLAN_CAPABILITY_DMG_ECPAC
)
1814 if (capa
& WLAN_CAPABILITY_DMG_SPECTRUM_MGMT
)
1815 printf(" SpectrumMgmt");
1816 if (capa
& WLAN_CAPABILITY_DMG_RADIO_MEASURE
)
1817 printf(" RadioMeasure");
1820 static void print_capa_non_dmg(__u16 capa
)
1822 if (capa
& WLAN_CAPABILITY_ESS
)
1824 if (capa
& WLAN_CAPABILITY_IBSS
)
1826 if (capa
& WLAN_CAPABILITY_CF_POLLABLE
)
1827 printf(" CfPollable");
1828 if (capa
& WLAN_CAPABILITY_CF_POLL_REQUEST
)
1829 printf(" CfPollReq");
1830 if (capa
& WLAN_CAPABILITY_PRIVACY
)
1832 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
1833 printf(" ShortPreamble");
1834 if (capa
& WLAN_CAPABILITY_PBCC
)
1836 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
1837 printf(" ChannelAgility");
1838 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
1839 printf(" SpectrumMgmt");
1840 if (capa
& WLAN_CAPABILITY_QOS
)
1842 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
1843 printf(" ShortSlotTime");
1844 if (capa
& WLAN_CAPABILITY_APSD
)
1846 if (capa
& WLAN_CAPABILITY_RADIO_MEASURE
)
1847 printf(" RadioMeasure");
1848 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
1849 printf(" DSSS-OFDM");
1850 if (capa
& WLAN_CAPABILITY_DEL_BACK
)
1851 printf(" DelayedBACK");
1852 if (capa
& WLAN_CAPABILITY_IMM_BACK
)
1853 printf(" ImmediateBACK");
1856 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
1858 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
1859 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
1860 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
1861 char mac_addr
[20], dev
[20];
1862 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
1863 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
1864 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
1865 [NL80211_BSS_BSSID
] = { },
1866 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
1867 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
1868 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
1869 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
1870 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
1871 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
1872 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
1873 [NL80211_BSS_BEACON_IES
] = { },
1875 struct scan_params
*params
= arg
;
1876 int show
= params
->show_both_ie_sets
? 2 : 1;
1877 bool is_dmg
= false;
1879 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
1880 genlmsg_attrlen(gnlh
, 0), NULL
);
1882 if (!tb
[NL80211_ATTR_BSS
]) {
1883 fprintf(stderr
, "bss info missing!\n");
1886 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
1887 tb
[NL80211_ATTR_BSS
],
1889 fprintf(stderr
, "failed to parse nested attributes!\n");
1893 if (!bss
[NL80211_BSS_BSSID
])
1896 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
1897 printf("BSS %s", mac_addr
);
1898 if (tb
[NL80211_ATTR_IFINDEX
]) {
1899 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
1900 printf("(on %s)", dev
);
1903 if (bss
[NL80211_BSS_STATUS
]) {
1904 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
1905 case NL80211_BSS_STATUS_AUTHENTICATED
:
1906 printf(" -- authenticated");
1908 case NL80211_BSS_STATUS_ASSOCIATED
:
1909 printf(" -- associated");
1911 case NL80211_BSS_STATUS_IBSS_JOINED
:
1912 printf(" -- joined");
1915 printf(" -- unknown status: %d",
1916 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
1922 if (bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]) {
1923 unsigned long long bt
;
1924 bt
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]);
1925 printf("\tlast seen: %llu.%.3llus [boottime]\n", bt
/1000000000, (bt
%1000000000)/1000000);
1928 if (bss
[NL80211_BSS_TSF
]) {
1929 unsigned long long tsf
;
1930 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
1931 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
1932 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
1933 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
1935 if (bss
[NL80211_BSS_FREQUENCY
]) {
1936 int freq
= nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]);
1937 printf("\tfreq: %d\n", freq
);
1941 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
1942 printf("\tbeacon interval: %d TUs\n",
1943 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
1944 if (bss
[NL80211_BSS_CAPABILITY
]) {
1945 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
1946 printf("\tcapability:");
1948 print_capa_dmg(capa
);
1950 print_capa_non_dmg(capa
);
1951 printf(" (0x%.4x)\n", capa
);
1953 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
1954 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
1955 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
1957 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
1958 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
1959 printf("\tsignal: %d/100\n", s
);
1961 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
1962 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
1963 printf("\tlast seen: %d ms ago\n", age
);
1966 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
1967 if (bss
[NL80211_BSS_BEACON_IES
])
1968 printf("\tInformation elements from Probe Response "
1970 print_ies(nla_data(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
1971 nla_len(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
1972 params
->unknown
, params
->type
);
1974 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
1975 printf("\tInformation elements from Beacon frame:\n");
1976 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
1977 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
1978 params
->unknown
, params
->type
);
1984 static struct scan_params scan_params
;
1986 static int handle_scan_dump(struct nl80211_state
*state
,
1988 int argc
, char **argv
,
1994 memset(&scan_params
, 0, sizeof(scan_params
));
1996 if (argc
== 1 && !strcmp(argv
[0], "-u"))
1997 scan_params
.unknown
= true;
1998 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
1999 scan_params
.show_both_ie_sets
= true;
2001 scan_params
.type
= PRINT_SCAN
;
2003 register_handler(print_bss_handler
,
2008 static int handle_scan_combined(struct nl80211_state
*state
,
2010 int argc
, char **argv
,
2014 static char *dump_argv
[] = {
2020 static const __u32 cmds
[] = {
2021 NL80211_CMD_NEW_SCAN_RESULTS
,
2022 NL80211_CMD_SCAN_ABORTED
,
2024 int trig_argc
, dump_argc
, err
;
2027 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
2029 dump_argv
[3] = "-u";
2030 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
2032 dump_argv
[3] = "-b";
2036 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
2037 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
2040 trig_argv
[0] = argv
[0];
2041 trig_argv
[1] = "scan";
2042 trig_argv
[2] = "trigger";
2044 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
2045 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
2046 err
= handle_cmd(state
, id
, trig_argc
, trig_argv
);
2052 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
2054 * This code has a bug, which requires creating a separate
2055 * nl80211 socket to fix:
2056 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
2057 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
2058 * before (!) we listen to it, because we only start listening
2059 * after we send our scan request.
2061 * Doing it the other way around has a race condition as well,
2062 * if you first open the events socket you may get a notification
2063 * for a previous scan.
2065 * The only proper way to fix this would be to listen to events
2066 * before sending the command, and for the kernel to send the
2067 * scan request along with the event, so that you can match up
2068 * whether the scan you requested was finished or aborted (this
2069 * may result in processing a scan that another application
2070 * requested, but that doesn't seem to be a problem).
2072 * Alas, the kernel doesn't do that (yet).
2075 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
2076 NL80211_CMD_SCAN_ABORTED
) {
2077 printf("scan aborted!\n");
2081 dump_argv
[0] = argv
[0];
2082 return handle_cmd(state
, id
, dump_argc
, dump_argv
);
2084 TOPLEVEL(scan
, "[-u] [freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]", 0, 0,
2085 CIB_NETDEV
, handle_scan_combined
,
2086 "Scan on the given frequencies and probe for the given SSIDs\n"
2087 "(or wildcard if not given) unless passive scanning is requested.\n"
2088 "If -u is specified print unknown data in the scan results.\n"
2089 "Specified (vendor) IEs must be well-formed.");
2090 COMMAND(scan
, dump
, "[-u]",
2091 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
2092 "Dump the current scan results. If -u is specified, print unknown\n"
2093 "data in scan results.");
2094 COMMAND(scan
, trigger
, "[freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]",
2095 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
2096 "Trigger a scan on the given frequencies with probing for the given\n"
2097 "SSIDs (or wildcard if not given) unless passive scanning is requested.");
2100 static int handle_start_sched_scan(struct nl80211_state
*state
,
2102 int argc
, char **argv
, enum id_input id
)
2104 return parse_sched_scan(msg
, &argc
, &argv
);
2107 static int handle_stop_sched_scan(struct nl80211_state
*state
,
2108 struct nl_msg
*msg
, int argc
, char **argv
,
2117 COMMAND(scan
, sched_start
,
2119 NL80211_CMD_START_SCHED_SCAN
, 0, CIB_NETDEV
, handle_start_sched_scan
,
2120 "Start a scheduled scan at the specified interval on the given frequencies\n"
2121 "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2122 "scanning is requested. If matches are specified, only matching results\n"
2123 "will be returned.");
2124 COMMAND(scan
, sched_stop
, "",
2125 NL80211_CMD_STOP_SCHED_SCAN
, 0, CIB_NETDEV
, handle_stop_sched_scan
,
2126 "Stop an ongoing scheduled scan.");