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_DSSS_OFDM (1<<13)
30 static unsigned char ms_oui
[3] = { 0x00, 0x50, 0xf2 };
31 static unsigned char ieee80211_oui
[3] = { 0x00, 0x0f, 0xac };
32 static unsigned char wfa_oui
[3] = { 0x50, 0x6f, 0x9a };
36 enum print_ie_type type
;
37 bool show_both_ie_sets
;
40 #define IEEE80211_COUNTRY_EXTENSION_ID 201
42 union ieee80211_country_ie_triplet
{
47 } __attribute__ ((packed
)) chans
;
49 __u8 reg_extension_id
;
52 } __attribute__ ((packed
)) ext
;
53 } __attribute__ ((packed
));
55 static int handle_scan(struct nl80211_state
*state
,
58 int argc
, char **argv
,
61 struct nl_msg
*ssids
= NULL
, *freqs
= NULL
;
73 bool passive
= false, have_ssids
= false, have_freqs
= false;
78 ssids
= nlmsg_alloc();
82 freqs
= nlmsg_alloc();
88 for (i
= 0; i
< argc
; i
++) {
91 if (strcmp(argv
[i
], "freq") == 0) {
95 } else if (strcmp(argv
[i
], "ies") == 0) {
98 } else if (strcmp(argv
[i
], "lowpri") == 0) {
100 flags
|= NL80211_SCAN_FLAG_LOW_PRIORITY
;
102 } else if (strcmp(argv
[i
], "flush") == 0) {
104 flags
|= NL80211_SCAN_FLAG_FLUSH
;
106 } else if (strcmp(argv
[i
], "ap-force") == 0) {
108 flags
|= NL80211_SCAN_FLAG_AP
;
110 } else if (strcmp(argv
[i
], "ssid") == 0) {
114 } else if (strcmp(argv
[i
], "passive") == 0) {
122 freq
= strtoul(argv
[i
], &eptr
, 10);
123 if (eptr
!= argv
[i
] + strlen(argv
[i
])) {
124 /* failed to parse as number -- maybe a tag? */
129 NLA_PUT_U32(freqs
, i
, freq
);
132 ies
= parse_hex(argv
[i
], &tmp
);
134 goto nla_put_failure
;
135 NLA_PUT(msg
, NL80211_ATTR_IE
, tmp
, ies
);
140 NLA_PUT(ssids
, i
, strlen(argv
[i
]), argv
[i
]);
146 NLA_PUT(ssids
, 1, 0, "");
148 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
151 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
153 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
162 static void tab_on_first(bool *first
)
170 static void print_ssid(const uint8_t type
, uint8_t len
, const uint8_t *data
)
173 print_ssid_escaped(len
, data
);
177 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
178 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
180 static void print_supprates(const uint8_t type
, uint8_t len
, const uint8_t *data
)
186 for (i
= 0; i
< len
; i
++) {
187 int r
= data
[i
] & 0x7f;
189 if (r
== BSS_MEMBERSHIP_SELECTOR_VHT_PHY
&& data
[i
] & 0x80)
191 else if (r
== BSS_MEMBERSHIP_SELECTOR_HT_PHY
&& data
[i
] & 0x80)
194 printf("%d.%d", r
/2, 5*(r
&1));
196 printf("%s ", data
[i
] & 0x80 ? "*" : "");
201 static void print_ds(const uint8_t type
, uint8_t len
, const uint8_t *data
)
203 printf(" channel %d\n", data
[0]);
206 static const char *country_env_str(char environment
)
208 switch (environment
) {
210 return "Indoor only";
212 return "Outdoor only";
214 return "Indoor/Outdoor";
220 static void print_country(const uint8_t type
, uint8_t len
, const uint8_t *data
)
222 printf(" %.*s", 2, data
);
224 printf("\tEnvironment: %s\n", country_env_str(data
[2]));
230 printf("\t\tNo country IE triplets present\n");
236 union ieee80211_country_ie_triplet
*triplet
= (void *) data
;
238 if (triplet
->ext
.reg_extension_id
>= IEEE80211_COUNTRY_EXTENSION_ID
) {
239 printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
240 triplet
->ext
.reg_extension_id
,
241 triplet
->ext
.reg_class
,
242 triplet
->ext
.coverage_class
,
243 triplet
->ext
.coverage_class
* 450);
251 if (triplet
->chans
.first_channel
<= 14)
252 end_channel
= triplet
->chans
.first_channel
+ (triplet
->chans
.num_channels
- 1);
254 end_channel
= triplet
->chans
.first_channel
+ (4 * (triplet
->chans
.num_channels
- 1));
256 printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet
->chans
.first_channel
, end_channel
, triplet
->chans
.max_power
);
265 static void print_powerconstraint(const uint8_t type
, uint8_t len
, const uint8_t *data
)
267 printf(" %d dB\n", data
[0]);
270 static void print_erp(const uint8_t type
, uint8_t len
, const uint8_t *data
)
273 printf(" <no flags>");
275 printf(" NonERP_Present");
277 printf(" Use_Protection");
279 printf(" Barker_Preamble_Mode");
283 static void print_cipher(const uint8_t *data
)
285 if (memcmp(data
, ms_oui
, 3) == 0) {
288 printf("Use group cipher suite");
303 printf("%.02x-%.02x-%.02x:%d",
304 data
[0], data
[1] ,data
[2], data
[3]);
307 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
310 printf("Use group cipher suite");
325 printf("AES-128-CMAC");
331 printf("%.02x-%.02x-%.02x:%d",
332 data
[0], data
[1] ,data
[2], data
[3]);
336 printf("%.02x-%.02x-%.02x:%d",
337 data
[0], data
[1] ,data
[2], data
[3]);
340 static void print_auth(const uint8_t *data
)
342 if (memcmp(data
, ms_oui
, 3) == 0) {
345 printf("IEEE 802.1X");
351 printf("%.02x-%.02x-%.02x:%d",
352 data
[0], data
[1] ,data
[2], data
[3]);
355 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
358 printf("IEEE 802.1X");
364 printf("FT/IEEE 802.1X");
370 printf("IEEE 802.1X/SHA-256");
373 printf("PSK/SHA-256");
376 printf("%.02x-%.02x-%.02x:%d",
377 data
[0], data
[1] ,data
[2], data
[3]);
381 printf("%.02x-%.02x-%.02x:%d",
382 data
[0], data
[1] ,data
[2], data
[3]);
385 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
386 uint8_t len
, const uint8_t *data
)
389 __u16 version
, count
, capa
;
392 version
= data
[0] + (data
[1] << 8);
393 tab_on_first(&first
);
394 printf("\t * Version: %d\n", version
);
400 tab_on_first(&first
);
401 printf("\t * Group cipher: %s\n", defcipher
);
402 printf("\t * Pairwise ciphers: %s\n", defcipher
);
406 tab_on_first(&first
);
407 printf("\t * Group cipher: ");
415 tab_on_first(&first
);
416 printf("\t * Pairwise ciphers: %s\n", defcipher
);
420 count
= data
[0] | (data
[1] << 8);
421 if (2 + (count
* 4) > len
)
424 tab_on_first(&first
);
425 printf("\t * Pairwise ciphers:");
426 for (i
= 0; i
< count
; i
++) {
428 print_cipher(data
+ 2 + (i
* 4));
432 data
+= 2 + (count
* 4);
433 len
-= 2 + (count
* 4);
436 tab_on_first(&first
);
437 printf("\t * Authentication suites: %s\n", defauth
);
441 count
= data
[0] | (data
[1] << 8);
442 if (2 + (count
* 4) > len
)
445 tab_on_first(&first
);
446 printf("\t * Authentication suites:");
447 for (i
= 0; i
< count
; i
++) {
449 print_auth(data
+ 2 + (i
* 4));
453 data
+= 2 + (count
* 4);
454 len
-= 2 + (count
* 4);
457 capa
= data
[0] | (data
[1] << 8);
458 tab_on_first(&first
);
459 printf("\t * Capabilities:");
463 printf(" NoPairwise");
464 switch ((capa
& 0x000c) >> 2) {
468 printf(" 2-PTKSA-RC");
471 printf(" 4-PTKSA-RC");
474 printf(" 16-PTKSA-RC");
477 switch ((capa
& 0x0030) >> 4) {
481 printf(" 2-GTKSA-RC");
484 printf(" 4-GTKSA-RC");
487 printf(" 16-GTKSA-RC");
491 printf(" MFP-required");
493 printf(" MFP-capable");
495 printf(" Peerkey-enabled");
497 printf(" SPP-AMSDU-capable");
499 printf(" SPP-AMSDU-required");
500 printf(" (0x%.4x)\n", capa
);
506 int pmkid_count
= data
[0] | (data
[1] << 8);
508 if (len
>= 2 + 16 * pmkid_count
) {
509 tab_on_first(&first
);
510 printf("\t * %d PMKIDs\n", pmkid_count
);
511 /* not printing PMKID values */
512 data
+= 2 + 16 * pmkid_count
;
513 len
-= 2 + 16 * pmkid_count
;
519 tab_on_first(&first
);
520 printf("\t * Group mgmt cipher suite: ");
529 printf("\t\t * bogus tail data (%d):", len
);
531 printf(" %.2x", *data
);
539 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
)
541 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
544 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
547 print_ht_capability(data
[0] | (data
[1] << 8));
548 print_ampdu_length(data
[2] & 3);
549 print_ampdu_spacing((data
[2] >> 2) & 7);
550 print_ht_mcs(data
+ 3);
553 static const char *ht_secondary_offset
[4] = {
560 static void print_ht_op(const uint8_t type
, uint8_t len
, const uint8_t *data
)
562 static const char *protection
[4] = {
568 static const char *sta_chan_width
[2] = {
574 printf("\t\t * primary channel: %d\n", data
[0]);
575 printf("\t\t * secondary channel offset: %s\n",
576 ht_secondary_offset
[data
[1] & 0x3]);
577 printf("\t\t * STA channel width: %s\n", sta_chan_width
[(data
[1] & 0x4)>>2]);
578 printf("\t\t * RIFS: %d\n", (data
[1] & 0x8)>>3);
579 printf("\t\t * HT protection: %s\n", protection
[data
[2] & 0x3]);
580 printf("\t\t * non-GF present: %d\n", (data
[2] & 0x4) >> 2);
581 printf("\t\t * OBSS non-GF present: %d\n", (data
[2] & 0x10) >> 4);
582 printf("\t\t * dual beacon: %d\n", (data
[4] & 0x40) >> 6);
583 printf("\t\t * dual CTS protection: %d\n", (data
[4] & 0x80) >> 7);
584 printf("\t\t * STBC beacon: %d\n", data
[5] & 0x1);
585 printf("\t\t * L-SIG TXOP Prot: %d\n", (data
[5] & 0x2) >> 1);
586 printf("\t\t * PCO active: %d\n", (data
[5] & 0x4) >> 2);
587 printf("\t\t * PCO phase: %d\n", (data
[5] & 0x8) >> 3);
590 static void print_capabilities(const uint8_t type
, uint8_t len
, const uint8_t *data
)
596 for (i
= 0; i
< len
; i
++) {
599 for (bit
= 0; bit
< 8; bit
++) {
600 if (!(data
[i
] & (1 << bit
)))
608 #define CAPA(bit, name) case bit: printf(" " name); break
610 switch (bit
+ base
) {
611 CAPA(0, "HT Information Exchange Supported");
612 CAPA(1, "reserved (On-demand Beacon)");
613 CAPA(2, "Extended Channel Switching");
614 CAPA(3, "reserved (Wave Indication)");
615 CAPA(4, "PSMP Capability");
616 CAPA(5, "reserved (Service Interval Granularity)");
617 CAPA(6, "S-PSMP Capability");
619 CAPA(8, "Diagnostics");
620 CAPA(9, "Multicast Diagnostics");
621 CAPA(10, "Location Tracking");
623 CAPA(12, "Proxy ARP Service");
624 CAPA(13, "Collocated Interference Reporting");
625 CAPA(14, "Civic Location");
626 CAPA(15, "Geospatial Location");
628 CAPA(17, "WNM-Sleep Mode");
629 CAPA(18, "TIM Broadcast");
630 CAPA(19, "BSS Transition");
631 CAPA(20, "QoS Traffic Capability");
632 CAPA(21, "AC Station Count");
633 CAPA(22, "Multiple BSSID");
634 CAPA(23, "Timing Measurement");
635 CAPA(24, "Channel Usage");
636 CAPA(25, "SSID List");
638 CAPA(27, "UTC TSF Offset");
639 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
640 CAPA(29, "TDLS Peer PSM Support");
641 CAPA(30, "TDLS channel switching");
642 CAPA(31, "Interworking");
645 CAPA(34, "SSPN Interface");
646 CAPA(35, "Reserved");
647 CAPA(36, "MSGCF Capability");
648 CAPA(37, "TDLS Support");
649 CAPA(38, "TDLS Prohibited");
650 CAPA(39, "TDLS Channel Switching Prohibited");
651 CAPA(40, "Reject Unadmitted Frame");
652 CAPA(44, "Identifier Location");
653 CAPA(45, "U-APSD Coexistence");
654 CAPA(46, "WNM-Notification");
655 CAPA(47, "Reserved");
656 CAPA(48, "UTF-8 SSID");
668 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
)
670 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
672 data
[0], data
[1], data
[2], data
[3]);
674 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
678 static void print_vht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
681 print_vht_info(data
[0] | (data
[1] << 8) |
682 (data
[2] << 16) | (data
[3] << 24),
686 static void print_vht_oper(const uint8_t type
, uint8_t len
, const uint8_t *data
)
688 const char *chandwidths
[] = {
689 [0] = "20 or 40 MHz",
696 printf("\t\t * channel width: %d (%s)\n", data
[0],
697 data
[0] < ARRAY_SIZE(chandwidths
) ? chandwidths
[data
[0]] : "unknown");
698 printf("\t\t * center freq segment 1: %d\n", data
[1]);
699 printf("\t\t * center freq segment 2: %d\n", data
[2]);
700 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data
[4], data
[3]);
703 static void print_obss_scan_params(const uint8_t type
, uint8_t len
, const uint8_t *data
)
706 printf("\t\t * passive dwell: %d TUs\n", (data
[1] << 8) | data
[0]);
707 printf("\t\t * active dwell: %d TUs\n", (data
[3] << 8) | data
[2]);
708 printf("\t\t * channel width trigger scan interval: %d s\n", (data
[5] << 8) | data
[4]);
709 printf("\t\t * scan passive total per channel: %d TUs\n", (data
[7] << 8) | data
[6]);
710 printf("\t\t * scan active total per channel: %d TUs\n", (data
[9] << 8) | data
[8]);
711 printf("\t\t * BSS width channel transition delay factor: %d\n", (data
[11] << 8) | data
[10]);
712 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
713 ((data
[13] << 8) | data
[12]) / 100, ((data
[13] << 8) | data
[12]) % 100);
716 static void print_secchan_offs(const uint8_t type
, uint8_t len
, const uint8_t *data
)
718 if (data
[0] < ARRAY_SIZE(ht_secondary_offset
))
719 printf(" %s (%d)\n", ht_secondary_offset
[data
[0]], data
[0]);
721 printf(" %d\n", data
[0]);
724 static void print_bss_load(const uint8_t type
, uint8_t len
, const uint8_t *data
)
727 printf("\t\t * station count: %d\n", (data
[1] << 8) | data
[0]);
728 printf("\t\t * channel utilisation: %d/255\n", data
[2]);
729 printf("\t\t * available admission capacity: %d [*32us]\n", (data
[4] << 8) | data
[3]);
734 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
);
735 uint8_t minlen
, maxlen
;
739 static void print_ie(const struct ie_print
*p
, const uint8_t type
,
740 uint8_t len
, const uint8_t *data
)
747 printf("\t%s:", p
->name
);
748 if (len
< p
->minlen
|| len
> p
->maxlen
) {
750 printf(" <invalid: %d bytes:", len
);
751 for (i
= 0; i
< len
; i
++)
752 printf(" %.02x", data
[i
]);
755 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
757 printf(" <invalid: no data>\n");
761 p
->print(type
, len
, data
);
764 #define PRINT_IGN { \
771 static const struct ie_print ieprinters
[] = {
772 [0] = { "SSID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
773 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
774 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
775 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
776 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
777 [11] = { "BSS Load", print_bss_load
, 5, 5, BIT(PRINT_SCAN
), },
778 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
779 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
780 [45] = { "HT capabilities", print_ht_capa
, 26, 26, BIT(PRINT_SCAN
), },
781 [74] = { "Overlapping BSS scan params", print_obss_scan_params
, 14, 255, BIT(PRINT_SCAN
), },
782 [61] = { "HT operation", print_ht_op
, 22, 22, BIT(PRINT_SCAN
), },
783 [62] = { "Secondary Channel Offset", print_secchan_offs
, 1, 1, BIT(PRINT_SCAN
), },
784 [191] = { "VHT capabilities", print_vht_capa
, 12, 255, BIT(PRINT_SCAN
), },
785 [192] = { "VHT operation", print_vht_oper
, 5, 255, BIT(PRINT_SCAN
), },
786 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
787 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
788 [114] = { "MESH ID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
789 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
792 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
794 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
797 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
800 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
806 printf("Parameter: not version 1: ");
810 printf("\t * Parameter version 1");
815 printf("\n\t\t * u-APSD");
819 for (i
= 0; i
< 4; i
++) {
820 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
823 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
824 (1 << (data
[1] >> 4)) - 1);
825 printf(", AIFSN %d", data
[0] & 0xf);
826 if (data
[2] | data
[3])
827 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
839 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
)
845 printf(" information:");
848 if (print_wifi_wmm_param(data
+ 1, len
- 1))
852 printf(" type %d:", data
[0]);
856 for(i
= 1; i
< len
; i
++)
857 printf(" %.02x", data
[i
]);
861 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
865 return "Default (PIN)";
867 return "User-specified";
869 return "Machine-specified";
875 return "Registrar-specified";
881 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
)
884 __u16 subtype
, sublen
;
887 subtype
= (data
[0] << 8) + data
[1];
888 sublen
= (data
[2] << 8) + data
[3];
894 tab_on_first(&first
);
895 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
898 tab_on_first(&first
);
899 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
903 tab_on_first(&first
);
905 printf("\t * Device Password ID: (invalid "
906 "length %d)\n", sublen
);
909 id
= data
[4] << 8 | data
[5];
910 printf("\t * Device Password ID: %u (%s)\n",
911 id
, wifi_wps_dev_passwd_id(id
));
915 tab_on_first(&first
);
916 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
919 tab_on_first(&first
);
920 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
923 tab_on_first(&first
);
924 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
928 tab_on_first(&first
);
929 printf("\t * Response Type: %d%s\n",
930 val
, val
== 3 ? " (AP)" : "");
935 tab_on_first(&first
);
936 printf("\t * RF Bands: 0x%x\n", val
);
941 tab_on_first(&first
);
942 printf("\t * Selected Registrar: 0x%x\n", val
);
946 tab_on_first(&first
);
947 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
951 tab_on_first(&first
);
952 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
954 val
== 1 ? " (Unconfigured)" : "",
955 val
== 2 ? " (Configured)" : "");
959 tab_on_first(&first
);
960 printf("\t * UUID: ");
962 printf("(invalid, length=%d)\n", sublen
);
965 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
966 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
967 data
[4], data
[5], data
[6], data
[7],
968 data
[8], data
[9], data
[10], data
[11],
969 data
[12], data
[13], data
[14], data
[15],
970 data
[16], data
[17], data
[18], data
[19]);
973 tab_on_first(&first
);
975 printf("\t * Primary Device Type: (invalid "
976 "length %d)\n", sublen
);
979 printf("\t * Primary Device Type: "
980 "%u-%02x%02x%02x%02x-%u\n",
981 data
[4] << 8 | data
[5],
982 data
[6], data
[7], data
[8], data
[9],
983 data
[10] << 8 | data
[11]);
988 tab_on_first(&first
);
989 printf("\t * AP setup locked: 0x%.2x\n", val
);
994 __u16 meth
= (data
[4] << 8) + data
[5];
996 tab_on_first(&first
);
997 printf("\t * %sConfig methods:",
998 subtype
== 0x1053 ? "Selected Registrar ": "");
999 #define T(bit, name) do { \
1000 if (meth & (1<<bit)) { \
1020 const __u8
*subdata
= data
+ 4;
1021 __u16 tmplen
= sublen
;
1023 tab_on_first(&first
);
1024 printf("\t * Unknown TLV (%#.4x, %d bytes):",
1027 printf(" %.2x", *subdata
);
1041 printf("\t\t * bogus tail data (%d):", len
);
1043 printf(" %.2x", *data
);
1051 static const struct ie_print wifiprinters
[] = {
1052 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
1053 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
1054 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
1057 static inline void print_p2p(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1065 sublen
= (data
[2] << 8) + data
[1];
1067 if (sublen
> len
- 3)
1071 case 0x02: /* capability */
1072 tab_on_first(&first
);
1074 printf("\t * malformed capability\n");
1077 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
1080 case 0x0d: /* device info */
1081 if (sublen
< 6 + 2 + 8 + 1) {
1082 printf("\t * malformed device info\n");
1085 /* fall through for now */
1086 case 0x00: /* status */
1087 case 0x01: /* minor reason */
1088 case 0x03: /* device ID */
1089 case 0x04: /* GO intent */
1090 case 0x05: /* configuration timeout */
1091 case 0x06: /* listen channel */
1092 case 0x07: /* group BSSID */
1093 case 0x08: /* ext listen timing */
1094 case 0x09: /* intended interface address */
1095 case 0x0a: /* manageability */
1096 case 0x0b: /* channel list */
1097 case 0x0c: /* NoA */
1098 case 0x0e: /* group info */
1099 case 0x0f: /* group ID */
1100 case 0x10: /* interface */
1101 case 0x11: /* operating channel */
1102 case 0x12: /* invitation flags */
1103 case 0xdd: /* vendor specific */
1105 const __u8
*subdata
= data
+ 4;
1106 __u16 tmplen
= sublen
;
1108 tab_on_first(&first
);
1109 printf("\t * Unknown TLV (%#.2x, %d bytes):",
1112 printf(" %.2x", *subdata
);
1126 tab_on_first(&first
);
1127 printf("\t * bogus tail data (%d):", len
);
1129 printf(" %.2x", *data
);
1137 static const struct ie_print wfa_printers
[] = {
1138 [9] = { "P2P", print_p2p
, 2, 255, BIT(PRINT_SCAN
), },
1141 static void print_vendor(unsigned char len
, unsigned char *data
,
1142 bool unknown
, enum print_ie_type ptype
)
1147 printf("\tVendor specific: <too short> data:");
1148 for(i
= 0; i
< len
; i
++)
1149 printf(" %.02x", data
[i
]);
1154 if (len
>= 4 && memcmp(data
, ms_oui
, 3) == 0) {
1155 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
1156 wifiprinters
[data
[3]].name
&&
1157 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
1158 print_ie(&wifiprinters
[data
[3]], data
[3], len
- 4, data
+ 4);
1163 printf("\tMS/WiFi %#.2x, data:", data
[3]);
1164 for(i
= 0; i
< len
- 4; i
++)
1165 printf(" %.02x", data
[i
+ 4]);
1170 if (len
>= 4 && memcmp(data
, wfa_oui
, 3) == 0) {
1171 if (data
[3] < ARRAY_SIZE(wfa_printers
) &&
1172 wfa_printers
[data
[3]].name
&&
1173 wfa_printers
[data
[3]].flags
& BIT(ptype
)) {
1174 print_ie(&wfa_printers
[data
[3]], data
[3], len
- 4, data
+ 4);
1179 printf("\tWFA %#.2x, data:", data
[3]);
1180 for(i
= 0; i
< len
- 4; i
++)
1181 printf(" %.02x", data
[i
+ 4]);
1189 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
1190 data
[0], data
[1], data
[2]);
1191 for (i
= 3; i
< len
; i
++)
1192 printf(" %.2x", data
[i
]);
1196 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
1197 enum print_ie_type ptype
)
1199 while (ielen
>= 2 && ielen
>= ie
[1]) {
1200 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
1201 ieprinters
[ie
[0]].name
&&
1202 ieprinters
[ie
[0]].flags
& BIT(ptype
)) {
1203 print_ie(&ieprinters
[ie
[0]], ie
[0], ie
[1], ie
+ 2);
1204 } else if (ie
[0] == 221 /* vendor */) {
1205 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
1206 } else if (unknown
) {
1209 printf("\tUnknown IE (%d):", ie
[0]);
1210 for (i
=0; i
<ie
[1]; i
++)
1211 printf(" %.2x", ie
[2+i
]);
1219 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
1221 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
1222 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
1223 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
1224 char mac_addr
[20], dev
[20];
1225 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
1226 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
1227 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
1228 [NL80211_BSS_BSSID
] = { },
1229 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
1230 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
1231 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
1232 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
1233 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
1234 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
1235 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
1236 [NL80211_BSS_BEACON_IES
] = { },
1238 struct scan_params
*params
= arg
;
1239 int show
= params
->show_both_ie_sets
? 2 : 1;
1241 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
1242 genlmsg_attrlen(gnlh
, 0), NULL
);
1244 if (!tb
[NL80211_ATTR_BSS
]) {
1245 fprintf(stderr
, "bss info missing!\n");
1248 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
1249 tb
[NL80211_ATTR_BSS
],
1251 fprintf(stderr
, "failed to parse nested attributes!\n");
1255 if (!bss
[NL80211_BSS_BSSID
])
1258 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
1259 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
1260 printf("BSS %s (on %s)", mac_addr
, dev
);
1262 if (bss
[NL80211_BSS_STATUS
]) {
1263 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
1264 case NL80211_BSS_STATUS_AUTHENTICATED
:
1265 printf(" -- authenticated");
1267 case NL80211_BSS_STATUS_ASSOCIATED
:
1268 printf(" -- associated");
1270 case NL80211_BSS_STATUS_IBSS_JOINED
:
1271 printf(" -- joined");
1274 printf(" -- unknown status: %d",
1275 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
1281 if (bss
[NL80211_BSS_TSF
]) {
1282 unsigned long long tsf
;
1283 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
1284 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
1285 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
1286 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
1288 if (bss
[NL80211_BSS_FREQUENCY
])
1289 printf("\tfreq: %d\n",
1290 nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]));
1291 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
1292 printf("\tbeacon interval: %d\n",
1293 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
1294 if (bss
[NL80211_BSS_CAPABILITY
]) {
1295 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
1296 printf("\tcapability:");
1297 if (capa
& WLAN_CAPABILITY_ESS
)
1299 if (capa
& WLAN_CAPABILITY_IBSS
)
1301 if (capa
& WLAN_CAPABILITY_PRIVACY
)
1303 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
1304 printf(" ShortPreamble");
1305 if (capa
& WLAN_CAPABILITY_PBCC
)
1307 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
1308 printf(" ChannelAgility");
1309 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
1310 printf(" SpectrumMgmt");
1311 if (capa
& WLAN_CAPABILITY_QOS
)
1313 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
1314 printf(" ShortSlotTime");
1315 if (capa
& WLAN_CAPABILITY_APSD
)
1317 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
1318 printf(" DSSS-OFDM");
1319 printf(" (0x%.4x)\n", capa
);
1321 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
1322 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
1323 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
1325 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
1326 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
1327 printf("\tsignal: %d/100\n", s
);
1329 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
1330 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
1331 printf("\tlast seen: %d ms ago\n", age
);
1334 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
1335 if (bss
[NL80211_BSS_BEACON_IES
])
1336 printf("\tInformation elements from Probe Response "
1338 print_ies(nla_data(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
1339 nla_len(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
1340 params
->unknown
, params
->type
);
1342 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
1343 printf("\tInformation elements from Beacon frame:\n");
1344 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
1345 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
1346 params
->unknown
, params
->type
);
1352 static struct scan_params scan_params
;
1354 static int handle_scan_dump(struct nl80211_state
*state
,
1357 int argc
, char **argv
,
1363 memset(&scan_params
, 0, sizeof(scan_params
));
1365 if (argc
== 1 && !strcmp(argv
[0], "-u"))
1366 scan_params
.unknown
= true;
1367 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
1368 scan_params
.show_both_ie_sets
= true;
1370 scan_params
.type
= PRINT_SCAN
;
1372 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_bss_handler
,
1377 static int handle_scan_combined(struct nl80211_state
*state
,
1380 int argc
, char **argv
,
1384 static char *dump_argv
[] = {
1390 static const __u32 cmds
[] = {
1391 NL80211_CMD_NEW_SCAN_RESULTS
,
1392 NL80211_CMD_SCAN_ABORTED
,
1394 int trig_argc
, dump_argc
, err
;
1396 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
1398 dump_argv
[3] = "-u";
1399 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
1401 dump_argv
[3] = "-b";
1405 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
1406 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
1409 trig_argv
[0] = argv
[0];
1410 trig_argv
[1] = "scan";
1411 trig_argv
[2] = "trigger";
1413 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
1414 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
1415 err
= handle_cmd(state
, id
, trig_argc
, trig_argv
);
1421 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
1423 * This code has a bug, which requires creating a separate
1424 * nl80211 socket to fix:
1425 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
1426 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
1427 * before (!) we listen to it, because we only start listening
1428 * after we send our scan request.
1430 * Doing it the other way around has a race condition as well,
1431 * if you first open the events socket you may get a notification
1432 * for a previous scan.
1434 * The only proper way to fix this would be to listen to events
1435 * before sending the command, and for the kernel to send the
1436 * scan request along with the event, so that you can match up
1437 * whether the scan you requested was finished or aborted (this
1438 * may result in processing a scan that another application
1439 * requested, but that doesn't seem to be a problem).
1441 * Alas, the kernel doesn't do that (yet).
1444 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
1445 NL80211_CMD_SCAN_ABORTED
) {
1446 printf("scan aborted!\n");
1450 dump_argv
[0] = argv
[0];
1451 return handle_cmd(state
, id
, dump_argc
, dump_argv
);
1453 TOPLEVEL(scan
, "[-u] [freq <freq>*] [ies <hex as 00:11:..>] [lowpri,flush,ap-force] [ssid <ssid>*|passive]", 0, 0,
1454 CIB_NETDEV
, handle_scan_combined
,
1455 "Scan on the given frequencies and probe for the given SSIDs\n"
1456 "(or wildcard if not given) unless passive scanning is requested.\n"
1457 "If -u is specified print unknown data in the scan results.\n"
1458 "Specified (vendor) IEs must be well-formed.");
1459 COMMAND(scan
, dump
, "[-u]",
1460 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
1461 "Dump the current scan results. If -u is specified, print unknown\n"
1462 "data in scan results.");
1463 COMMAND(scan
, trigger
, "[freq <freq>*] [ies <hex as 00:11:..>] [lowpri,flush,ap-force] [ssid <ssid>*|passive]",
1464 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
1465 "Trigger a scan on the given frequencies with probing for the given\n"
1466 "SSIDs (or wildcard if not given) unless passive scanning is requested.");