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>
20 static int handle_scan(struct nl80211_state
*state
,
23 int argc
, char **argv
)
25 struct nl_msg
*ssids
= NULL
;
28 ssids
= nlmsg_alloc();
31 NLA_PUT(ssids
, 1, 0, "");
32 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
39 COMMAND(scan
, trigger
, NULL
,
40 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
);
42 typedef void (*printfn
)(unsigned char type
, unsigned char len
, unsigned char *data
);
44 static void print_ssid(unsigned char type
, unsigned char len
, unsigned char *data
)
48 for (i
=0; i
<len
; i
++) {
50 printf("%c", data
[i
]);
52 printf("\\x%.2x", data
[i
]);
57 static void print_supprates(unsigned char type
, unsigned char len
, unsigned char *data
)
62 printf("\tSupported rates: ");
64 printf("\tExtended supported rates: ");
66 for (i
=0; i
<len
; i
++) {
67 int r
= data
[i
] & 0x7f;
68 printf("%d.%d%s ", r
/2, 5*(r
&1), data
[i
] & 0x80 ? "*":"");
73 static void print_ds(unsigned char type
, unsigned char len
, unsigned char *data
)
75 printf("\tDS Parameter set: channel %d\n", data
[0]);
78 static void print_ign(unsigned char type
, unsigned char len
, unsigned char *data
)
80 /* ignore for now, not too useful */
83 static void print_erp(unsigned char type
, unsigned char len
, unsigned char *data
)
90 printf(" NonERP_Present");
92 printf(" Use_Protection");
94 printf(" Barker_Preamble_Mode");
98 static const printfn ieprinters
[] = {
100 [1] = print_supprates
,
104 [50] = print_supprates
,
107 static void tab_on_first(bool *first
)
115 static void print_wifi_wps(unsigned char type
, unsigned char len
, unsigned char *data
)
118 __u16 subtype
, sublen
;
123 subtype
= (data
[0] << 8) + data
[1];
124 sublen
= (data
[2] << 8) + data
[3];
130 tab_on_first(&first
);
131 printf("\t * Version: %#.2x\n", data
[4]);
134 tab_on_first(&first
);
135 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
138 tab_on_first(&first
);
139 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
142 tab_on_first(&first
);
143 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
146 __u16 val
= (data
[4] << 8) | data
[5];
147 tab_on_first(&first
);
148 printf("\t * AP setup locked: 0x%.4x\n", val
);
152 __u16 meth
= (data
[4] << 8) + data
[5];
154 tab_on_first(&first
);
155 printf("\t * Config methods:");
156 #define T(bit, name) do { \
157 if (meth & (1<<bit)) { \
185 printf("\t\t * bogus tail data (%d):", len
);
187 printf(" %.2x", *data
);
195 static const printfn wifiprinters
[] = {
196 [4] = print_wifi_wps
,
199 static void print_vendor(unsigned char len
, unsigned char *data
,
200 struct scan_params
*params
)
205 printf("\tVendor specific: <too short> data:");
206 for(i
= 0; i
< len
; i
++)
207 printf(" %.02x", data
[i
]);
212 if (len
>= 4 && data
[0] == 0x00 && data
[1] == 0x50 && data
[2] == 0xF2) {
213 if (data
[3] < ARRAY_SIZE(wifiprinters
) && wifiprinters
[data
[3]])
214 return wifiprinters
[data
[3]](data
[3], len
- 4, data
+ 4);
215 if (!params
->unknown
)
217 printf("\tWiFi OUI %#.2x data:", data
[3]);
218 for(i
= 0; i
< len
- 4; i
++)
219 printf(" %.02x", data
[i
+ 4]);
224 if (!params
->unknown
)
227 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
228 data
[0], data
[1], data
[2]);
229 for (i
= 3; i
< len
; i
++)
230 printf(" %.2x", data
[i
]);
234 static void print_ies(unsigned char *ie
, int ielen
, struct scan_params
*params
)
236 while (ielen
>= 2 && ielen
>= ie
[1]) {
237 if (ie
[0] < ARRAY_SIZE(ieprinters
) && ieprinters
[ie
[0]]) {
238 ieprinters
[ie
[0]](ie
[0], ie
[1], ie
+ 2);
239 } else if (ie
[0] == 221 /* vendor */) {
240 print_vendor(ie
[1], ie
+ 2, params
);
241 } else if (params
->unknown
) {
244 printf("\tUnknown IE (%d):", ie
[0]);
245 for (i
=0; i
<ie
[1]; i
++)
246 printf(" %.2x", ie
[2+i
]);
254 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
256 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
257 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
258 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
259 char mac_addr
[20], dev
[20];
260 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
261 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
262 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
263 [NL80211_BSS_BSSID
] = { },
264 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
265 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
266 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
267 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
268 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
271 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
272 genlmsg_attrlen(gnlh
, 0), NULL
);
274 if (!tb
[NL80211_ATTR_BSS
]) {
275 fprintf(stderr
, "bss info missing!");
278 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
279 tb
[NL80211_ATTR_BSS
],
281 fprintf(stderr
, "failed to parse nested attributes!");
285 if (!bss
[NL80211_BSS_BSSID
])
288 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
289 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
290 printf("BSS %s (on %s)\n", mac_addr
, dev
);
292 if (bss
[NL80211_BSS_TSF
]) {
293 unsigned long long tsf
;
294 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
295 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
296 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
297 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
299 if (bss
[NL80211_BSS_FREQUENCY
])
300 printf("\tfreq: %d\n",
301 nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]));
302 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
303 printf("\tbeacon interval: %d\n",
304 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
305 if (bss
[NL80211_BSS_CAPABILITY
])
306 printf("\tcapability: 0x%.4x\n",
307 nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]));
308 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
309 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
310 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
312 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
313 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
314 printf("\tsignal: %d/100\n", s
);
316 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
])
317 print_ies(nla_data(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
318 nla_len(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
324 static struct scan_params scan_params
;
326 static int handle_scan_dump(struct nl80211_state
*state
,
329 int argc
, char **argv
)
334 scan_params
.unknown
= false;
335 if (argc
== 1 && !strcmp(argv
[0], "-u"))
336 scan_params
.unknown
= true;
338 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_bss_handler
,
342 COMMAND(scan
, dump
, "[-u]",
343 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
);
345 static int handle_scan_combined(struct nl80211_state
*state
,
348 int argc
, char **argv
)
350 static char *trig_argv
[] = {
355 static char *dump_argv
[] = {
361 static const __u32 cmds
[] = {
362 NL80211_CMD_NEW_SCAN_RESULTS
,
363 NL80211_CMD_SCAN_ABORTED
,
367 trig_argv
[0] = argv
[0];
368 err
= handle_cmd(state
, II_NETDEV
, ARRAY_SIZE(trig_argv
), trig_argv
);
373 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
375 * This code has a bug, which requires creating a separate
376 * nl80211 socket to fix:
377 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
378 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
379 * before (!) we listen to it, because we only start listening
380 * after we send our scan request.
382 * Doing it the other way around has a race condition as well,
383 * if you first open the events socket you may get a notification
384 * for a previous scan.
386 * The only proper way to fix this would be to listen to events
387 * before sending the command, and for the kernel to send the
388 * scan request along with the event, so that you can match up
389 * whether the scan you requested was finished or aborted (this
390 * may result in processing a scan that another application
391 * requested, but that doesn't seem to be a problem).
393 * Alas, the kernel doesn't do that (yet).
396 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
397 NL80211_CMD_SCAN_ABORTED
) {
398 printf("scan aborted!\n");
402 if (argc
== 3 && !strcmp(argv
[2], "-u")) {
408 dump_argv
[0] = argv
[0];
409 return handle_cmd(state
, II_NETDEV
, dump_argc
, dump_argv
);
411 TOPLEVEL(scan
, "[-u]", 0, 0, CIB_NETDEV
, handle_scan_combined
);