]> git.ipfire.org Git - thirdparty/iw.git/blame - scan.c
validate IE length better in places
[thirdparty/iw.git] / scan.c
CommitLineData
3563f4c5
JB
1#include <net/if.h>
2#include <errno.h>
3#include <string.h>
4#include <ctype.h>
764fe753 5#include <stdbool.h>
3563f4c5
JB
6
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>
12
13#include "nl80211.h"
14#include "iw.h"
15
92a04ecd
MH
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)
29
857d966e
MH
30static unsigned char wifi_oui[3] = { 0x00, 0x50, 0xf2 };
31static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
32
764fe753
JB
33struct scan_params {
34 bool unknown;
35};
36
7c37a24d
JB
37static int handle_scan(struct nl80211_state *state,
38 struct nl_cb *cb,
3563f4c5
JB
39 struct nl_msg *msg,
40 int argc, char **argv)
41{
42 struct nl_msg *ssids = NULL;
43 int err = -ENOBUFS;
44
45 ssids = nlmsg_alloc();
46 if (!ssids)
47 return -ENOMEM;
48 NLA_PUT(ssids, 1, 0, "");
49 nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
50
51 err = 0;
52 nla_put_failure:
53 nlmsg_free(ssids);
54 return err;
55}
56COMMAND(scan, trigger, NULL,
57 NL80211_CMD_TRIGGER_SCAN, 0, CIB_NETDEV, handle_scan);
58
857d966e
MH
59static void tab_on_first(bool *first)
60{
61 if (!*first)
62 printf("\t");
63 else
64 *first = false;
65}
66
83b4934c 67static void print_ssid(const uint8_t type, uint8_t len, const uint8_t *data)
3563f4c5
JB
68{
69 int i;
83b4934c
JB
70
71 printf(" ");
72
73 for (i = 0; i < len; i++) {
3563f4c5
JB
74 if (isprint(data[i]))
75 printf("%c", data[i]);
76 else
77 printf("\\x%.2x", data[i]);
78 }
79 printf("\n");
80}
81
83b4934c 82static void print_supprates(const uint8_t type, uint8_t len, const uint8_t *data)
3563f4c5
JB
83{
84 int i;
85
83b4934c 86 printf(" ");
3563f4c5 87
83b4934c 88 for (i = 0; i < len; i++) {
3563f4c5
JB
89 int r = data[i] & 0x7f;
90 printf("%d.%d%s ", r/2, 5*(r&1), data[i] & 0x80 ? "*":"");
91 }
92 printf("\n");
93}
94
83b4934c 95static void print_ds(const uint8_t type, uint8_t len, const uint8_t *data)
3563f4c5 96{
83b4934c 97 printf(" channel %d\n", data[0]);
3563f4c5
JB
98}
99
83b4934c 100static void print_country(const uint8_t type, uint8_t len, const uint8_t *data)
b7e8fa37
MH
101{
102 int i;
103
83b4934c 104 printf(" %.*s", 2, data);
b7e8fa37
MH
105 switch (data[2]) {
106 case 'I':
107 printf(" (indoor)");
108 break;
109 case 'O':
110 printf(" (outdoor)");
111 break;
b6c0d634
JB
112 case ' ':
113 printf(" (in/outdoor)");
114 break;
115 default:
116 printf(" (invalid environment)");
117 break;
b7e8fa37
MH
118 }
119 printf(", data:");
120 for(i=0; i<len-3; i++)
121 printf(" %.02x", data[i + 3]);
122 printf("\n");
123}
124
83b4934c 125static void print_erp(const uint8_t type, uint8_t len, const uint8_t *data)
fc4d1484
MH
126{
127 if (data[0] == 0x00)
83b4934c 128 printf(" <no flags>");
fc4d1484
MH
129 if (data[0] & 0x01)
130 printf(" NonERP_Present");
131 if (data[0] & 0x02)
132 printf(" Use_Protection");
133 if (data[0] & 0x04)
134 printf(" Barker_Preamble_Mode");
135 printf("\n");
136}
137
83b4934c 138static void print_cipher(const uint8_t *data)
857d966e
MH
139{
140 if (memcmp(data, wifi_oui, 3) == 0) {
141 switch (data[3]) {
142 case 0x00:
143 printf("Use group cipher suite");
144 break;
145 case 0x01:
146 printf("WEP-40");
147 break;
148 case 0x02:
149 printf("TKIP");
150 break;
151 case 0x04:
152 printf("CCMP");
153 break;
154 case 0x05:
155 printf("WEP-104");
156 break;
157 default:
5594fd23
JB
158 printf("Unknown (%.02x-%.02x-%.02x:%d)",
159 data[0], data[1] ,data[2], data[3]);
857d966e
MH
160 break;
161 }
162 } else if (memcmp(data, ieee80211_oui, 3) == 0) {
163 switch (data[3]) {
164 case 0x00:
165 printf("Use group cipher suite");
166 break;
167 case 0x01:
168 printf("WEP-40");
169 break;
170 case 0x02:
171 printf("TKIP");
172 break;
173 case 0x04:
174 printf("CCMP");
175 break;
176 case 0x05:
177 printf("WEP-104");
178 break;
179 case 0x06:
180 printf("AES-128-CMAC");
181 break;
182 default:
5594fd23
JB
183 printf("Unknown (%.02x-%.02x-%.02x:%d)",
184 data[0], data[1] ,data[2], data[3]);
857d966e
MH
185 break;
186 }
187 } else
5594fd23
JB
188 printf("Unknown (%.02x-%.02x-%.02x:%d)",
189 data[0], data[1] ,data[2], data[3]);
857d966e
MH
190}
191
83b4934c 192static void print_auth(const uint8_t *data)
857d966e
MH
193{
194 if (memcmp(data, wifi_oui, 3) == 0) {
195 switch (data[3]) {
196 case 0x01:
197 printf("IEEE 802.1X");
198 break;
199 case 0x02:
200 printf("PSK");
201 break;
202 default:
5594fd23
JB
203 printf("Unknown (%.02x-%.02x-%.02x:%d)",
204 data[0], data[1] ,data[2], data[3]);
857d966e
MH
205 break;
206 }
207 } else if (memcmp(data, ieee80211_oui, 3) == 0) {
208 switch (data[3]) {
209 case 0x01:
210 printf("IEEE 802.1X");
211 break;
212 case 0x02:
213 printf("PSK");
214 break;
215 default:
5594fd23
JB
216 printf("Unknown (%.02x-%.02x-%.02x:%d)",
217 data[0], data[1] ,data[2], data[3]);
857d966e
MH
218 break;
219 }
220 } else
5594fd23
JB
221 printf("Unknown (%.02x-%.02x-%.02x:%d)",
222 data[0], data[1] ,data[2], data[3]);
857d966e
MH
223}
224
83b4934c
JB
225static void print_rsn_ie(const char *defcipher, const char *defauth,
226 uint8_t len, const uint8_t *data)
857d966e
MH
227{
228 bool first = true;
229 __u16 version, count, capa;
230 int i;
231
857d966e
MH
232 version = data[0] + (data[1] << 8);
233 tab_on_first(&first);
234 printf("\t * Version: %d\n", version);
235
236 data += 2;
237 len -= 2;
238
239 if (len < 4) {
240 tab_on_first(&first);
241 printf("\t * Group cipher: %s\n", defcipher);
242 printf("\t * Pairwise ciphers: %s\n", defcipher);
243 return;
244 }
245
246 tab_on_first(&first);
247 printf("\t * Group cipher: ");
248 print_cipher(data);
249 printf("\n");
250
251 data += 4;
252 len -= 4;
253
254 if (len < 2) {
255 tab_on_first(&first);
256 printf("\t * Pairwise ciphers: %s\n", defcipher);
257 return;
258 }
259
260 count = data[0] | (data[1] << 8);
261 tab_on_first(&first);
262 printf("\t * Pairwise ciphers:");
263 for (i=0; i<count; i++) {
264 printf(" ");
265 print_cipher(data + 2 + (i * 4));
266 }
267 printf("\n");
268
269 data += 2 + (count * 4);
270 len -= 2 + (count * 4);
271
272 if (len < 2) {
273 tab_on_first(&first);
274 printf("\t * Authentication suites: %s\n", defauth);
275 return;
276 }
277
278 count = data[0] | (data[1] << 8);
279 tab_on_first(&first);
280 printf("\t * Authentication suites:");
83b4934c 281 for (i = 0; i < count; i++) {
857d966e
MH
282 printf(" ");
283 print_auth(data + 2 + (i * 4));
284 }
285 printf("\n");
286
287 data += 2 + (count * 4);
288 len -= 2 + (count * 4);
289
290 if (len < 2)
291 return;
292
293 capa = data[0] | (data[1] << 8);
294 tab_on_first(&first);
295 printf("\t * Capabilities: 0x%.4x\n", capa);
296}
297
83b4934c 298static void print_rsn(const uint8_t type, uint8_t len, const uint8_t *data)
857d966e 299{
83b4934c 300 print_rsn_ie("CCMP", "IEEE 802.1X", len, data);
857d966e
MH
301}
302
83b4934c 303static void print_capabilities(const uint8_t type, uint8_t len, const uint8_t *data)
9b880b00
MH
304{
305 int i;
306
83b4934c 307 for(i = 0; i < len; i++)
9b880b00
MH
308 printf(" %.02x", data[i]);
309 printf("\n");
310}
311
83b4934c
JB
312struct ie_print {
313 const char *name;
314 void (*print)(const uint8_t type, uint8_t len, const uint8_t *data);
315 uint8_t minlen, maxlen;
764fe753
JB
316};
317
83b4934c
JB
318static void print_ie(const struct ie_print *p, const uint8_t type,
319 uint8_t len, const uint8_t *data)
4673a894 320{
83b4934c
JB
321 int i;
322
323 if (!p->print)
324 return;
325
326 printf("\t%s:", p->name);
327 if (len < p->minlen || len > p->maxlen) {
328 if (len > 1) {
329 printf(" <invalid: %d bytes:", len);
330 for (i = 0; i < len; i++)
331 printf(" %.02x", data[i]);
332 printf(">\n");
333 } else if (len)
334 printf(" <invalid: 1 byte: %.02x>\n", data[0]);
335 else
336 printf(" <invalid: no data>\n");
337 return;
338 }
339
340 p->print(type, len, data);
341}
342
343#define PRINT_IGN { \
344 .name = "IGNORE", \
345 .print = NULL, \
346 .minlen = 0, \
347 .maxlen = 255, \
4673a894
JB
348}
349
83b4934c
JB
350static const struct ie_print ieprinters[] = {
351 [0] = { "SSID", print_ssid, 0, 32, },
352 [1] = { "Supported rates", print_supprates, 0, 255, },
353 [3] = { "DS Paramater set", print_ds, 1, 1, },
354 [5] = PRINT_IGN,
355 [7] = { "Country", print_country, 3, 255, },
356 [42] = { "ERP", print_erp, 1, 255, },
357 [48] = { "RSN", print_rsn, 2, 255, },
358 [50] = { "Extended supported rates", print_supprates, 0, 255, },
359 [127] = { "Extended capabilities", print_capabilities, 0, 255, },
360};
361
362static void print_wifi_wpa(const uint8_t type, uint8_t len, const uint8_t *data)
363{
364 print_rsn_ie("TKIP", "IEEE 802.1X", len, data);
365}
366
367static void print_wifi_wmm(const uint8_t type, uint8_t len, const uint8_t *data)
6ff0c93a
MH
368{
369 int i;
370
6ff0c93a
MH
371 switch (data[0]) {
372 case 0x00:
83b4934c 373 printf(" information:");
6ff0c93a
MH
374 break;
375 case 0x01:
83b4934c 376 printf(" parameter:");
6ff0c93a
MH
377 break;
378 default:
83b4934c 379 printf(" type %d:", data[0]);
6ff0c93a
MH
380 break;
381 }
382
83b4934c 383 for(i = 0; i < len - 1; i++)
6ff0c93a
MH
384 printf(" %.02x", data[i + 1]);
385 printf("\n");
386}
387
83b4934c 388static void print_wifi_wps(const uint8_t type, uint8_t len, const uint8_t *data)
4673a894
JB
389{
390 bool first = true;
391 __u16 subtype, sublen;
392
4673a894
JB
393 while (len >= 4) {
394 subtype = (data[0] << 8) + data[1];
395 sublen = (data[2] << 8) + data[3];
396 if (sublen > len)
397 break;
398
399 switch (subtype) {
400 case 0x104a:
401 tab_on_first(&first);
dffc6750 402 printf("\t * Version: %d.%d\n", data[4] >> 4, data[4] & 0xF);
4673a894
JB
403 break;
404 case 0x1011:
405 tab_on_first(&first);
406 printf("\t * Device name: %.*s\n", sublen, data + 4);
407 break;
408 case 0x1021:
409 tab_on_first(&first);
410 printf("\t * Manufacturer: %.*s\n", sublen, data + 4);
411 break;
412 case 0x1023:
413 tab_on_first(&first);
414 printf("\t * Model: %.*s\n", sublen, data + 4);
415 break;
7ee5a865
JB
416 case 0x1057: {
417 __u16 val = (data[4] << 8) | data[5];
418 tab_on_first(&first);
419 printf("\t * AP setup locked: 0x%.4x\n", val);
420 break;
421 }
4673a894
JB
422 case 0x1008: {
423 __u16 meth = (data[4] << 8) + data[5];
424 bool comma = false;
425 tab_on_first(&first);
426 printf("\t * Config methods:");
427#define T(bit, name) do { \
428 if (meth & (1<<bit)) { \
429 if (comma) \
430 printf(","); \
431 comma = true; \
432 printf(" " name); \
433 } } while (0)
434 T(0, "USB");
435 T(1, "Ethernet");
436 T(2, "Label");
437 T(3, "Display");
438 T(4, "Ext. NFC");
439 T(5, "Int. NFC");
440 T(6, "NFC Intf.");
441 T(7, "PBC");
442 T(8, "Keypad");
443 printf("\n");
444 break;
445#undef T
446 }
447 default:
448 break;
449 }
450
451 data += sublen + 4;
452 len -= sublen + 4;
453 }
454
455 if (len != 0) {
456 printf("\t\t * bogus tail data (%d):", len);
457 while (len) {
458 printf(" %.2x", *data);
459 data++;
460 len--;
461 }
462 printf("\n");
463 }
464}
465
83b4934c
JB
466static const struct ie_print wifiprinters[] = {
467 [1] = { "WPA", print_wifi_wpa, 2, 255, },
468 [2] = { "WMM", print_wifi_wmm, 1, 255, },
469 [4] = { "WPS", print_wifi_wps, 0, 255, },
4673a894
JB
470};
471
764fe753
JB
472static void print_vendor(unsigned char len, unsigned char *data,
473 struct scan_params *params)
3563f4c5
JB
474{
475 int i;
476
fbf80af5 477 if (len < 3) {
4673a894 478 printf("\tVendor specific: <too short> data:");
fbf80af5
JB
479 for(i = 0; i < len; i++)
480 printf(" %.02x", data[i]);
481 printf("\n");
482 return;
483 }
484
857d966e 485 if (len >= 4 && memcmp(data, wifi_oui, 3) == 0) {
83b4934c
JB
486 if (data[3] < ARRAY_SIZE(wifiprinters) && wifiprinters[data[3]].name) {
487 print_ie(&wifiprinters[data[3]], data[3], len - 4, data + 4);
488 return;
489 }
4673a894
JB
490 if (!params->unknown)
491 return;
857d966e 492 printf("\tWiFi OUI %#.2x, data:", data[3]);
4673a894
JB
493 for(i = 0; i < len - 4; i++)
494 printf(" %.02x", data[i + 4]);
495 printf("\n");
496 return;
497 }
498
764fe753
JB
499 if (!params->unknown)
500 return;
501
fbf80af5 502 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
3563f4c5 503 data[0], data[1], data[2]);
fbf80af5
JB
504 for (i = 3; i < len; i++)
505 printf(" %.2x", data[i]);
3563f4c5
JB
506 printf("\n");
507}
508
764fe753 509static void print_ies(unsigned char *ie, int ielen, struct scan_params *params)
3563f4c5
JB
510{
511 while (ielen >= 2 && ielen >= ie[1]) {
83b4934c
JB
512 if (ie[0] < ARRAY_SIZE(ieprinters) && ieprinters[ie[0]].name) {
513 print_ie(&ieprinters[ie[0]], ie[0], ie[1], ie + 2);
764fe753
JB
514 } else if (ie[0] == 221 /* vendor */) {
515 print_vendor(ie[1], ie + 2, params);
516 } else if (params->unknown) {
3563f4c5
JB
517 int i;
518
8086b700 519 printf("\tUnknown IE (%d):", ie[0]);
3563f4c5 520 for (i=0; i<ie[1]; i++)
8086b700 521 printf(" %.2x", ie[2+i]);
3563f4c5
JB
522 printf("\n");
523 }
524 ielen -= ie[1] + 2;
525 ie += ie[1] + 2;
526 }
527}
528
529static int print_bss_handler(struct nl_msg *msg, void *arg)
530{
531 struct nlattr *tb[NL80211_ATTR_MAX + 1];
532 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
533 struct nlattr *bss[NL80211_BSS_MAX + 1];
534 char mac_addr[20], dev[20];
535 static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
536 [NL80211_BSS_TSF] = { .type = NLA_U64 },
537 [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
538 [NL80211_BSS_BSSID] = { },
539 [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
540 [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
541 [NL80211_BSS_INFORMATION_ELEMENTS] = { },
f2e17e1f
JB
542 [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
543 [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
3563f4c5
JB
544 };
545
546 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
547 genlmsg_attrlen(gnlh, 0), NULL);
548
549 if (!tb[NL80211_ATTR_BSS]) {
550 fprintf(stderr, "bss info missing!");
551 return NL_SKIP;
552 }
553 if (nla_parse_nested(bss, NL80211_BSS_MAX,
554 tb[NL80211_ATTR_BSS],
555 bss_policy)) {
556 fprintf(stderr, "failed to parse nested attributes!");
557 return NL_SKIP;
558 }
559
560 if (!bss[NL80211_BSS_BSSID])
561 return NL_SKIP;
562
563 mac_addr_n2a(mac_addr, nla_data(bss[NL80211_BSS_BSSID]));
564 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
565 printf("BSS %s (on %s)\n", mac_addr, dev);
566
e7109a8a
JB
567 if (bss[NL80211_BSS_TSF]) {
568 unsigned long long tsf;
569 tsf = (unsigned long long)nla_get_u64(bss[NL80211_BSS_TSF]);
570 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
571 tsf, tsf/1000/1000/60/60/24, (tsf/1000/1000/60/60) % 24,
572 (tsf/1000/1000/60) % 60, (tsf/1000/1000) % 60);
573 }
3563f4c5
JB
574 if (bss[NL80211_BSS_FREQUENCY])
575 printf("\tfreq: %d\n",
576 nla_get_u32(bss[NL80211_BSS_FREQUENCY]));
577 if (bss[NL80211_BSS_BEACON_INTERVAL])
578 printf("\tbeacon interval: %d\n",
579 nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]));
92a04ecd
MH
580 if (bss[NL80211_BSS_CAPABILITY]) {
581 __u16 capa = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
582 printf("\tcapability:");
583 if (capa & WLAN_CAPABILITY_ESS)
584 printf(" ESS");
585 if (capa & WLAN_CAPABILITY_IBSS)
586 printf(" IBSS");
587 if (capa & WLAN_CAPABILITY_PRIVACY)
588 printf(" Privacy");
589 if (capa & WLAN_CAPABILITY_SHORT_PREAMBLE)
590 printf(" ShortPreamble");
591 if (capa & WLAN_CAPABILITY_PBCC)
592 printf(" PBCC");
593 if (capa & WLAN_CAPABILITY_CHANNEL_AGILITY)
594 printf(" ChannelAgility");
595 if (capa & WLAN_CAPABILITY_SPECTRUM_MGMT)
596 printf(" SpectrumMgmt");
597 if (capa & WLAN_CAPABILITY_QOS)
598 printf(" QoS");
599 if (capa & WLAN_CAPABILITY_SHORT_SLOT_TIME)
600 printf(" ShortSlotTime");
601 if (capa & WLAN_CAPABILITY_APSD)
602 printf(" APSD");
603 if (capa & WLAN_CAPABILITY_DSSS_OFDM)
604 printf(" DSSS-OFDM");
605 printf(" (0x%.4x)\n", capa);
606 }
f2e17e1f
JB
607 if (bss[NL80211_BSS_SIGNAL_MBM]) {
608 int s = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
609 printf("\tsignal: %d.%.2d dBm\n", s/100, s%100);
610 }
611 if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
612 unsigned char s = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
613 printf("\tsignal: %d/100\n", s);
614 }
3563f4c5
JB
615 if (bss[NL80211_BSS_INFORMATION_ELEMENTS])
616 print_ies(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
764fe753
JB
617 nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
618 arg);
3563f4c5
JB
619
620 return NL_SKIP;
621}
622
764fe753 623static struct scan_params scan_params;
3563f4c5 624
7c37a24d
JB
625static int handle_scan_dump(struct nl80211_state *state,
626 struct nl_cb *cb,
3563f4c5
JB
627 struct nl_msg *msg,
628 int argc, char **argv)
629{
764fe753
JB
630 if (argc > 1)
631 return 1;
632
633 scan_params.unknown = false;
634 if (argc == 1 && !strcmp(argv[0], "-u"))
635 scan_params.unknown = true;
636
637 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_bss_handler,
638 &scan_params);
3563f4c5
JB
639 return 0;
640}
764fe753 641COMMAND(scan, dump, "[-u]",
3563f4c5 642 NL80211_CMD_GET_SCAN, NLM_F_DUMP, CIB_NETDEV, handle_scan_dump);
a5fe4ef2
JB
643
644static int handle_scan_combined(struct nl80211_state *state,
645 struct nl_cb *cb,
646 struct nl_msg *msg,
647 int argc, char **argv)
648{
649 static char *trig_argv[] = {
650 NULL,
651 "scan",
652 "trigger",
653 };
654 static char *dump_argv[] = {
655 NULL,
656 "scan",
657 "dump",
92649eab 658 NULL,
a5fe4ef2
JB
659 };
660 static const __u32 cmds[] = {
661 NL80211_CMD_NEW_SCAN_RESULTS,
662 NL80211_CMD_SCAN_ABORTED,
663 };
92649eab 664 int dump_argc, err;
a5fe4ef2
JB
665
666 trig_argv[0] = argv[0];
667 err = handle_cmd(state, II_NETDEV, ARRAY_SIZE(trig_argv), trig_argv);
668 if (err)
669 return err;
670
61725dbe
JB
671 /*
672 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
673 *
674 * This code has a bug, which requires creating a separate
675 * nl80211 socket to fix:
676 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
677 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
678 * before (!) we listen to it, because we only start listening
679 * after we send our scan request.
680 *
681 * Doing it the other way around has a race condition as well,
682 * if you first open the events socket you may get a notification
683 * for a previous scan.
684 *
685 * The only proper way to fix this would be to listen to events
686 * before sending the command, and for the kernel to send the
687 * scan request along with the event, so that you can match up
688 * whether the scan you requested was finished or aborted (this
689 * may result in processing a scan that another application
690 * requested, but that doesn't seem to be a problem).
691 *
692 * Alas, the kernel doesn't do that (yet).
693 */
694
a5fe4ef2
JB
695 if (listen_events(state, ARRAY_SIZE(cmds), cmds) ==
696 NL80211_CMD_SCAN_ABORTED) {
697 printf("scan aborted!\n");
698 return 0;
699 }
700
92649eab
MH
701 if (argc == 3 && !strcmp(argv[2], "-u")) {
702 dump_argc = 4;
703 dump_argv[3] = "-u";
704 } else
705 dump_argc = 3;
706
a5fe4ef2 707 dump_argv[0] = argv[0];
92649eab 708 return handle_cmd(state, II_NETDEV, dump_argc, dump_argv);
a5fe4ef2 709}
92649eab 710TOPLEVEL(scan, "[-u]", 0, 0, CIB_NETDEV, handle_scan_combined);