7 #include <netlink/genl/genl.h>
8 #include <netlink/genl/family.h>
9 #include <netlink/genl/ctrl.h>
10 #include <netlink/msg.h>
11 #include <netlink/attr.h>
16 #define WLAN_CAPABILITY_ESS (1<<0)
17 #define WLAN_CAPABILITY_IBSS (1<<1)
18 #define WLAN_CAPABILITY_CF_POLLABLE (1<<2)
19 #define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3)
20 #define WLAN_CAPABILITY_PRIVACY (1<<4)
21 #define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
22 #define WLAN_CAPABILITY_PBCC (1<<6)
23 #define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
24 #define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8)
25 #define WLAN_CAPABILITY_QOS (1<<9)
26 #define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10)
27 #define WLAN_CAPABILITY_APSD (1<<11)
28 #define WLAN_CAPABILITY_RADIO_MEASURE (1<<12)
29 #define WLAN_CAPABILITY_DSSS_OFDM (1<<13)
30 #define WLAN_CAPABILITY_DEL_BACK (1<<14)
31 #define WLAN_CAPABILITY_IMM_BACK (1<<15)
32 /* DMG (60gHz) 802.11ad */
33 /* type - bits 0..1 */
34 #define WLAN_CAPABILITY_DMG_TYPE_MASK (3<<0)
36 #define WLAN_CAPABILITY_DMG_TYPE_IBSS (1<<0) /* Tx by: STA */
37 #define WLAN_CAPABILITY_DMG_TYPE_PBSS (2<<0) /* Tx by: PCP */
38 #define WLAN_CAPABILITY_DMG_TYPE_AP (3<<0) /* Tx by: AP */
40 #define WLAN_CAPABILITY_DMG_CBAP_ONLY (1<<2)
41 #define WLAN_CAPABILITY_DMG_CBAP_SOURCE (1<<3)
42 #define WLAN_CAPABILITY_DMG_PRIVACY (1<<4)
43 #define WLAN_CAPABILITY_DMG_ECPAC (1<<5)
45 #define WLAN_CAPABILITY_DMG_SPECTRUM_MGMT (1<<8)
46 #define WLAN_CAPABILITY_DMG_RADIO_MEASURE (1<<12)
48 static unsigned char ms_oui
[3] = { 0x00, 0x50, 0xf2 };
49 static unsigned char ieee80211_oui
[3] = { 0x00, 0x0f, 0xac };
50 static unsigned char wfa_oui
[3] = { 0x50, 0x6f, 0x9a };
54 enum print_ie_type type
;
55 bool show_both_ie_sets
;
58 #define IEEE80211_COUNTRY_EXTENSION_ID 201
60 union ieee80211_country_ie_triplet
{
65 } __attribute__ ((packed
)) chans
;
67 __u8 reg_extension_id
;
70 } __attribute__ ((packed
)) ext
;
71 } __attribute__ ((packed
));
73 static int parse_random_mac_addr(struct nl_msg
*msg
, char *arg
)
75 char *a_addr
, *a_mask
, *sep
;
76 unsigned char addr
[ETH_ALEN
], mask
[ETH_ALEN
];
77 char *addrs
= arg
+ 9;
83 sep
= strchr(addrs
, '/');
91 if (mac_addr_a2n(addr
, a_addr
) || mac_addr_a2n(mask
, a_mask
))
94 NLA_PUT(msg
, NL80211_ATTR_MAC
, ETH_ALEN
, addr
);
95 NLA_PUT(msg
, NL80211_ATTR_MAC_MASK
, ETH_ALEN
, mask
);
102 int parse_sched_scan(struct nl_msg
*msg
, int *argc
, char ***argv
)
104 struct nl_msg
*matchset
= NULL
, *freqs
= NULL
;
105 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;
117 matchset
= nlmsg_alloc();
123 freqs
= nlmsg_alloc();
130 switch (parse_state
) {
132 if (!strcmp(v
[0], "interval")) {
136 goto nla_put_failure
;
141 goto nla_put_failure
;
143 interval
= strtoul(v
[0], &end
, 10);
144 if (*end
|| !interval
) {
146 goto nla_put_failure
;
149 NL80211_ATTR_SCHED_SCAN_INTERVAL
,
151 } else if (!strcmp(v
[0], "delay")) {
155 goto nla_put_failure
;
160 goto nla_put_failure
;
162 delay
= strtoul(v
[0], &end
, 10);
165 goto nla_put_failure
;
168 NL80211_ATTR_SCHED_SCAN_DELAY
,
170 } else if (!strcmp(v
[0], "matches")) {
171 parse_state
= ND_MATCH
;
174 goto nla_put_failure
;
178 } else if (!strcmp(v
[0], "freqs")) {
179 parse_state
= ND_FREQS
;
182 goto nla_put_failure
;
188 /* this element is not for us, so
189 * return to continue parsing.
191 goto nla_put_failure
;
197 if (!strcmp(v
[0], "ssid")) {
201 goto nla_put_failure
;
204 /* TODO: for now we can only have an
205 * SSID in the match, so we can start
206 * the match nest here.
208 match
= nla_nest_start(matchset
, i
);
211 goto nla_put_failure
;
215 NL80211_SCHED_SCAN_MATCH_ATTR_SSID
,
217 nla_nest_end(matchset
, match
);
220 have_matchset
= true;
224 /* other element that cannot be part
225 * of a match indicates the end of the
227 /* need at least one match in the matchset */
230 goto nla_put_failure
;
233 parse_state
= ND_TOPLEVEL
;
238 freq
= strtoul(v
[0], &end
, 10);
242 goto nla_put_failure
;
245 parse_state
= ND_TOPLEVEL
;
247 NLA_PUT_U32(freqs
, i
, freq
);
256 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
258 nla_put_nested(msg
, NL80211_ATTR_SCHED_SCAN_MATCH
, matchset
);
262 nla_nest_end(msg
, match
);
264 nlmsg_free(matchset
);
272 static int handle_scan(struct nl80211_state
*state
,
275 int argc
, char **argv
,
278 struct nl_msg
*ssids
= NULL
, *freqs
= NULL
;
291 bool passive
= false, have_ssids
= false, have_freqs
= false;
292 size_t ies_len
= 0, meshid_len
= 0;
293 unsigned char *ies
= NULL
, *meshid
= NULL
, *tmpies
;
294 unsigned int flags
= 0;
296 ssids
= nlmsg_alloc();
300 freqs
= nlmsg_alloc();
306 for (i
= 0; i
< argc
; i
++) {
309 if (strcmp(argv
[i
], "freq") == 0) {
313 } else if (strcmp(argv
[i
], "ies") == 0) {
316 } else if (strcmp(argv
[i
], "lowpri") == 0) {
317 flags
|= NL80211_SCAN_FLAG_LOW_PRIORITY
;
319 } else if (strcmp(argv
[i
], "flush") == 0) {
320 flags
|= NL80211_SCAN_FLAG_FLUSH
;
322 } else if (strcmp(argv
[i
], "ap-force") == 0) {
323 flags
|= NL80211_SCAN_FLAG_AP
;
325 } else if (strncmp(argv
[i
], "randomise", 9) == 0 ||
326 strncmp(argv
[i
], "randomize", 9) == 0) {
327 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
328 err
= parse_random_mac_addr(msg
, argv
[i
]);
330 goto nla_put_failure
;
332 } else if (strcmp(argv
[i
], "ssid") == 0) {
336 } else if (strcmp(argv
[i
], "passive") == 0) {
340 } else if (strcmp(argv
[i
], "meshid") == 0) {
347 freq
= strtoul(argv
[i
], &eptr
, 10);
348 if (eptr
!= argv
[i
] + strlen(argv
[i
])) {
349 /* failed to parse as number -- maybe a tag? */
354 NLA_PUT_U32(freqs
, i
, freq
);
357 ies
= parse_hex(argv
[i
], &ies_len
);
359 goto nla_put_failure
;
363 NLA_PUT(ssids
, i
, strlen(argv
[i
]), argv
[i
]);
366 meshid_len
= strlen(argv
[i
]);
367 meshid
= (unsigned char *) malloc(meshid_len
+ 2);
369 goto nla_put_failure
;
370 meshid
[0] = 114; /* mesh element id */
371 meshid
[1] = meshid_len
;
372 memcpy(&meshid
[2], argv
[i
], meshid_len
);
380 tmpies
= (unsigned char *) malloc(ies_len
+ meshid_len
);
382 goto nla_put_failure
;
384 memcpy(tmpies
, ies
, ies_len
);
388 memcpy(&tmpies
[ies_len
], meshid
, meshid_len
);
391 NLA_PUT(msg
, NL80211_ATTR_IE
, ies_len
+ meshid_len
, tmpies
);
396 NLA_PUT(ssids
, 1, 0, "");
398 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
401 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
403 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
412 static void tab_on_first(bool *first
)
420 static void print_ssid(const uint8_t type
, uint8_t len
, const uint8_t *data
)
423 print_ssid_escaped(len
, data
);
427 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
428 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
430 static void print_supprates(const uint8_t type
, uint8_t len
, const uint8_t *data
)
436 for (i
= 0; i
< len
; i
++) {
437 int r
= data
[i
] & 0x7f;
439 if (r
== BSS_MEMBERSHIP_SELECTOR_VHT_PHY
&& data
[i
] & 0x80)
441 else if (r
== BSS_MEMBERSHIP_SELECTOR_HT_PHY
&& data
[i
] & 0x80)
444 printf("%d.%d", r
/2, 5*(r
&1));
446 printf("%s ", data
[i
] & 0x80 ? "*" : "");
451 static void print_ds(const uint8_t type
, uint8_t len
, const uint8_t *data
)
453 printf(" channel %d\n", data
[0]);
456 static const char *country_env_str(char environment
)
458 switch (environment
) {
460 return "Indoor only";
462 return "Outdoor only";
464 return "Indoor/Outdoor";
470 static void print_country(const uint8_t type
, uint8_t len
, const uint8_t *data
)
472 printf(" %.*s", 2, data
);
474 printf("\tEnvironment: %s\n", country_env_str(data
[2]));
480 printf("\t\tNo country IE triplets present\n");
486 union ieee80211_country_ie_triplet
*triplet
= (void *) data
;
488 if (triplet
->ext
.reg_extension_id
>= IEEE80211_COUNTRY_EXTENSION_ID
) {
489 printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
490 triplet
->ext
.reg_extension_id
,
491 triplet
->ext
.reg_class
,
492 triplet
->ext
.coverage_class
,
493 triplet
->ext
.coverage_class
* 450);
501 if (triplet
->chans
.first_channel
<= 14)
502 end_channel
= triplet
->chans
.first_channel
+ (triplet
->chans
.num_channels
- 1);
504 end_channel
= triplet
->chans
.first_channel
+ (4 * (triplet
->chans
.num_channels
- 1));
506 printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet
->chans
.first_channel
, end_channel
, triplet
->chans
.max_power
);
515 static void print_powerconstraint(const uint8_t type
, uint8_t len
, const uint8_t *data
)
517 printf(" %d dB\n", data
[0]);
520 static void print_tpcreport(const uint8_t type
, uint8_t len
, const uint8_t *data
)
522 printf(" TX power: %d dBm\n", data
[0]);
523 /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
526 static void print_erp(const uint8_t type
, uint8_t len
, const uint8_t *data
)
529 printf(" <no flags>");
531 printf(" NonERP_Present");
533 printf(" Use_Protection");
535 printf(" Barker_Preamble_Mode");
539 static void print_cipher(const uint8_t *data
)
541 if (memcmp(data
, ms_oui
, 3) == 0) {
544 printf("Use group cipher suite");
559 printf("%.02x-%.02x-%.02x:%d",
560 data
[0], data
[1] ,data
[2], data
[3]);
563 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
566 printf("Use group cipher suite");
581 printf("AES-128-CMAC");
587 printf("%.02x-%.02x-%.02x:%d",
588 data
[0], data
[1] ,data
[2], data
[3]);
592 printf("%.02x-%.02x-%.02x:%d",
593 data
[0], data
[1] ,data
[2], data
[3]);
596 static void print_auth(const uint8_t *data
)
598 if (memcmp(data
, ms_oui
, 3) == 0) {
601 printf("IEEE 802.1X");
607 printf("%.02x-%.02x-%.02x:%d",
608 data
[0], data
[1] ,data
[2], data
[3]);
611 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
614 printf("IEEE 802.1X");
620 printf("FT/IEEE 802.1X");
626 printf("IEEE 802.1X/SHA-256");
629 printf("PSK/SHA-256");
635 printf("%.02x-%.02x-%.02x:%d",
636 data
[0], data
[1] ,data
[2], data
[3]);
640 printf("%.02x-%.02x-%.02x:%d",
641 data
[0], data
[1] ,data
[2], data
[3]);
644 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
645 uint8_t len
, const uint8_t *data
)
648 __u16 version
, count
, capa
;
651 version
= data
[0] + (data
[1] << 8);
652 tab_on_first(&first
);
653 printf("\t * Version: %d\n", version
);
659 tab_on_first(&first
);
660 printf("\t * Group cipher: %s\n", defcipher
);
661 printf("\t * Pairwise ciphers: %s\n", defcipher
);
665 tab_on_first(&first
);
666 printf("\t * Group cipher: ");
674 tab_on_first(&first
);
675 printf("\t * Pairwise ciphers: %s\n", defcipher
);
679 count
= data
[0] | (data
[1] << 8);
680 if (2 + (count
* 4) > len
)
683 tab_on_first(&first
);
684 printf("\t * Pairwise ciphers:");
685 for (i
= 0; i
< count
; i
++) {
687 print_cipher(data
+ 2 + (i
* 4));
691 data
+= 2 + (count
* 4);
692 len
-= 2 + (count
* 4);
695 tab_on_first(&first
);
696 printf("\t * Authentication suites: %s\n", defauth
);
700 count
= data
[0] | (data
[1] << 8);
701 if (2 + (count
* 4) > len
)
704 tab_on_first(&first
);
705 printf("\t * Authentication suites:");
706 for (i
= 0; i
< count
; i
++) {
708 print_auth(data
+ 2 + (i
* 4));
712 data
+= 2 + (count
* 4);
713 len
-= 2 + (count
* 4);
716 capa
= data
[0] | (data
[1] << 8);
717 tab_on_first(&first
);
718 printf("\t * Capabilities:");
722 printf(" NoPairwise");
723 switch ((capa
& 0x000c) >> 2) {
725 printf(" 1-PTKSA-RC");
728 printf(" 2-PTKSA-RC");
731 printf(" 4-PTKSA-RC");
734 printf(" 16-PTKSA-RC");
737 switch ((capa
& 0x0030) >> 4) {
739 printf(" 1-GTKSA-RC");
742 printf(" 2-GTKSA-RC");
745 printf(" 4-GTKSA-RC");
748 printf(" 16-GTKSA-RC");
752 printf(" MFP-required");
754 printf(" MFP-capable");
756 printf(" Peerkey-enabled");
758 printf(" SPP-AMSDU-capable");
760 printf(" SPP-AMSDU-required");
761 printf(" (0x%.4x)\n", capa
);
767 int pmkid_count
= data
[0] | (data
[1] << 8);
769 if (len
>= 2 + 16 * pmkid_count
) {
770 tab_on_first(&first
);
771 printf("\t * %d PMKIDs\n", pmkid_count
);
772 /* not printing PMKID values */
773 data
+= 2 + 16 * pmkid_count
;
774 len
-= 2 + 16 * pmkid_count
;
780 tab_on_first(&first
);
781 printf("\t * Group mgmt cipher suite: ");
790 printf("\t\t * bogus tail data (%d):", len
);
792 printf(" %.2x", *data
);
800 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
)
802 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
805 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
808 print_ht_capability(data
[0] | (data
[1] << 8));
809 print_ampdu_length(data
[2] & 3);
810 print_ampdu_spacing((data
[2] >> 2) & 7);
811 print_ht_mcs(data
+ 3);
814 static const char* ntype_11u(uint8_t t
)
817 case 0: return "Private";
818 case 1: return "Private with Guest";
819 case 2: return "Chargeable Public";
820 case 3: return "Free Public";
821 case 4: return "Personal Device";
822 case 5: return "Emergency Services Only";
823 case 14: return "Test or Experimental";
824 case 15: return "Wildcard";
825 default: return "Reserved";
829 static const char* vgroup_11u(uint8_t t
)
832 case 0: return "Unspecified";
833 case 1: return "Assembly";
834 case 2: return "Business";
835 case 3: return "Educational";
836 case 4: return "Factory and Industrial";
837 case 5: return "Institutional";
838 case 6: return "Mercantile";
839 case 7: return "Residential";
840 case 8: return "Storage";
841 case 9: return "Utility and Miscellaneous";
842 case 10: return "Vehicular";
843 case 11: return "Outdoor";
844 default: return "Reserved";
848 static void print_interworking(const uint8_t type
, uint8_t len
, const uint8_t *data
)
850 /* See Section 7.3.2.92 in the 802.11u spec. */
853 uint8_t ano
= data
[0];
854 printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano
));
855 printf("\t\t\tNetwork Type: %i (%s)\n",
856 (int)(ano
& 0xf), ntype_11u(ano
& 0xf));
858 printf("\t\t\tInternet\n");
860 printf("\t\t\tASRA\n");
862 printf("\t\t\tESR\n");
864 printf("\t\t\tUESA\n");
866 if ((len
== 3) || (len
== 9)) {
867 printf("\t\tVenue Group: %i (%s)\n",
868 (int)(data
[1]), vgroup_11u(data
[1]));
869 printf("\t\tVenue Type: %i\n", (int)(data
[2]));
872 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
873 data
[3], data
[4], data
[5], data
[6], data
[7], data
[8]);
875 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
876 data
[1], data
[2], data
[3], data
[4], data
[5], data
[6]);
879 static void print_11u_advert(const uint8_t type
, uint8_t len
, const uint8_t *data
)
881 /* See Section 7.3.2.93 in the 802.11u spec. */
882 /* TODO: This code below does not decode private protocol IDs */
885 while (idx
< (len
- 1)) {
886 uint8_t qri
= data
[idx
];
887 uint8_t proto_id
= data
[idx
+ 1];
888 printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri
));
889 printf("\t\t\tQuery Response Length Limit: %i\n",
892 printf("\t\t\tPAME-BI\n");
895 printf("\t\t\tANQP\n"); break;
897 printf("\t\t\tMIH Information Service\n"); break;
899 printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
901 printf("\t\t\tEmergency Alert System (EAS)\n"); break;
903 printf("\t\t\tVendor Specific\n"); break;
905 printf("\t\t\tReserved: %i\n", proto_id
); break;
911 static void print_11u_rcon(const uint8_t type
, uint8_t len
, const uint8_t *data
)
913 /* See Section 7.3.2.96 in the 802.11u spec. */
915 int ln0
= data
[1] & 0xf;
916 int ln1
= ((data
[1] & 0xf0) >> 4);
921 ln2
= len
- 2 - ln0
- ln1
;
923 printf("\t\tANQP OIs: %i\n", data
[0]);
926 printf("\t\tOI 1: ");
928 printf("Invalid IE length.\n");
930 for (idx
= 0; idx
< ln0
; idx
++) {
931 printf("%02hx", data
[2 + idx
]);
938 printf("\t\tOI 2: ");
939 if (2 + ln0
+ ln1
> len
) {
940 printf("Invalid IE length.\n");
942 for (idx
= 0; idx
< ln1
; idx
++) {
943 printf("%02hx", data
[2 + ln0
+ idx
]);
950 printf("\t\tOI 3: ");
951 if (2 + ln0
+ ln1
+ ln2
> len
) {
952 printf("Invalid IE length.\n");
954 for (idx
= 0; idx
< ln2
; idx
++) {
955 printf("%02hx", data
[2 + ln0
+ ln1
+ idx
]);
962 static const char *ht_secondary_offset
[4] = {
969 static void print_ht_op(const uint8_t type
, uint8_t len
, const uint8_t *data
)
971 static const char *protection
[4] = {
977 static const char *sta_chan_width
[2] = {
983 printf("\t\t * primary channel: %d\n", data
[0]);
984 printf("\t\t * secondary channel offset: %s\n",
985 ht_secondary_offset
[data
[1] & 0x3]);
986 printf("\t\t * STA channel width: %s\n", sta_chan_width
[(data
[1] & 0x4)>>2]);
987 printf("\t\t * RIFS: %d\n", (data
[1] & 0x8)>>3);
988 printf("\t\t * HT protection: %s\n", protection
[data
[2] & 0x3]);
989 printf("\t\t * non-GF present: %d\n", (data
[2] & 0x4) >> 2);
990 printf("\t\t * OBSS non-GF present: %d\n", (data
[2] & 0x10) >> 4);
991 printf("\t\t * dual beacon: %d\n", (data
[4] & 0x40) >> 6);
992 printf("\t\t * dual CTS protection: %d\n", (data
[4] & 0x80) >> 7);
993 printf("\t\t * STBC beacon: %d\n", data
[5] & 0x1);
994 printf("\t\t * L-SIG TXOP Prot: %d\n", (data
[5] & 0x2) >> 1);
995 printf("\t\t * PCO active: %d\n", (data
[5] & 0x4) >> 2);
996 printf("\t\t * PCO phase: %d\n", (data
[5] & 0x8) >> 3);
999 static void print_capabilities(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1005 for (i
= 0; i
< len
; i
++) {
1008 for (bit
= 0; bit
< 8; bit
++) {
1009 if (!(data
[i
] & (1 << bit
)))
1017 #define CAPA(bit, name) case bit: printf(" " name); break
1019 switch (bit
+ base
) {
1020 CAPA(0, "HT Information Exchange Supported");
1021 CAPA(1, "reserved (On-demand Beacon)");
1022 CAPA(2, "Extended Channel Switching");
1023 CAPA(3, "reserved (Wave Indication)");
1024 CAPA(4, "PSMP Capability");
1025 CAPA(5, "reserved (Service Interval Granularity)");
1026 CAPA(6, "S-PSMP Capability");
1028 CAPA(8, "Diagnostics");
1029 CAPA(9, "Multicast Diagnostics");
1030 CAPA(10, "Location Tracking");
1032 CAPA(12, "Proxy ARP Service");
1033 CAPA(13, "Collocated Interference Reporting");
1034 CAPA(14, "Civic Location");
1035 CAPA(15, "Geospatial Location");
1037 CAPA(17, "WNM-Sleep Mode");
1038 CAPA(18, "TIM Broadcast");
1039 CAPA(19, "BSS Transition");
1040 CAPA(20, "QoS Traffic Capability");
1041 CAPA(21, "AC Station Count");
1042 CAPA(22, "Multiple BSSID");
1043 CAPA(23, "Timing Measurement");
1044 CAPA(24, "Channel Usage");
1045 CAPA(25, "SSID List");
1047 CAPA(27, "UTC TSF Offset");
1048 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1049 CAPA(29, "TDLS Peer PSM Support");
1050 CAPA(30, "TDLS channel switching");
1051 CAPA(31, "Interworking");
1052 CAPA(32, "QoS Map");
1054 CAPA(34, "SSPN Interface");
1055 CAPA(35, "Reserved");
1056 CAPA(36, "MSGCF Capability");
1057 CAPA(37, "TDLS Support");
1058 CAPA(38, "TDLS Prohibited");
1059 CAPA(39, "TDLS Channel Switching Prohibited");
1060 CAPA(40, "Reject Unadmitted Frame");
1061 CAPA(44, "Identifier Location");
1062 CAPA(45, "U-APSD Coexistence");
1063 CAPA(46, "WNM-Notification");
1064 CAPA(47, "Reserved");
1065 CAPA(48, "UTF-8 SSID");
1077 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1079 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1081 data
[0], data
[1], data
[2], data
[3]);
1083 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
1087 static void print_ibssatim(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1089 printf(" %d TUs", (data
[1] << 8) + data
[0]);
1092 static void print_vht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1095 print_vht_info(data
[0] | (data
[1] << 8) |
1096 (data
[2] << 16) | (data
[3] << 24),
1100 static void print_vht_oper(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1102 const char *chandwidths
[] = {
1103 [0] = "20 or 40 MHz",
1110 printf("\t\t * channel width: %d (%s)\n", data
[0],
1111 data
[0] < ARRAY_SIZE(chandwidths
) ? chandwidths
[data
[0]] : "unknown");
1112 printf("\t\t * center freq segment 1: %d\n", data
[1]);
1113 printf("\t\t * center freq segment 2: %d\n", data
[2]);
1114 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data
[4], data
[3]);
1117 static void print_obss_scan_params(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1120 printf("\t\t * passive dwell: %d TUs\n", (data
[1] << 8) | data
[0]);
1121 printf("\t\t * active dwell: %d TUs\n", (data
[3] << 8) | data
[2]);
1122 printf("\t\t * channel width trigger scan interval: %d s\n", (data
[5] << 8) | data
[4]);
1123 printf("\t\t * scan passive total per channel: %d TUs\n", (data
[7] << 8) | data
[6]);
1124 printf("\t\t * scan active total per channel: %d TUs\n", (data
[9] << 8) | data
[8]);
1125 printf("\t\t * BSS width channel transition delay factor: %d\n", (data
[11] << 8) | data
[10]);
1126 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1127 ((data
[13] << 8) | data
[12]) / 100, ((data
[13] << 8) | data
[12]) % 100);
1130 static void print_secchan_offs(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1132 if (data
[0] < ARRAY_SIZE(ht_secondary_offset
))
1133 printf(" %s (%d)\n", ht_secondary_offset
[data
[0]], data
[0]);
1135 printf(" %d\n", data
[0]);
1138 static void print_bss_load(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1141 printf("\t\t * station count: %d\n", (data
[1] << 8) | data
[0]);
1142 printf("\t\t * channel utilisation: %d/255\n", data
[2]);
1143 printf("\t\t * available admission capacity: %d [*32us]\n", (data
[4] << 8) | data
[3]);
1146 static void print_mesh_conf(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1149 printf("\t\t * Active Path Selection Protocol ID: %d\n", data
[0]);
1150 printf("\t\t * Active Path Selection Metric ID: %d\n", data
[1]);
1151 printf("\t\t * Congestion Control Mode ID: %d\n", data
[2]);
1152 printf("\t\t * Synchronization Method ID: %d\n", data
[3]);
1153 printf("\t\t * Authentication Protocol ID: %d\n", data
[4]);
1154 printf("\t\t * Mesh Formation Info:\n");
1155 printf("\t\t\t Number of Peerings: %d\n", (data
[5] & 0x7E) >> 1);
1157 printf("\t\t\t Connected to Mesh Gate\n");
1159 printf("\t\t\t Connected to AS\n");
1160 printf("\t\t * Mesh Capability\n");
1162 printf("\t\t\t Accepting Additional Mesh Peerings\n");
1164 printf("\t\t\t MCCA Supported\n");
1166 printf("\t\t\t MCCA Enabled\n");
1168 printf("\t\t\t Forwarding\n");
1170 printf("\t\t\t MBCA Supported\n");
1172 printf("\t\t\t TBTT Adjusting\n");
1174 printf("\t\t\t Mesh Power Save Level\n");
1179 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
);
1180 uint8_t minlen
, maxlen
;
1184 static void print_ie(const struct ie_print
*p
, const uint8_t type
,
1185 uint8_t len
, const uint8_t *data
)
1192 printf("\t%s:", p
->name
);
1193 if (len
< p
->minlen
|| len
> p
->maxlen
) {
1195 printf(" <invalid: %d bytes:", len
);
1196 for (i
= 0; i
< len
; i
++)
1197 printf(" %.02x", data
[i
]);
1200 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
1202 printf(" <invalid: no data>\n");
1206 p
->print(type
, len
, data
);
1209 #define PRINT_IGN { \
1216 static const struct ie_print ieprinters
[] = {
1217 [0] = { "SSID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1218 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1219 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
1220 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
1221 [6] = { "IBSS ATIM window", print_ibssatim
, 2, 2, BIT(PRINT_SCAN
), },
1222 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
1223 [11] = { "BSS Load", print_bss_load
, 5, 5, BIT(PRINT_SCAN
), },
1224 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
1225 [35] = { "TPC report", print_tpcreport
, 2, 2, BIT(PRINT_SCAN
), },
1226 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1227 [45] = { "HT capabilities", print_ht_capa
, 26, 26, BIT(PRINT_SCAN
), },
1228 [47] = { "ERP D4.0", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1229 [74] = { "Overlapping BSS scan params", print_obss_scan_params
, 14, 255, BIT(PRINT_SCAN
), },
1230 [61] = { "HT operation", print_ht_op
, 22, 22, BIT(PRINT_SCAN
), },
1231 [62] = { "Secondary Channel Offset", print_secchan_offs
, 1, 1, BIT(PRINT_SCAN
), },
1232 [191] = { "VHT capabilities", print_vht_capa
, 12, 255, BIT(PRINT_SCAN
), },
1233 [192] = { "VHT operation", print_vht_oper
, 5, 255, BIT(PRINT_SCAN
), },
1234 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
1235 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1236 [113] = { "MESH Configuration", print_mesh_conf
, 7, 7, BIT(PRINT_SCAN
), },
1237 [114] = { "MESH ID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1238 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
1239 [107] = { "802.11u Interworking", print_interworking
, 0, 255, BIT(PRINT_SCAN
), },
1240 [108] = { "802.11u Advertisement", print_11u_advert
, 0, 255, BIT(PRINT_SCAN
), },
1241 [111] = { "802.11u Roaming Consortium", print_11u_rcon
, 0, 255, BIT(PRINT_SCAN
), },
1244 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1246 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
1249 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
1252 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
1258 printf("Parameter: not version 1: ");
1262 printf("\t * Parameter version 1");
1267 printf("\n\t\t * u-APSD");
1271 for (i
= 0; i
< 4; i
++) {
1272 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
1275 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
1276 (1 << (data
[1] >> 4)) - 1);
1277 printf(", AIFSN %d", data
[0] & 0xf);
1278 if (data
[2] | data
[3])
1279 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
1287 printf("invalid: ");
1291 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1297 printf(" information:");
1300 if (print_wifi_wmm_param(data
+ 1, len
- 1))
1304 printf(" type %d:", data
[0]);
1308 for(i
= 1; i
< len
; i
++)
1309 printf(" %.02x", data
[i
]);
1313 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
1317 return "Default (PIN)";
1319 return "User-specified";
1321 return "Machine-specified";
1325 return "PushButton";
1327 return "Registrar-specified";
1333 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1336 __u16 subtype
, sublen
;
1339 subtype
= (data
[0] << 8) + data
[1];
1340 sublen
= (data
[2] << 8) + data
[3];
1346 tab_on_first(&first
);
1347 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
1350 tab_on_first(&first
);
1351 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
1355 tab_on_first(&first
);
1357 printf("\t * Device Password ID: (invalid "
1358 "length %d)\n", sublen
);
1361 id
= data
[4] << 8 | data
[5];
1362 printf("\t * Device Password ID: %u (%s)\n",
1363 id
, wifi_wps_dev_passwd_id(id
));
1367 tab_on_first(&first
);
1368 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
1371 tab_on_first(&first
);
1372 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
1375 tab_on_first(&first
);
1376 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
1380 tab_on_first(&first
);
1381 printf("\t * Response Type: %d%s\n",
1382 val
, val
== 3 ? " (AP)" : "");
1387 tab_on_first(&first
);
1388 printf("\t * RF Bands: 0x%x\n", val
);
1393 tab_on_first(&first
);
1394 printf("\t * Selected Registrar: 0x%x\n", val
);
1398 tab_on_first(&first
);
1399 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
1403 tab_on_first(&first
);
1404 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1406 val
== 1 ? " (Unconfigured)" : "",
1407 val
== 2 ? " (Configured)" : "");
1411 tab_on_first(&first
);
1412 printf("\t * UUID: ");
1414 printf("(invalid, length=%d)\n", sublen
);
1417 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1418 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1419 data
[4], data
[5], data
[6], data
[7],
1420 data
[8], data
[9], data
[10], data
[11],
1421 data
[12], data
[13], data
[14], data
[15],
1422 data
[16], data
[17], data
[18], data
[19]);
1425 tab_on_first(&first
);
1427 printf("\t * Primary Device Type: (invalid "
1428 "length %d)\n", sublen
);
1431 printf("\t * Primary Device Type: "
1432 "%u-%02x%02x%02x%02x-%u\n",
1433 data
[4] << 8 | data
[5],
1434 data
[6], data
[7], data
[8], data
[9],
1435 data
[10] << 8 | data
[11]);
1440 tab_on_first(&first
);
1441 printf("\t * AP setup locked: 0x%.2x\n", val
);
1446 __u16 meth
= (data
[4] << 8) + data
[5];
1448 tab_on_first(&first
);
1449 printf("\t * %sConfig methods:",
1450 subtype
== 0x1053 ? "Selected Registrar ": "");
1451 #define T(bit, name) do { \
1452 if (meth & (1<<bit)) { \
1472 const __u8
*subdata
= data
+ 4;
1473 __u16 tmplen
= sublen
;
1475 tab_on_first(&first
);
1476 printf("\t * Unknown TLV (%#.4x, %d bytes):",
1479 printf(" %.2x", *subdata
);
1493 printf("\t\t * bogus tail data (%d):", len
);
1495 printf(" %.2x", *data
);
1503 static const struct ie_print wifiprinters
[] = {
1504 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
1505 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
1506 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
1509 static inline void print_p2p(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1517 sublen
= (data
[2] << 8) + data
[1];
1519 if (sublen
> len
- 3)
1523 case 0x02: /* capability */
1524 tab_on_first(&first
);
1526 printf("\t * malformed capability\n");
1529 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
1532 case 0x0d: /* device info */
1533 if (sublen
< 6 + 2 + 8 + 1) {
1534 printf("\t * malformed device info\n");
1537 /* fall through for now */
1538 case 0x00: /* status */
1539 case 0x01: /* minor reason */
1540 case 0x03: /* device ID */
1541 case 0x04: /* GO intent */
1542 case 0x05: /* configuration timeout */
1543 case 0x06: /* listen channel */
1544 case 0x07: /* group BSSID */
1545 case 0x08: /* ext listen timing */
1546 case 0x09: /* intended interface address */
1547 case 0x0a: /* manageability */
1548 case 0x0b: /* channel list */
1549 case 0x0c: /* NoA */
1550 case 0x0e: /* group info */
1551 case 0x0f: /* group ID */
1552 case 0x10: /* interface */
1553 case 0x11: /* operating channel */
1554 case 0x12: /* invitation flags */
1555 case 0xdd: /* vendor specific */
1557 const __u8
*subdata
= data
+ 4;
1558 __u16 tmplen
= sublen
;
1560 tab_on_first(&first
);
1561 printf("\t * Unknown TLV (%#.2x, %d bytes):",
1564 printf(" %.2x", *subdata
);
1578 tab_on_first(&first
);
1579 printf("\t * bogus tail data (%d):", len
);
1581 printf(" %.2x", *data
);
1589 static inline void print_hs20_ind(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1591 /* I can't find the spec for this...just going off what wireshark uses. */
1594 printf("\t\tDGAF: %i\n", (int)(data
[0] & 0x1));
1596 printf("\t\tUnexpected length: %i\n", len
);
1599 static const struct ie_print wfa_printers
[] = {
1600 [9] = { "P2P", print_p2p
, 2, 255, BIT(PRINT_SCAN
), },
1601 [16] = { "HotSpot 2.0 Indication", print_hs20_ind
, 1, 255, BIT(PRINT_SCAN
), },
1604 static void print_vendor(unsigned char len
, unsigned char *data
,
1605 bool unknown
, enum print_ie_type ptype
)
1610 printf("\tVendor specific: <too short> data:");
1611 for(i
= 0; i
< len
; i
++)
1612 printf(" %.02x", data
[i
]);
1617 if (len
>= 4 && memcmp(data
, ms_oui
, 3) == 0) {
1618 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
1619 wifiprinters
[data
[3]].name
&&
1620 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
1621 print_ie(&wifiprinters
[data
[3]], data
[3], len
- 4, data
+ 4);
1626 printf("\tMS/WiFi %#.2x, data:", data
[3]);
1627 for(i
= 0; i
< len
- 4; i
++)
1628 printf(" %.02x", data
[i
+ 4]);
1633 if (len
>= 4 && memcmp(data
, wfa_oui
, 3) == 0) {
1634 if (data
[3] < ARRAY_SIZE(wfa_printers
) &&
1635 wfa_printers
[data
[3]].name
&&
1636 wfa_printers
[data
[3]].flags
& BIT(ptype
)) {
1637 print_ie(&wfa_printers
[data
[3]], data
[3], len
- 4, data
+ 4);
1642 printf("\tWFA %#.2x, data:", data
[3]);
1643 for(i
= 0; i
< len
- 4; i
++)
1644 printf(" %.02x", data
[i
+ 4]);
1652 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
1653 data
[0], data
[1], data
[2]);
1654 for (i
= 3; i
< len
; i
++)
1655 printf(" %.2x", data
[i
]);
1659 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
1660 enum print_ie_type ptype
)
1662 while (ielen
>= 2 && ielen
>= ie
[1]) {
1663 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
1664 ieprinters
[ie
[0]].name
&&
1665 ieprinters
[ie
[0]].flags
& BIT(ptype
)) {
1666 print_ie(&ieprinters
[ie
[0]], ie
[0], ie
[1], ie
+ 2);
1667 } else if (ie
[0] == 221 /* vendor */) {
1668 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
1669 } else if (unknown
) {
1672 printf("\tUnknown IE (%d):", ie
[0]);
1673 for (i
=0; i
<ie
[1]; i
++)
1674 printf(" %.2x", ie
[2+i
]);
1682 static void print_capa_dmg(__u16 capa
)
1684 switch (capa
& WLAN_CAPABILITY_DMG_TYPE_MASK
) {
1685 case WLAN_CAPABILITY_DMG_TYPE_AP
:
1688 case WLAN_CAPABILITY_DMG_TYPE_PBSS
:
1691 case WLAN_CAPABILITY_DMG_TYPE_IBSS
:
1692 printf(" DMG_IBSS");
1696 if (capa
& WLAN_CAPABILITY_DMG_CBAP_ONLY
)
1697 printf(" CBAP_Only");
1698 if (capa
& WLAN_CAPABILITY_DMG_CBAP_SOURCE
)
1699 printf(" CBAP_Src");
1700 if (capa
& WLAN_CAPABILITY_DMG_PRIVACY
)
1702 if (capa
& WLAN_CAPABILITY_DMG_ECPAC
)
1704 if (capa
& WLAN_CAPABILITY_DMG_SPECTRUM_MGMT
)
1705 printf(" SpectrumMgmt");
1706 if (capa
& WLAN_CAPABILITY_DMG_RADIO_MEASURE
)
1707 printf(" RadioMeasure");
1710 static void print_capa_non_dmg(__u16 capa
)
1712 if (capa
& WLAN_CAPABILITY_ESS
)
1714 if (capa
& WLAN_CAPABILITY_IBSS
)
1716 if (capa
& WLAN_CAPABILITY_CF_POLLABLE
)
1717 printf(" CfPollable");
1718 if (capa
& WLAN_CAPABILITY_CF_POLL_REQUEST
)
1719 printf(" CfPollReq");
1720 if (capa
& WLAN_CAPABILITY_PRIVACY
)
1722 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
1723 printf(" ShortPreamble");
1724 if (capa
& WLAN_CAPABILITY_PBCC
)
1726 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
1727 printf(" ChannelAgility");
1728 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
1729 printf(" SpectrumMgmt");
1730 if (capa
& WLAN_CAPABILITY_QOS
)
1732 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
1733 printf(" ShortSlotTime");
1734 if (capa
& WLAN_CAPABILITY_APSD
)
1736 if (capa
& WLAN_CAPABILITY_RADIO_MEASURE
)
1737 printf(" RadioMeasure");
1738 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
1739 printf(" DSSS-OFDM");
1740 if (capa
& WLAN_CAPABILITY_DEL_BACK
)
1741 printf(" DelayedBACK");
1742 if (capa
& WLAN_CAPABILITY_IMM_BACK
)
1743 printf(" ImmediateBACK");
1746 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
1748 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
1749 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
1750 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
1751 char mac_addr
[20], dev
[20];
1752 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
1753 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
1754 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
1755 [NL80211_BSS_BSSID
] = { },
1756 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
1757 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
1758 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
1759 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
1760 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
1761 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
1762 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
1763 [NL80211_BSS_BEACON_IES
] = { },
1765 struct scan_params
*params
= arg
;
1766 int show
= params
->show_both_ie_sets
? 2 : 1;
1767 bool is_dmg
= false;
1769 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
1770 genlmsg_attrlen(gnlh
, 0), NULL
);
1772 if (!tb
[NL80211_ATTR_BSS
]) {
1773 fprintf(stderr
, "bss info missing!\n");
1776 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
1777 tb
[NL80211_ATTR_BSS
],
1779 fprintf(stderr
, "failed to parse nested attributes!\n");
1783 if (!bss
[NL80211_BSS_BSSID
])
1786 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
1787 printf("BSS %s", mac_addr
);
1788 if (tb
[NL80211_ATTR_IFINDEX
]) {
1789 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
1790 printf("(on %s)", dev
);
1793 if (bss
[NL80211_BSS_STATUS
]) {
1794 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
1795 case NL80211_BSS_STATUS_AUTHENTICATED
:
1796 printf(" -- authenticated");
1798 case NL80211_BSS_STATUS_ASSOCIATED
:
1799 printf(" -- associated");
1801 case NL80211_BSS_STATUS_IBSS_JOINED
:
1802 printf(" -- joined");
1805 printf(" -- unknown status: %d",
1806 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
1812 if (bss
[NL80211_BSS_TSF
]) {
1813 unsigned long long tsf
;
1814 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
1815 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
1816 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
1817 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
1819 if (bss
[NL80211_BSS_FREQUENCY
]) {
1820 int freq
= nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]);
1821 printf("\tfreq: %d\n", freq
);
1825 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
1826 printf("\tbeacon interval: %d TUs\n",
1827 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
1828 if (bss
[NL80211_BSS_CAPABILITY
]) {
1829 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
1830 printf("\tcapability:");
1832 print_capa_dmg(capa
);
1834 print_capa_non_dmg(capa
);
1835 printf(" (0x%.4x)\n", capa
);
1837 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
1838 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
1839 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
1841 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
1842 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
1843 printf("\tsignal: %d/100\n", s
);
1845 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
1846 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
1847 printf("\tlast seen: %d ms ago\n", age
);
1850 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
1851 if (bss
[NL80211_BSS_BEACON_IES
])
1852 printf("\tInformation elements from Probe Response "
1854 print_ies(nla_data(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
1855 nla_len(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
1856 params
->unknown
, params
->type
);
1858 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
1859 printf("\tInformation elements from Beacon frame:\n");
1860 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
1861 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
1862 params
->unknown
, params
->type
);
1868 static struct scan_params scan_params
;
1870 static int handle_scan_dump(struct nl80211_state
*state
,
1873 int argc
, char **argv
,
1879 memset(&scan_params
, 0, sizeof(scan_params
));
1881 if (argc
== 1 && !strcmp(argv
[0], "-u"))
1882 scan_params
.unknown
= true;
1883 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
1884 scan_params
.show_both_ie_sets
= true;
1886 scan_params
.type
= PRINT_SCAN
;
1888 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_bss_handler
,
1893 static int handle_scan_combined(struct nl80211_state
*state
,
1896 int argc
, char **argv
,
1900 static char *dump_argv
[] = {
1906 static const __u32 cmds
[] = {
1907 NL80211_CMD_NEW_SCAN_RESULTS
,
1908 NL80211_CMD_SCAN_ABORTED
,
1910 int trig_argc
, dump_argc
, err
;
1912 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
1914 dump_argv
[3] = "-u";
1915 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
1917 dump_argv
[3] = "-b";
1921 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
1922 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
1925 trig_argv
[0] = argv
[0];
1926 trig_argv
[1] = "scan";
1927 trig_argv
[2] = "trigger";
1929 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
1930 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
1931 err
= handle_cmd(state
, id
, trig_argc
, trig_argv
);
1937 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
1939 * This code has a bug, which requires creating a separate
1940 * nl80211 socket to fix:
1941 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
1942 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
1943 * before (!) we listen to it, because we only start listening
1944 * after we send our scan request.
1946 * Doing it the other way around has a race condition as well,
1947 * if you first open the events socket you may get a notification
1948 * for a previous scan.
1950 * The only proper way to fix this would be to listen to events
1951 * before sending the command, and for the kernel to send the
1952 * scan request along with the event, so that you can match up
1953 * whether the scan you requested was finished or aborted (this
1954 * may result in processing a scan that another application
1955 * requested, but that doesn't seem to be a problem).
1957 * Alas, the kernel doesn't do that (yet).
1960 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
1961 NL80211_CMD_SCAN_ABORTED
) {
1962 printf("scan aborted!\n");
1966 dump_argv
[0] = argv
[0];
1967 return handle_cmd(state
, id
, dump_argc
, dump_argv
);
1969 TOPLEVEL(scan
, "[-u] [freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]", 0, 0,
1970 CIB_NETDEV
, handle_scan_combined
,
1971 "Scan on the given frequencies and probe for the given SSIDs\n"
1972 "(or wildcard if not given) unless passive scanning is requested.\n"
1973 "If -u is specified print unknown data in the scan results.\n"
1974 "Specified (vendor) IEs must be well-formed.");
1975 COMMAND(scan
, dump
, "[-u]",
1976 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
1977 "Dump the current scan results. If -u is specified, print unknown\n"
1978 "data in scan results.");
1979 COMMAND(scan
, trigger
, "[freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]",
1980 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
1981 "Trigger a scan on the given frequencies with probing for the given\n"
1982 "SSIDs (or wildcard if not given) unless passive scanning is requested.");
1985 static int handle_start_sched_scan(struct nl80211_state
*state
,
1986 struct nl_cb
*cb
, struct nl_msg
*msg
,
1987 int argc
, char **argv
, enum id_input id
)
1989 return parse_sched_scan(msg
, &argc
, &argv
);
1992 static int handle_stop_sched_scan(struct nl80211_state
*state
, struct nl_cb
*cb
,
1993 struct nl_msg
*msg
, int argc
, char **argv
,
2002 COMMAND(scan
, sched_start
,
2004 NL80211_CMD_START_SCHED_SCAN
, 0, CIB_NETDEV
, handle_start_sched_scan
,
2005 "Start a scheduled scan at the specified interval on the given frequencies\n"
2006 "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2007 "scanning is requested. If matches are specified, only matching results\n"
2008 "will be returned.");
2009 COMMAND(scan
, sched_stop
, "",
2010 NL80211_CMD_STOP_SCHED_SCAN
, 0, CIB_NETDEV
, handle_stop_sched_scan
,
2011 "Stop an ongoing scheduled scan.");