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 static int handle_scan(struct nl80211_state
*state
,
105 int argc
, char **argv
,
108 struct nl_msg
*ssids
= NULL
, *freqs
= NULL
;
121 bool passive
= false, have_ssids
= false, have_freqs
= false;
122 size_t ies_len
= 0, meshid_len
= 0;
123 unsigned char *ies
= NULL
, *meshid
= NULL
, *tmpies
;
124 unsigned int flags
= 0;
126 ssids
= nlmsg_alloc();
130 freqs
= nlmsg_alloc();
136 for (i
= 0; i
< argc
; i
++) {
139 if (strcmp(argv
[i
], "freq") == 0) {
143 } else if (strcmp(argv
[i
], "ies") == 0) {
146 } else if (strcmp(argv
[i
], "lowpri") == 0) {
147 flags
|= NL80211_SCAN_FLAG_LOW_PRIORITY
;
149 } else if (strcmp(argv
[i
], "flush") == 0) {
150 flags
|= NL80211_SCAN_FLAG_FLUSH
;
152 } else if (strcmp(argv
[i
], "ap-force") == 0) {
153 flags
|= NL80211_SCAN_FLAG_AP
;
155 } else if (strncmp(argv
[i
], "randomise", 9) == 0 ||
156 strncmp(argv
[i
], "randomize", 9) == 0) {
157 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
158 err
= parse_random_mac_addr(msg
, argv
[i
]);
160 goto nla_put_failure
;
162 } else if (strcmp(argv
[i
], "ssid") == 0) {
166 } else if (strcmp(argv
[i
], "passive") == 0) {
170 } else if (strcmp(argv
[i
], "meshid") == 0) {
177 freq
= strtoul(argv
[i
], &eptr
, 10);
178 if (eptr
!= argv
[i
] + strlen(argv
[i
])) {
179 /* failed to parse as number -- maybe a tag? */
184 NLA_PUT_U32(freqs
, i
, freq
);
187 ies
= parse_hex(argv
[i
], &ies_len
);
189 goto nla_put_failure
;
193 NLA_PUT(ssids
, i
, strlen(argv
[i
]), argv
[i
]);
196 meshid_len
= strlen(argv
[i
]);
197 meshid
= (unsigned char *) malloc(meshid_len
+ 2);
199 goto nla_put_failure
;
200 meshid
[0] = 114; /* mesh element id */
201 meshid
[1] = meshid_len
;
202 memcpy(&meshid
[2], argv
[i
], meshid_len
);
210 tmpies
= (unsigned char *) malloc(ies_len
+ meshid_len
);
212 goto nla_put_failure
;
214 memcpy(tmpies
, ies
, ies_len
);
218 memcpy(&tmpies
[ies_len
], meshid
, meshid_len
);
221 NLA_PUT(msg
, NL80211_ATTR_IE
, ies_len
+ meshid_len
, tmpies
);
226 NLA_PUT(ssids
, 1, 0, "");
228 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
231 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
233 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
242 static void tab_on_first(bool *first
)
250 static void print_ssid(const uint8_t type
, uint8_t len
, const uint8_t *data
)
253 print_ssid_escaped(len
, data
);
257 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
258 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
260 static void print_supprates(const uint8_t type
, uint8_t len
, const uint8_t *data
)
266 for (i
= 0; i
< len
; i
++) {
267 int r
= data
[i
] & 0x7f;
269 if (r
== BSS_MEMBERSHIP_SELECTOR_VHT_PHY
&& data
[i
] & 0x80)
271 else if (r
== BSS_MEMBERSHIP_SELECTOR_HT_PHY
&& data
[i
] & 0x80)
274 printf("%d.%d", r
/2, 5*(r
&1));
276 printf("%s ", data
[i
] & 0x80 ? "*" : "");
281 static void print_ds(const uint8_t type
, uint8_t len
, const uint8_t *data
)
283 printf(" channel %d\n", data
[0]);
286 static const char *country_env_str(char environment
)
288 switch (environment
) {
290 return "Indoor only";
292 return "Outdoor only";
294 return "Indoor/Outdoor";
300 static void print_country(const uint8_t type
, uint8_t len
, const uint8_t *data
)
302 printf(" %.*s", 2, data
);
304 printf("\tEnvironment: %s\n", country_env_str(data
[2]));
310 printf("\t\tNo country IE triplets present\n");
316 union ieee80211_country_ie_triplet
*triplet
= (void *) data
;
318 if (triplet
->ext
.reg_extension_id
>= IEEE80211_COUNTRY_EXTENSION_ID
) {
319 printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
320 triplet
->ext
.reg_extension_id
,
321 triplet
->ext
.reg_class
,
322 triplet
->ext
.coverage_class
,
323 triplet
->ext
.coverage_class
* 450);
331 if (triplet
->chans
.first_channel
<= 14)
332 end_channel
= triplet
->chans
.first_channel
+ (triplet
->chans
.num_channels
- 1);
334 end_channel
= triplet
->chans
.first_channel
+ (4 * (triplet
->chans
.num_channels
- 1));
336 printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet
->chans
.first_channel
, end_channel
, triplet
->chans
.max_power
);
345 static void print_powerconstraint(const uint8_t type
, uint8_t len
, const uint8_t *data
)
347 printf(" %d dB\n", data
[0]);
350 static void print_tpcreport(const uint8_t type
, uint8_t len
, const uint8_t *data
)
352 printf(" TX power: %d dBm\n", data
[0]);
353 /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
356 static void print_erp(const uint8_t type
, uint8_t len
, const uint8_t *data
)
359 printf(" <no flags>");
361 printf(" NonERP_Present");
363 printf(" Use_Protection");
365 printf(" Barker_Preamble_Mode");
369 static void print_cipher(const uint8_t *data
)
371 if (memcmp(data
, ms_oui
, 3) == 0) {
374 printf("Use group cipher suite");
389 printf("%.02x-%.02x-%.02x:%d",
390 data
[0], data
[1] ,data
[2], data
[3]);
393 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
396 printf("Use group cipher suite");
411 printf("AES-128-CMAC");
417 printf("%.02x-%.02x-%.02x:%d",
418 data
[0], data
[1] ,data
[2], data
[3]);
422 printf("%.02x-%.02x-%.02x:%d",
423 data
[0], data
[1] ,data
[2], data
[3]);
426 static void print_auth(const uint8_t *data
)
428 if (memcmp(data
, ms_oui
, 3) == 0) {
431 printf("IEEE 802.1X");
437 printf("%.02x-%.02x-%.02x:%d",
438 data
[0], data
[1] ,data
[2], data
[3]);
441 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
444 printf("IEEE 802.1X");
450 printf("FT/IEEE 802.1X");
456 printf("IEEE 802.1X/SHA-256");
459 printf("PSK/SHA-256");
465 printf("%.02x-%.02x-%.02x:%d",
466 data
[0], data
[1] ,data
[2], data
[3]);
470 printf("%.02x-%.02x-%.02x:%d",
471 data
[0], data
[1] ,data
[2], data
[3]);
474 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
475 uint8_t len
, const uint8_t *data
)
478 __u16 version
, count
, capa
;
481 version
= data
[0] + (data
[1] << 8);
482 tab_on_first(&first
);
483 printf("\t * Version: %d\n", version
);
489 tab_on_first(&first
);
490 printf("\t * Group cipher: %s\n", defcipher
);
491 printf("\t * Pairwise ciphers: %s\n", defcipher
);
495 tab_on_first(&first
);
496 printf("\t * Group cipher: ");
504 tab_on_first(&first
);
505 printf("\t * Pairwise ciphers: %s\n", defcipher
);
509 count
= data
[0] | (data
[1] << 8);
510 if (2 + (count
* 4) > len
)
513 tab_on_first(&first
);
514 printf("\t * Pairwise ciphers:");
515 for (i
= 0; i
< count
; i
++) {
517 print_cipher(data
+ 2 + (i
* 4));
521 data
+= 2 + (count
* 4);
522 len
-= 2 + (count
* 4);
525 tab_on_first(&first
);
526 printf("\t * Authentication suites: %s\n", defauth
);
530 count
= data
[0] | (data
[1] << 8);
531 if (2 + (count
* 4) > len
)
534 tab_on_first(&first
);
535 printf("\t * Authentication suites:");
536 for (i
= 0; i
< count
; i
++) {
538 print_auth(data
+ 2 + (i
* 4));
542 data
+= 2 + (count
* 4);
543 len
-= 2 + (count
* 4);
546 capa
= data
[0] | (data
[1] << 8);
547 tab_on_first(&first
);
548 printf("\t * Capabilities:");
552 printf(" NoPairwise");
553 switch ((capa
& 0x000c) >> 2) {
555 printf(" 1-PTKSA-RC");
558 printf(" 2-PTKSA-RC");
561 printf(" 4-PTKSA-RC");
564 printf(" 16-PTKSA-RC");
567 switch ((capa
& 0x0030) >> 4) {
569 printf(" 1-GTKSA-RC");
572 printf(" 2-GTKSA-RC");
575 printf(" 4-GTKSA-RC");
578 printf(" 16-GTKSA-RC");
582 printf(" MFP-required");
584 printf(" MFP-capable");
586 printf(" Peerkey-enabled");
588 printf(" SPP-AMSDU-capable");
590 printf(" SPP-AMSDU-required");
591 printf(" (0x%.4x)\n", capa
);
597 int pmkid_count
= data
[0] | (data
[1] << 8);
599 if (len
>= 2 + 16 * pmkid_count
) {
600 tab_on_first(&first
);
601 printf("\t * %d PMKIDs\n", pmkid_count
);
602 /* not printing PMKID values */
603 data
+= 2 + 16 * pmkid_count
;
604 len
-= 2 + 16 * pmkid_count
;
610 tab_on_first(&first
);
611 printf("\t * Group mgmt cipher suite: ");
620 printf("\t\t * bogus tail data (%d):", len
);
622 printf(" %.2x", *data
);
630 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
)
632 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
635 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
638 print_ht_capability(data
[0] | (data
[1] << 8));
639 print_ampdu_length(data
[2] & 3);
640 print_ampdu_spacing((data
[2] >> 2) & 7);
641 print_ht_mcs(data
+ 3);
644 static const char* ntype_11u(uint8_t t
)
647 case 0: return "Private";
648 case 1: return "Private with Guest";
649 case 2: return "Chargeable Public";
650 case 3: return "Free Public";
651 case 4: return "Personal Device";
652 case 5: return "Emergency Services Only";
653 case 14: return "Test or Experimental";
654 case 15: return "Wildcard";
655 default: return "Reserved";
659 static const char* vgroup_11u(uint8_t t
)
662 case 0: return "Unspecified";
663 case 1: return "Assembly";
664 case 2: return "Business";
665 case 3: return "Educational";
666 case 4: return "Factory and Industrial";
667 case 5: return "Institutional";
668 case 6: return "Mercantile";
669 case 7: return "Residential";
670 case 8: return "Storage";
671 case 9: return "Utility and Miscellaneous";
672 case 10: return "Vehicular";
673 case 11: return "Outdoor";
674 default: return "Reserved";
678 static void print_interworking(const uint8_t type
, uint8_t len
, const uint8_t *data
)
680 /* See Section 7.3.2.92 in the 802.11u spec. */
683 uint8_t ano
= data
[0];
684 printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano
));
685 printf("\t\t\tNetwork Type: %i (%s)\n",
686 (int)(ano
& 0xf), ntype_11u(ano
& 0xf));
688 printf("\t\t\tInternet\n");
690 printf("\t\t\tASRA\n");
692 printf("\t\t\tESR\n");
694 printf("\t\t\tUESA\n");
696 if ((len
== 3) || (len
== 9)) {
697 printf("\t\tVenue Group: %i (%s)\n",
698 (int)(data
[1]), vgroup_11u(data
[1]));
699 printf("\t\tVenue Type: %i\n", (int)(data
[2]));
702 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
703 data
[3], data
[4], data
[5], data
[6], data
[7], data
[8]);
705 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
706 data
[1], data
[2], data
[3], data
[4], data
[5], data
[6]);
709 static void print_11u_advert(const uint8_t type
, uint8_t len
, const uint8_t *data
)
711 /* See Section 7.3.2.93 in the 802.11u spec. */
712 /* TODO: This code below does not decode private protocol IDs */
715 while (idx
< (len
- 1)) {
716 uint8_t qri
= data
[idx
];
717 uint8_t proto_id
= data
[idx
+ 1];
718 printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri
));
719 printf("\t\t\tQuery Response Length Limit: %i\n",
722 printf("\t\t\tPAME-BI\n");
725 printf("\t\t\tANQP\n"); break;
727 printf("\t\t\tMIH Information Service\n"); break;
729 printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
731 printf("\t\t\tEmergency Alert System (EAS)\n"); break;
733 printf("\t\t\tVendor Specific\n"); break;
735 printf("\t\t\tReserved: %i\n", proto_id
); break;
741 static void print_11u_rcon(const uint8_t type
, uint8_t len
, const uint8_t *data
)
743 /* See Section 7.3.2.96 in the 802.11u spec. */
745 int ln0
= data
[1] & 0xf;
746 int ln1
= ((data
[1] & 0xf0) >> 4);
751 ln2
= len
- 2 - ln0
- ln1
;
753 printf("\t\tANQP OIs: %i\n", data
[0]);
756 printf("\t\tOI 1: ");
758 printf("Invalid IE length.\n");
760 for (idx
= 0; idx
< ln0
; idx
++) {
761 printf("%02hx", data
[2 + idx
]);
768 printf("\t\tOI 2: ");
769 if (2 + ln0
+ ln1
> len
) {
770 printf("Invalid IE length.\n");
772 for (idx
= 0; idx
< ln1
; idx
++) {
773 printf("%02hx", data
[2 + ln0
+ idx
]);
780 printf("\t\tOI 3: ");
781 if (2 + ln0
+ ln1
+ ln2
> len
) {
782 printf("Invalid IE length.\n");
784 for (idx
= 0; idx
< ln2
; idx
++) {
785 printf("%02hx", data
[2 + ln0
+ ln1
+ idx
]);
792 static const char *ht_secondary_offset
[4] = {
799 static void print_ht_op(const uint8_t type
, uint8_t len
, const uint8_t *data
)
801 static const char *protection
[4] = {
807 static const char *sta_chan_width
[2] = {
813 printf("\t\t * primary channel: %d\n", data
[0]);
814 printf("\t\t * secondary channel offset: %s\n",
815 ht_secondary_offset
[data
[1] & 0x3]);
816 printf("\t\t * STA channel width: %s\n", sta_chan_width
[(data
[1] & 0x4)>>2]);
817 printf("\t\t * RIFS: %d\n", (data
[1] & 0x8)>>3);
818 printf("\t\t * HT protection: %s\n", protection
[data
[2] & 0x3]);
819 printf("\t\t * non-GF present: %d\n", (data
[2] & 0x4) >> 2);
820 printf("\t\t * OBSS non-GF present: %d\n", (data
[2] & 0x10) >> 4);
821 printf("\t\t * dual beacon: %d\n", (data
[4] & 0x40) >> 6);
822 printf("\t\t * dual CTS protection: %d\n", (data
[4] & 0x80) >> 7);
823 printf("\t\t * STBC beacon: %d\n", data
[5] & 0x1);
824 printf("\t\t * L-SIG TXOP Prot: %d\n", (data
[5] & 0x2) >> 1);
825 printf("\t\t * PCO active: %d\n", (data
[5] & 0x4) >> 2);
826 printf("\t\t * PCO phase: %d\n", (data
[5] & 0x8) >> 3);
829 static void print_capabilities(const uint8_t type
, uint8_t len
, const uint8_t *data
)
835 for (i
= 0; i
< len
; i
++) {
838 for (bit
= 0; bit
< 8; bit
++) {
839 if (!(data
[i
] & (1 << bit
)))
847 #define CAPA(bit, name) case bit: printf(" " name); break
849 switch (bit
+ base
) {
850 CAPA(0, "HT Information Exchange Supported");
851 CAPA(1, "reserved (On-demand Beacon)");
852 CAPA(2, "Extended Channel Switching");
853 CAPA(3, "reserved (Wave Indication)");
854 CAPA(4, "PSMP Capability");
855 CAPA(5, "reserved (Service Interval Granularity)");
856 CAPA(6, "S-PSMP Capability");
858 CAPA(8, "Diagnostics");
859 CAPA(9, "Multicast Diagnostics");
860 CAPA(10, "Location Tracking");
862 CAPA(12, "Proxy ARP Service");
863 CAPA(13, "Collocated Interference Reporting");
864 CAPA(14, "Civic Location");
865 CAPA(15, "Geospatial Location");
867 CAPA(17, "WNM-Sleep Mode");
868 CAPA(18, "TIM Broadcast");
869 CAPA(19, "BSS Transition");
870 CAPA(20, "QoS Traffic Capability");
871 CAPA(21, "AC Station Count");
872 CAPA(22, "Multiple BSSID");
873 CAPA(23, "Timing Measurement");
874 CAPA(24, "Channel Usage");
875 CAPA(25, "SSID List");
877 CAPA(27, "UTC TSF Offset");
878 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
879 CAPA(29, "TDLS Peer PSM Support");
880 CAPA(30, "TDLS channel switching");
881 CAPA(31, "Interworking");
884 CAPA(34, "SSPN Interface");
885 CAPA(35, "Reserved");
886 CAPA(36, "MSGCF Capability");
887 CAPA(37, "TDLS Support");
888 CAPA(38, "TDLS Prohibited");
889 CAPA(39, "TDLS Channel Switching Prohibited");
890 CAPA(40, "Reject Unadmitted Frame");
891 CAPA(44, "Identifier Location");
892 CAPA(45, "U-APSD Coexistence");
893 CAPA(46, "WNM-Notification");
894 CAPA(47, "Reserved");
895 CAPA(48, "UTF-8 SSID");
907 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
)
909 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
911 data
[0], data
[1], data
[2], data
[3]);
913 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
917 static void print_ibssatim(const uint8_t type
, uint8_t len
, const uint8_t *data
)
919 printf(" %d TUs", (data
[1] << 8) + data
[0]);
922 static void print_vht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
925 print_vht_info(data
[0] | (data
[1] << 8) |
926 (data
[2] << 16) | (data
[3] << 24),
930 static void print_vht_oper(const uint8_t type
, uint8_t len
, const uint8_t *data
)
932 const char *chandwidths
[] = {
933 [0] = "20 or 40 MHz",
940 printf("\t\t * channel width: %d (%s)\n", data
[0],
941 data
[0] < ARRAY_SIZE(chandwidths
) ? chandwidths
[data
[0]] : "unknown");
942 printf("\t\t * center freq segment 1: %d\n", data
[1]);
943 printf("\t\t * center freq segment 2: %d\n", data
[2]);
944 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data
[4], data
[3]);
947 static void print_obss_scan_params(const uint8_t type
, uint8_t len
, const uint8_t *data
)
950 printf("\t\t * passive dwell: %d TUs\n", (data
[1] << 8) | data
[0]);
951 printf("\t\t * active dwell: %d TUs\n", (data
[3] << 8) | data
[2]);
952 printf("\t\t * channel width trigger scan interval: %d s\n", (data
[5] << 8) | data
[4]);
953 printf("\t\t * scan passive total per channel: %d TUs\n", (data
[7] << 8) | data
[6]);
954 printf("\t\t * scan active total per channel: %d TUs\n", (data
[9] << 8) | data
[8]);
955 printf("\t\t * BSS width channel transition delay factor: %d\n", (data
[11] << 8) | data
[10]);
956 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
957 ((data
[13] << 8) | data
[12]) / 100, ((data
[13] << 8) | data
[12]) % 100);
960 static void print_secchan_offs(const uint8_t type
, uint8_t len
, const uint8_t *data
)
962 if (data
[0] < ARRAY_SIZE(ht_secondary_offset
))
963 printf(" %s (%d)\n", ht_secondary_offset
[data
[0]], data
[0]);
965 printf(" %d\n", data
[0]);
968 static void print_bss_load(const uint8_t type
, uint8_t len
, const uint8_t *data
)
971 printf("\t\t * station count: %d\n", (data
[1] << 8) | data
[0]);
972 printf("\t\t * channel utilisation: %d/255\n", data
[2]);
973 printf("\t\t * available admission capacity: %d [*32us]\n", (data
[4] << 8) | data
[3]);
976 static void print_mesh_conf(const uint8_t type
, uint8_t len
, const uint8_t *data
)
979 printf("\t\t * Active Path Selection Protocol ID: %d\n", data
[0]);
980 printf("\t\t * Active Path Selection Metric ID: %d\n", data
[1]);
981 printf("\t\t * Congestion Control Mode ID: %d\n", data
[2]);
982 printf("\t\t * Synchronization Method ID: %d\n", data
[3]);
983 printf("\t\t * Authentication Protocol ID: %d\n", data
[4]);
984 printf("\t\t * Mesh Formation Info:\n");
985 printf("\t\t\t Number of Peerings: %d\n", (data
[5] & 0x7E) >> 1);
987 printf("\t\t\t Connected to Mesh Gate\n");
989 printf("\t\t\t Connected to AS\n");
990 printf("\t\t * Mesh Capability\n");
992 printf("\t\t\t Accepting Additional Mesh Peerings\n");
994 printf("\t\t\t MCCA Supported\n");
996 printf("\t\t\t MCCA Enabled\n");
998 printf("\t\t\t Forwarding\n");
1000 printf("\t\t\t MBCA Supported\n");
1002 printf("\t\t\t TBTT Adjusting\n");
1004 printf("\t\t\t Mesh Power Save Level\n");
1009 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
);
1010 uint8_t minlen
, maxlen
;
1014 static void print_ie(const struct ie_print
*p
, const uint8_t type
,
1015 uint8_t len
, const uint8_t *data
)
1022 printf("\t%s:", p
->name
);
1023 if (len
< p
->minlen
|| len
> p
->maxlen
) {
1025 printf(" <invalid: %d bytes:", len
);
1026 for (i
= 0; i
< len
; i
++)
1027 printf(" %.02x", data
[i
]);
1030 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
1032 printf(" <invalid: no data>\n");
1036 p
->print(type
, len
, data
);
1039 #define PRINT_IGN { \
1046 static const struct ie_print ieprinters
[] = {
1047 [0] = { "SSID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1048 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1049 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
1050 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
1051 [6] = { "IBSS ATIM window", print_ibssatim
, 2, 2, BIT(PRINT_SCAN
), },
1052 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
1053 [11] = { "BSS Load", print_bss_load
, 5, 5, BIT(PRINT_SCAN
), },
1054 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
1055 [35] = { "TPC report", print_tpcreport
, 2, 2, BIT(PRINT_SCAN
), },
1056 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1057 [45] = { "HT capabilities", print_ht_capa
, 26, 26, BIT(PRINT_SCAN
), },
1058 [47] = { "ERP D4.0", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1059 [74] = { "Overlapping BSS scan params", print_obss_scan_params
, 14, 255, BIT(PRINT_SCAN
), },
1060 [61] = { "HT operation", print_ht_op
, 22, 22, BIT(PRINT_SCAN
), },
1061 [62] = { "Secondary Channel Offset", print_secchan_offs
, 1, 1, BIT(PRINT_SCAN
), },
1062 [191] = { "VHT capabilities", print_vht_capa
, 12, 255, BIT(PRINT_SCAN
), },
1063 [192] = { "VHT operation", print_vht_oper
, 5, 255, BIT(PRINT_SCAN
), },
1064 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
1065 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1066 [113] = { "MESH Configuration", print_mesh_conf
, 7, 7, BIT(PRINT_SCAN
), },
1067 [114] = { "MESH ID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1068 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
1069 [107] = { "802.11u Interworking", print_interworking
, 0, 255, BIT(PRINT_SCAN
), },
1070 [108] = { "802.11u Advertisement", print_11u_advert
, 0, 255, BIT(PRINT_SCAN
), },
1071 [111] = { "802.11u Roaming Consortium", print_11u_rcon
, 0, 255, BIT(PRINT_SCAN
), },
1074 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1076 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
1079 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
1082 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
1088 printf("Parameter: not version 1: ");
1092 printf("\t * Parameter version 1");
1097 printf("\n\t\t * u-APSD");
1101 for (i
= 0; i
< 4; i
++) {
1102 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
1105 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
1106 (1 << (data
[1] >> 4)) - 1);
1107 printf(", AIFSN %d", data
[0] & 0xf);
1108 if (data
[2] | data
[3])
1109 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
1117 printf("invalid: ");
1121 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1127 printf(" information:");
1130 if (print_wifi_wmm_param(data
+ 1, len
- 1))
1134 printf(" type %d:", data
[0]);
1138 for(i
= 1; i
< len
; i
++)
1139 printf(" %.02x", data
[i
]);
1143 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
1147 return "Default (PIN)";
1149 return "User-specified";
1151 return "Machine-specified";
1155 return "PushButton";
1157 return "Registrar-specified";
1163 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1166 __u16 subtype
, sublen
;
1169 subtype
= (data
[0] << 8) + data
[1];
1170 sublen
= (data
[2] << 8) + data
[3];
1176 tab_on_first(&first
);
1177 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
1180 tab_on_first(&first
);
1181 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
1185 tab_on_first(&first
);
1187 printf("\t * Device Password ID: (invalid "
1188 "length %d)\n", sublen
);
1191 id
= data
[4] << 8 | data
[5];
1192 printf("\t * Device Password ID: %u (%s)\n",
1193 id
, wifi_wps_dev_passwd_id(id
));
1197 tab_on_first(&first
);
1198 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
1201 tab_on_first(&first
);
1202 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
1205 tab_on_first(&first
);
1206 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
1210 tab_on_first(&first
);
1211 printf("\t * Response Type: %d%s\n",
1212 val
, val
== 3 ? " (AP)" : "");
1217 tab_on_first(&first
);
1218 printf("\t * RF Bands: 0x%x\n", val
);
1223 tab_on_first(&first
);
1224 printf("\t * Selected Registrar: 0x%x\n", val
);
1228 tab_on_first(&first
);
1229 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
1233 tab_on_first(&first
);
1234 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1236 val
== 1 ? " (Unconfigured)" : "",
1237 val
== 2 ? " (Configured)" : "");
1241 tab_on_first(&first
);
1242 printf("\t * UUID: ");
1244 printf("(invalid, length=%d)\n", sublen
);
1247 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1248 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1249 data
[4], data
[5], data
[6], data
[7],
1250 data
[8], data
[9], data
[10], data
[11],
1251 data
[12], data
[13], data
[14], data
[15],
1252 data
[16], data
[17], data
[18], data
[19]);
1255 tab_on_first(&first
);
1257 printf("\t * Primary Device Type: (invalid "
1258 "length %d)\n", sublen
);
1261 printf("\t * Primary Device Type: "
1262 "%u-%02x%02x%02x%02x-%u\n",
1263 data
[4] << 8 | data
[5],
1264 data
[6], data
[7], data
[8], data
[9],
1265 data
[10] << 8 | data
[11]);
1270 tab_on_first(&first
);
1271 printf("\t * AP setup locked: 0x%.2x\n", val
);
1276 __u16 meth
= (data
[4] << 8) + data
[5];
1278 tab_on_first(&first
);
1279 printf("\t * %sConfig methods:",
1280 subtype
== 0x1053 ? "Selected Registrar ": "");
1281 #define T(bit, name) do { \
1282 if (meth & (1<<bit)) { \
1302 const __u8
*subdata
= data
+ 4;
1303 __u16 tmplen
= sublen
;
1305 tab_on_first(&first
);
1306 printf("\t * Unknown TLV (%#.4x, %d bytes):",
1309 printf(" %.2x", *subdata
);
1323 printf("\t\t * bogus tail data (%d):", len
);
1325 printf(" %.2x", *data
);
1333 static const struct ie_print wifiprinters
[] = {
1334 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
1335 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
1336 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
1339 static inline void print_p2p(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1347 sublen
= (data
[2] << 8) + data
[1];
1349 if (sublen
> len
- 3)
1353 case 0x02: /* capability */
1354 tab_on_first(&first
);
1356 printf("\t * malformed capability\n");
1359 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
1362 case 0x0d: /* device info */
1363 if (sublen
< 6 + 2 + 8 + 1) {
1364 printf("\t * malformed device info\n");
1367 /* fall through for now */
1368 case 0x00: /* status */
1369 case 0x01: /* minor reason */
1370 case 0x03: /* device ID */
1371 case 0x04: /* GO intent */
1372 case 0x05: /* configuration timeout */
1373 case 0x06: /* listen channel */
1374 case 0x07: /* group BSSID */
1375 case 0x08: /* ext listen timing */
1376 case 0x09: /* intended interface address */
1377 case 0x0a: /* manageability */
1378 case 0x0b: /* channel list */
1379 case 0x0c: /* NoA */
1380 case 0x0e: /* group info */
1381 case 0x0f: /* group ID */
1382 case 0x10: /* interface */
1383 case 0x11: /* operating channel */
1384 case 0x12: /* invitation flags */
1385 case 0xdd: /* vendor specific */
1387 const __u8
*subdata
= data
+ 4;
1388 __u16 tmplen
= sublen
;
1390 tab_on_first(&first
);
1391 printf("\t * Unknown TLV (%#.2x, %d bytes):",
1394 printf(" %.2x", *subdata
);
1408 tab_on_first(&first
);
1409 printf("\t * bogus tail data (%d):", len
);
1411 printf(" %.2x", *data
);
1419 static inline void print_hs20_ind(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1421 /* I can't find the spec for this...just going off what wireshark uses. */
1424 printf("\t\tDGAF: %i\n", (int)(data
[0] & 0x1));
1426 printf("\t\tUnexpected length: %i\n", len
);
1429 static const struct ie_print wfa_printers
[] = {
1430 [9] = { "P2P", print_p2p
, 2, 255, BIT(PRINT_SCAN
), },
1431 [16] = { "HotSpot 2.0 Indication", print_hs20_ind
, 1, 255, BIT(PRINT_SCAN
), },
1434 static void print_vendor(unsigned char len
, unsigned char *data
,
1435 bool unknown
, enum print_ie_type ptype
)
1440 printf("\tVendor specific: <too short> data:");
1441 for(i
= 0; i
< len
; i
++)
1442 printf(" %.02x", data
[i
]);
1447 if (len
>= 4 && memcmp(data
, ms_oui
, 3) == 0) {
1448 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
1449 wifiprinters
[data
[3]].name
&&
1450 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
1451 print_ie(&wifiprinters
[data
[3]], data
[3], len
- 4, data
+ 4);
1456 printf("\tMS/WiFi %#.2x, data:", data
[3]);
1457 for(i
= 0; i
< len
- 4; i
++)
1458 printf(" %.02x", data
[i
+ 4]);
1463 if (len
>= 4 && memcmp(data
, wfa_oui
, 3) == 0) {
1464 if (data
[3] < ARRAY_SIZE(wfa_printers
) &&
1465 wfa_printers
[data
[3]].name
&&
1466 wfa_printers
[data
[3]].flags
& BIT(ptype
)) {
1467 print_ie(&wfa_printers
[data
[3]], data
[3], len
- 4, data
+ 4);
1472 printf("\tWFA %#.2x, data:", data
[3]);
1473 for(i
= 0; i
< len
- 4; i
++)
1474 printf(" %.02x", data
[i
+ 4]);
1482 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
1483 data
[0], data
[1], data
[2]);
1484 for (i
= 3; i
< len
; i
++)
1485 printf(" %.2x", data
[i
]);
1489 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
1490 enum print_ie_type ptype
)
1492 while (ielen
>= 2 && ielen
>= ie
[1]) {
1493 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
1494 ieprinters
[ie
[0]].name
&&
1495 ieprinters
[ie
[0]].flags
& BIT(ptype
)) {
1496 print_ie(&ieprinters
[ie
[0]], ie
[0], ie
[1], ie
+ 2);
1497 } else if (ie
[0] == 221 /* vendor */) {
1498 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
1499 } else if (unknown
) {
1502 printf("\tUnknown IE (%d):", ie
[0]);
1503 for (i
=0; i
<ie
[1]; i
++)
1504 printf(" %.2x", ie
[2+i
]);
1512 static void print_capa_dmg(__u16 capa
)
1514 switch (capa
& WLAN_CAPABILITY_DMG_TYPE_MASK
) {
1515 case WLAN_CAPABILITY_DMG_TYPE_AP
:
1518 case WLAN_CAPABILITY_DMG_TYPE_PBSS
:
1521 case WLAN_CAPABILITY_DMG_TYPE_IBSS
:
1522 printf(" DMG_IBSS");
1526 if (capa
& WLAN_CAPABILITY_DMG_CBAP_ONLY
)
1527 printf(" CBAP_Only");
1528 if (capa
& WLAN_CAPABILITY_DMG_CBAP_SOURCE
)
1529 printf(" CBAP_Src");
1530 if (capa
& WLAN_CAPABILITY_DMG_PRIVACY
)
1532 if (capa
& WLAN_CAPABILITY_DMG_ECPAC
)
1534 if (capa
& WLAN_CAPABILITY_DMG_SPECTRUM_MGMT
)
1535 printf(" SpectrumMgmt");
1536 if (capa
& WLAN_CAPABILITY_DMG_RADIO_MEASURE
)
1537 printf(" RadioMeasure");
1540 static void print_capa_non_dmg(__u16 capa
)
1542 if (capa
& WLAN_CAPABILITY_ESS
)
1544 if (capa
& WLAN_CAPABILITY_IBSS
)
1546 if (capa
& WLAN_CAPABILITY_CF_POLLABLE
)
1547 printf(" CfPollable");
1548 if (capa
& WLAN_CAPABILITY_CF_POLL_REQUEST
)
1549 printf(" CfPollReq");
1550 if (capa
& WLAN_CAPABILITY_PRIVACY
)
1552 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
1553 printf(" ShortPreamble");
1554 if (capa
& WLAN_CAPABILITY_PBCC
)
1556 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
1557 printf(" ChannelAgility");
1558 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
1559 printf(" SpectrumMgmt");
1560 if (capa
& WLAN_CAPABILITY_QOS
)
1562 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
1563 printf(" ShortSlotTime");
1564 if (capa
& WLAN_CAPABILITY_APSD
)
1566 if (capa
& WLAN_CAPABILITY_RADIO_MEASURE
)
1567 printf(" RadioMeasure");
1568 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
1569 printf(" DSSS-OFDM");
1570 if (capa
& WLAN_CAPABILITY_DEL_BACK
)
1571 printf(" DelayedBACK");
1572 if (capa
& WLAN_CAPABILITY_IMM_BACK
)
1573 printf(" ImmediateBACK");
1576 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
1578 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
1579 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
1580 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
1581 char mac_addr
[20], dev
[20];
1582 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
1583 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
1584 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
1585 [NL80211_BSS_BSSID
] = { },
1586 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
1587 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
1588 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
1589 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
1590 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
1591 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
1592 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
1593 [NL80211_BSS_BEACON_IES
] = { },
1595 struct scan_params
*params
= arg
;
1596 int show
= params
->show_both_ie_sets
? 2 : 1;
1597 bool is_dmg
= false;
1599 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
1600 genlmsg_attrlen(gnlh
, 0), NULL
);
1602 if (!tb
[NL80211_ATTR_BSS
]) {
1603 fprintf(stderr
, "bss info missing!\n");
1606 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
1607 tb
[NL80211_ATTR_BSS
],
1609 fprintf(stderr
, "failed to parse nested attributes!\n");
1613 if (!bss
[NL80211_BSS_BSSID
])
1616 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
1617 printf("BSS %s", mac_addr
);
1618 if (tb
[NL80211_ATTR_IFINDEX
]) {
1619 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
1620 printf("(on %s)", dev
);
1623 if (bss
[NL80211_BSS_STATUS
]) {
1624 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
1625 case NL80211_BSS_STATUS_AUTHENTICATED
:
1626 printf(" -- authenticated");
1628 case NL80211_BSS_STATUS_ASSOCIATED
:
1629 printf(" -- associated");
1631 case NL80211_BSS_STATUS_IBSS_JOINED
:
1632 printf(" -- joined");
1635 printf(" -- unknown status: %d",
1636 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
1642 if (bss
[NL80211_BSS_TSF
]) {
1643 unsigned long long tsf
;
1644 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
1645 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
1646 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
1647 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
1649 if (bss
[NL80211_BSS_FREQUENCY
]) {
1650 int freq
= nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]);
1651 printf("\tfreq: %d\n", freq
);
1655 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
1656 printf("\tbeacon interval: %d TUs\n",
1657 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
1658 if (bss
[NL80211_BSS_CAPABILITY
]) {
1659 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
1660 printf("\tcapability:");
1662 print_capa_dmg(capa
);
1664 print_capa_non_dmg(capa
);
1665 printf(" (0x%.4x)\n", capa
);
1667 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
1668 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
1669 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
1671 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
1672 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
1673 printf("\tsignal: %d/100\n", s
);
1675 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
1676 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
1677 printf("\tlast seen: %d ms ago\n", age
);
1680 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
1681 if (bss
[NL80211_BSS_BEACON_IES
])
1682 printf("\tInformation elements from Probe Response "
1684 print_ies(nla_data(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
1685 nla_len(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
1686 params
->unknown
, params
->type
);
1688 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
1689 printf("\tInformation elements from Beacon frame:\n");
1690 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
1691 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
1692 params
->unknown
, params
->type
);
1698 static struct scan_params scan_params
;
1700 static int handle_scan_dump(struct nl80211_state
*state
,
1703 int argc
, char **argv
,
1709 memset(&scan_params
, 0, sizeof(scan_params
));
1711 if (argc
== 1 && !strcmp(argv
[0], "-u"))
1712 scan_params
.unknown
= true;
1713 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
1714 scan_params
.show_both_ie_sets
= true;
1716 scan_params
.type
= PRINT_SCAN
;
1718 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_bss_handler
,
1723 static int handle_scan_combined(struct nl80211_state
*state
,
1726 int argc
, char **argv
,
1730 static char *dump_argv
[] = {
1736 static const __u32 cmds
[] = {
1737 NL80211_CMD_NEW_SCAN_RESULTS
,
1738 NL80211_CMD_SCAN_ABORTED
,
1740 int trig_argc
, dump_argc
, err
;
1742 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
1744 dump_argv
[3] = "-u";
1745 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
1747 dump_argv
[3] = "-b";
1751 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
1752 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
1755 trig_argv
[0] = argv
[0];
1756 trig_argv
[1] = "scan";
1757 trig_argv
[2] = "trigger";
1759 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
1760 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
1761 err
= handle_cmd(state
, id
, trig_argc
, trig_argv
);
1767 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
1769 * This code has a bug, which requires creating a separate
1770 * nl80211 socket to fix:
1771 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
1772 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
1773 * before (!) we listen to it, because we only start listening
1774 * after we send our scan request.
1776 * Doing it the other way around has a race condition as well,
1777 * if you first open the events socket you may get a notification
1778 * for a previous scan.
1780 * The only proper way to fix this would be to listen to events
1781 * before sending the command, and for the kernel to send the
1782 * scan request along with the event, so that you can match up
1783 * whether the scan you requested was finished or aborted (this
1784 * may result in processing a scan that another application
1785 * requested, but that doesn't seem to be a problem).
1787 * Alas, the kernel doesn't do that (yet).
1790 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
1791 NL80211_CMD_SCAN_ABORTED
) {
1792 printf("scan aborted!\n");
1796 dump_argv
[0] = argv
[0];
1797 return handle_cmd(state
, id
, dump_argc
, dump_argv
);
1799 TOPLEVEL(scan
, "[-u] [freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]", 0, 0,
1800 CIB_NETDEV
, handle_scan_combined
,
1801 "Scan on the given frequencies and probe for the given SSIDs\n"
1802 "(or wildcard if not given) unless passive scanning is requested.\n"
1803 "If -u is specified print unknown data in the scan results.\n"
1804 "Specified (vendor) IEs must be well-formed.");
1805 COMMAND(scan
, dump
, "[-u]",
1806 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
1807 "Dump the current scan results. If -u is specified, print unknown\n"
1808 "data in scan results.");
1809 COMMAND(scan
, trigger
, "[freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]",
1810 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
1811 "Trigger a scan on the given frequencies with probing for the given\n"
1812 "SSIDs (or wildcard if not given) unless passive scanning is requested.");