]> git.ipfire.org Git - thirdparty/hostap.git/blame - wlantest/wlantest_cli.c
edit: Use struct dl_list for history buffer
[thirdparty/hostap.git] / wlantest / wlantest_cli.c
CommitLineData
644fb8c8
JM
1/*
2 * wlantest controller
3 * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "utils/includes.h"
16#include <sys/un.h>
17
18#include "utils/common.h"
ef49bb80
JM
19#include "utils/eloop.h"
20#include "utils/edit.h"
644fb8c8
JM
21#include "wlantest_ctrl.h"
22
23
79a670cb
JM
24static int get_cmd_arg_num(const char *str, int pos)
25{
26 int arg = 0, i;
27
28 for (i = 0; i <= pos; i++) {
29 if (str[i] != ' ') {
30 arg++;
31 while (i <= pos && str[i] != ' ')
32 i++;
33 }
34 }
35
36 if (arg > 0)
37 arg--;
38 return arg;
39}
40
41
42static int get_prev_arg_pos(const char *str, int pos)
43{
44 while (pos > 0 && str[pos - 1] != ' ')
45 pos--;
46 while (pos > 0 && str[pos - 1] == ' ')
47 pos--;
48 while (pos > 0 && str[pos - 1] != ' ')
49 pos--;
50 return pos;
51}
52
53
6f2346c1
JM
54static u8 * attr_get(u8 *buf, size_t buflen, enum wlantest_ctrl_attr attr,
55 size_t *len)
56{
57 u8 *pos = buf;
58
59 while (pos + 8 <= buf + buflen) {
60 enum wlantest_ctrl_attr a;
61 size_t alen;
62 a = WPA_GET_BE32(pos);
63 pos += 4;
64 alen = WPA_GET_BE32(pos);
65 pos += 4;
66 if (pos + alen > buf + buflen) {
67 printf("Invalid control message attribute\n");
68 return NULL;
69 }
70 if (a == attr) {
71 *len = alen;
72 return pos;
73 }
74 pos += alen;
75 }
76
77 return NULL;
78}
79
80
6d5ce9fc
JM
81static u8 * attr_hdr_add(u8 *pos, u8 *end, enum wlantest_ctrl_attr attr,
82 size_t len)
83{
84 if (pos == NULL || end - pos < 8 + len)
85 return NULL;
86 WPA_PUT_BE32(pos, attr);
87 pos += 4;
88 WPA_PUT_BE32(pos, len);
89 pos += 4;
90 return pos;
91}
92
93
fbdd2132
JM
94static u8 * attr_add_str(u8 *pos, u8 *end, enum wlantest_ctrl_attr attr,
95 const char *str)
96{
97 size_t len = os_strlen(str);
98
99 if (pos == NULL || end - pos < 8 + len)
100 return NULL;
101 WPA_PUT_BE32(pos, attr);
102 pos += 4;
103 WPA_PUT_BE32(pos, len);
104 pos += 4;
105 os_memcpy(pos, str, len);
106 pos += len;
107 return pos;
108}
109
110
6d5ce9fc
JM
111static u8 * attr_add_be32(u8 *pos, u8 *end, enum wlantest_ctrl_attr attr,
112 u32 val)
113{
114 if (pos == NULL || end - pos < 12)
115 return NULL;
116 WPA_PUT_BE32(pos, attr);
117 pos += 4;
118 WPA_PUT_BE32(pos, 4);
119 pos += 4;
120 WPA_PUT_BE32(pos, val);
121 pos += 4;
122 return pos;
123}
124
125
6f2346c1
JM
126static int cmd_send_and_recv(int s, const u8 *cmd, size_t cmd_len,
127 u8 *resp, size_t max_resp_len)
644fb8c8 128{
644fb8c8 129 int res;
6f2346c1 130 enum wlantest_ctrl_cmd cmd_resp;
644fb8c8 131
6f2346c1 132 if (send(s, cmd, cmd_len, 0) < 0)
644fb8c8 133 return -1;
6f2346c1 134 res = recv(s, resp, max_resp_len, 0);
644fb8c8
JM
135 if (res < 4)
136 return -1;
137
6f2346c1
JM
138 cmd_resp = WPA_GET_BE32(resp);
139 if (cmd_resp == WLANTEST_CTRL_SUCCESS)
140 return res;
141
142 if (cmd_resp == WLANTEST_CTRL_UNKNOWN_CMD)
644fb8c8 143 printf("Unknown command\n");
6f2346c1
JM
144 else if (cmd_resp == WLANTEST_CTRL_INVALID_CMD)
145 printf("Invalid command\n");
644fb8c8 146
6f2346c1
JM
147 return -1;
148}
149
150
151static int cmd_simple(int s, enum wlantest_ctrl_cmd cmd)
152{
153 u8 buf[4];
154 int res;
155 WPA_PUT_BE32(buf, cmd);
156 res = cmd_send_and_recv(s, buf, sizeof(buf), buf, sizeof(buf));
157 return res < 0 ? -1 : 0;
644fb8c8
JM
158}
159
160
79a670cb
JM
161static char ** get_bssid_list(int s)
162{
163 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
164 u8 buf[4];
165 u8 *bssid;
166 size_t len;
167 int rlen, i;
168 char **res;
169
170 WPA_PUT_BE32(buf, WLANTEST_CTRL_LIST_BSS);
171 rlen = cmd_send_and_recv(s, buf, sizeof(buf), resp, sizeof(resp));
172 if (rlen < 0)
173 return NULL;
174
175 bssid = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_BSSID, &len);
176 if (bssid == NULL)
177 return NULL;
178
179 res = os_zalloc((len / ETH_ALEN + 1) * sizeof(char *));
180 if (res == NULL)
181 return NULL;
182 for (i = 0; i < len / ETH_ALEN; i++) {
183 res[i] = os_zalloc(18);
184 if (res[i] == NULL)
185 break;
186 os_snprintf(res[i], 18, MACSTR, MAC2STR(bssid + ETH_ALEN * i));
187 }
188
189 return res;
190}
191
192
193static char ** get_sta_list(int s, const u8 *bssid, int add_bcast)
194{
195 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
196 u8 buf[100], *pos, *end;
197 u8 *addr;
198 size_t len;
199 int rlen, i;
200 char **res;
201
202 pos = buf;
203 end = buf + sizeof(buf);
204 WPA_PUT_BE32(pos, WLANTEST_CTRL_LIST_STA);
205 pos += 4;
206 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
207 os_memcpy(pos, bssid, ETH_ALEN);
208 pos += ETH_ALEN;
0954399c 209 rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
79a670cb
JM
210 if (rlen < 0)
211 return NULL;
212
213 addr = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_STA_ADDR, &len);
214 if (addr == NULL)
215 return NULL;
216
217 res = os_zalloc((len / ETH_ALEN + 1 + add_bcast) * sizeof(char *));
218 if (res == NULL)
219 return NULL;
220 for (i = 0; i < len / ETH_ALEN; i++) {
221 res[i] = os_zalloc(18);
222 if (res[i] == NULL)
223 break;
224 os_snprintf(res[i], 18, MACSTR, MAC2STR(addr + ETH_ALEN * i));
225 }
226 if (add_bcast)
227 res[i] = os_strdup("ff:ff:ff:ff:ff:ff");
228
229 return res;
230}
231
232
644fb8c8
JM
233static int cmd_ping(int s, int argc, char *argv[])
234{
6f2346c1
JM
235 int res = cmd_simple(s, WLANTEST_CTRL_PING);
236 if (res == 0)
237 printf("PONG\n");
238 return res == 0;
644fb8c8
JM
239}
240
241
242static int cmd_terminate(int s, int argc, char *argv[])
243{
244 return cmd_simple(s, WLANTEST_CTRL_TERMINATE);
245}
246
247
6f2346c1
JM
248static int cmd_list_bss(int s, int argc, char *argv[])
249{
250 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
251 u8 buf[4];
252 u8 *bssid;
253 size_t len;
254 int rlen, i;
255
256 WPA_PUT_BE32(buf, WLANTEST_CTRL_LIST_BSS);
257 rlen = cmd_send_and_recv(s, buf, sizeof(buf), resp, sizeof(resp));
258 if (rlen < 0)
259 return -1;
260
261 bssid = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_BSSID, &len);
262 if (bssid == NULL)
263 return -1;
264
265 for (i = 0; i < len / ETH_ALEN; i++)
266 printf(MACSTR " ", MAC2STR(bssid + ETH_ALEN * i));
267 printf("\n");
268
269 return 0;
270}
271
272
273static int cmd_list_sta(int s, int argc, char *argv[])
274{
275 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
276 u8 buf[100], *pos;
277 u8 *addr;
278 size_t len;
279 int rlen, i;
280
281 if (argc < 1) {
282 printf("list_sta needs one argument: BSSID\n");
283 return -1;
284 }
285
286 pos = buf;
287 WPA_PUT_BE32(pos, WLANTEST_CTRL_LIST_STA);
288 pos += 4;
289 WPA_PUT_BE32(pos, WLANTEST_ATTR_BSSID);
290 pos += 4;
291 WPA_PUT_BE32(pos, ETH_ALEN);
292 pos += 4;
293 if (hwaddr_aton(argv[0], pos) < 0) {
294 printf("Invalid BSSID '%s'\n", argv[0]);
295 return -1;
296 }
297 pos += ETH_ALEN;
298
299 rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
300 if (rlen < 0)
301 return -1;
302
303 addr = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_STA_ADDR, &len);
304 if (addr == NULL)
305 return -1;
306
307 for (i = 0; i < len / ETH_ALEN; i++)
308 printf(MACSTR " ", MAC2STR(addr + ETH_ALEN * i));
309 printf("\n");
310
311 return 0;
312}
313
314
79a670cb
JM
315static char ** complete_list_sta(int s, const char *str, int pos)
316{
317 if (get_cmd_arg_num(str, pos) == 1)
318 return get_bssid_list(s);
319 return NULL;
320}
321
322
d356bd63
JM
323static int cmd_flush(int s, int argc, char *argv[])
324{
325 return cmd_simple(s, WLANTEST_CTRL_FLUSH);
326}
327
328
6d5ce9fc
JM
329static int cmd_clear_sta_counters(int s, int argc, char *argv[])
330{
331 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
332 u8 buf[100], *pos;
333 int rlen;
334
335 if (argc < 2) {
336 printf("clear_sta_counters needs two arguments: BSSID and "
337 "STA address\n");
338 return -1;
339 }
340
341 pos = buf;
342 WPA_PUT_BE32(pos, WLANTEST_CTRL_CLEAR_STA_COUNTERS);
343 pos += 4;
344 WPA_PUT_BE32(pos, WLANTEST_ATTR_BSSID);
345 pos += 4;
346 WPA_PUT_BE32(pos, ETH_ALEN);
347 pos += 4;
348 if (hwaddr_aton(argv[0], pos) < 0) {
349 printf("Invalid BSSID '%s'\n", argv[0]);
350 return -1;
351 }
352 pos += ETH_ALEN;
353
354 WPA_PUT_BE32(pos, WLANTEST_ATTR_STA_ADDR);
355 pos += 4;
356 WPA_PUT_BE32(pos, ETH_ALEN);
357 pos += 4;
358 if (hwaddr_aton(argv[1], pos) < 0) {
359 printf("Invalid STA address '%s'\n", argv[1]);
360 return -1;
361 }
362 pos += ETH_ALEN;
363
364 rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
365 if (rlen < 0)
366 return -1;
367 printf("OK\n");
368 return 0;
369}
370
371
79a670cb
JM
372static char ** complete_clear_sta_counters(int s, const char *str, int pos)
373{
374 int arg = get_cmd_arg_num(str, pos);
375 char **res = NULL;
376 u8 addr[ETH_ALEN];
377
378 switch (arg) {
379 case 1:
380 res = get_bssid_list(s);
381 break;
382 case 2:
383 if (hwaddr_aton(&str[get_prev_arg_pos(str, pos)], addr) < 0)
384 break;
385 res = get_sta_list(s, addr, 0);
386 break;
387 }
388
389 return res;
390}
391
392
6d5ce9fc
JM
393static int cmd_clear_bss_counters(int s, int argc, char *argv[])
394{
395 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
396 u8 buf[100], *pos;
397 int rlen;
398
399 if (argc < 1) {
400 printf("clear_bss_counters needs one argument: BSSID\n");
401 return -1;
402 }
403
404 pos = buf;
405 WPA_PUT_BE32(pos, WLANTEST_CTRL_CLEAR_BSS_COUNTERS);
406 pos += 4;
407 WPA_PUT_BE32(pos, WLANTEST_ATTR_BSSID);
408 pos += 4;
409 WPA_PUT_BE32(pos, ETH_ALEN);
410 pos += 4;
411 if (hwaddr_aton(argv[0], pos) < 0) {
412 printf("Invalid BSSID '%s'\n", argv[0]);
413 return -1;
414 }
415 pos += ETH_ALEN;
416
417 rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
418 if (rlen < 0)
419 return -1;
420 printf("OK\n");
421 return 0;
422}
423
424
79a670cb
JM
425static char ** complete_clear_bss_counters(int s, const char *str, int pos)
426{
427 if (get_cmd_arg_num(str, pos) == 1)
428 return get_bssid_list(s);
429 return NULL;
430}
431
432
6d5ce9fc
JM
433struct sta_counters {
434 const char *name;
435 enum wlantest_sta_counter num;
436};
437
438static const struct sta_counters sta_counters[] = {
439 { "auth_tx", WLANTEST_STA_COUNTER_AUTH_TX },
440 { "auth_rx", WLANTEST_STA_COUNTER_AUTH_RX },
441 { "assocreq_tx", WLANTEST_STA_COUNTER_ASSOCREQ_TX },
442 { "reassocreq_tx", WLANTEST_STA_COUNTER_REASSOCREQ_TX },
443 { "ptk_learned", WLANTEST_STA_COUNTER_PTK_LEARNED },
444 { "valid_deauth_tx", WLANTEST_STA_COUNTER_VALID_DEAUTH_TX },
445 { "valid_deauth_rx", WLANTEST_STA_COUNTER_VALID_DEAUTH_RX },
446 { "invalid_deauth_tx", WLANTEST_STA_COUNTER_INVALID_DEAUTH_TX },
447 { "invalid_deauth_rx", WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX },
448 { "valid_disassoc_tx", WLANTEST_STA_COUNTER_VALID_DISASSOC_TX },
449 { "valid_disassoc_rx", WLANTEST_STA_COUNTER_VALID_DISASSOC_RX },
450 { "invalid_disassoc_tx", WLANTEST_STA_COUNTER_INVALID_DISASSOC_TX },
451 { "invalid_disassoc_rx", WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX },
452 { "valid_saqueryreq_tx", WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_TX },
453 { "valid_saqueryreq_rx", WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_RX },
454 { "invalid_saqueryreq_tx",
455 WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_TX },
456 { "invalid_saqueryreq_rx",
457 WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_RX },
458 { "valid_saqueryresp_tx", WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_TX },
459 { "valid_saqueryresp_rx", WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_RX },
460 { "invalid_saqueryresp_tx",
461 WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_TX },
462 { "invalid_saqueryresp_rx",
463 WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_RX },
ee3b84be 464 { "ping_ok", WLANTEST_STA_COUNTER_PING_OK },
6d5ce9fc
JM
465 { NULL, 0 }
466};
467
468static int cmd_get_sta_counter(int s, int argc, char *argv[])
469{
470 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
471 u8 buf[100], *end, *pos;
472 int rlen, i;
473 size_t len;
474
475 if (argc != 3) {
476 printf("get_sta_counter needs at three arguments: "
477 "counter name, BSSID, and STA address\n");
478 return -1;
479 }
480
481 pos = buf;
482 end = buf + sizeof(buf);
483 WPA_PUT_BE32(pos, WLANTEST_CTRL_GET_STA_COUNTER);
484 pos += 4;
485
486 for (i = 0; sta_counters[i].name; i++) {
487 if (os_strcasecmp(sta_counters[i].name, argv[0]) == 0)
488 break;
489 }
490 if (sta_counters[i].name == NULL) {
491 printf("Unknown STA counter '%s'\n", argv[0]);
492 printf("Counters:");
493 for (i = 0; sta_counters[i].name; i++)
494 printf(" %s", sta_counters[i].name);
495 printf("\n");
496 return -1;
497 }
498
499 pos = attr_add_be32(pos, end, WLANTEST_ATTR_STA_COUNTER,
500 sta_counters[i].num);
501 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
502 if (hwaddr_aton(argv[1], pos) < 0) {
503 printf("Invalid BSSID '%s'\n", argv[1]);
504 return -1;
505 }
506 pos += ETH_ALEN;
507
508 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA_ADDR, ETH_ALEN);
509 if (hwaddr_aton(argv[2], pos) < 0) {
510 printf("Invalid STA address '%s'\n", argv[2]);
511 return -1;
512 }
513 pos += ETH_ALEN;
514
515 rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
516 if (rlen < 0)
517 return -1;
518
519 pos = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_COUNTER, &len);
520 if (pos == NULL || len != 4)
521 return -1;
522 printf("%u\n", WPA_GET_BE32(pos));
523 return 0;
524}
525
526
79a670cb
JM
527static char ** complete_get_sta_counter(int s, const char *str, int pos)
528{
529 int arg = get_cmd_arg_num(str, pos);
530 char **res = NULL;
531 int i, count;
532 u8 addr[ETH_ALEN];
533
534 switch (arg) {
535 case 1:
536 /* counter list */
537 count = sizeof(sta_counters) / sizeof(sta_counters[0]);
538 res = os_zalloc(count * sizeof(char *));
539 if (res == NULL)
540 return NULL;
541 for (i = 0; sta_counters[i].name; i++) {
542 res[i] = os_strdup(sta_counters[i].name);
543 if (res[i] == NULL)
544 break;
545 }
546 break;
547 case 2:
548 res = get_bssid_list(s);
549 break;
550 case 3:
551 if (hwaddr_aton(&str[get_prev_arg_pos(str, pos)], addr) < 0)
552 break;
553 res = get_sta_list(s, addr, 0);
554 break;
555 }
556
557 return res;
558}
559
560
6d5ce9fc
JM
561struct bss_counters {
562 const char *name;
563 enum wlantest_bss_counter num;
564};
565
566static const struct bss_counters bss_counters[] = {
567 { "valid_bip_mmie", WLANTEST_BSS_COUNTER_VALID_BIP_MMIE },
568 { "invalid_bip_mmie", WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE },
569 { "missing_bip_mmie", WLANTEST_BSS_COUNTER_MISSING_BIP_MMIE },
570 { NULL, 0 }
571};
572
573static int cmd_get_bss_counter(int s, int argc, char *argv[])
574{
575 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
576 u8 buf[100], *end, *pos;
577 int rlen, i;
578 size_t len;
579
580 if (argc != 2) {
581 printf("get_bss_counter needs at three arguments: "
582 "counter name and BSSID\n");
583 return -1;
584 }
585
586 pos = buf;
587 end = buf + sizeof(buf);
588 WPA_PUT_BE32(pos, WLANTEST_CTRL_GET_BSS_COUNTER);
589 pos += 4;
590
591 for (i = 0; bss_counters[i].name; i++) {
592 if (os_strcasecmp(bss_counters[i].name, argv[0]) == 0)
593 break;
594 }
595 if (bss_counters[i].name == NULL) {
596 printf("Unknown BSS counter '%s'\n", argv[0]);
597 printf("Counters:");
598 for (i = 0; bss_counters[i].name; i++)
599 printf(" %s", bss_counters[i].name);
600 printf("\n");
601 return -1;
602 }
603
604 pos = attr_add_be32(pos, end, WLANTEST_ATTR_BSS_COUNTER,
605 bss_counters[i].num);
606 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
607 if (hwaddr_aton(argv[1], pos) < 0) {
608 printf("Invalid BSSID '%s'\n", argv[1]);
609 return -1;
610 }
611 pos += ETH_ALEN;
612
613 rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
614 if (rlen < 0)
615 return -1;
616
617 pos = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_COUNTER, &len);
618 if (pos == NULL || len != 4)
619 return -1;
620 printf("%u\n", WPA_GET_BE32(pos));
621 return 0;
622}
623
624
79a670cb
JM
625static char ** complete_get_bss_counter(int s, const char *str, int pos)
626{
627 int arg = get_cmd_arg_num(str, pos);
628 char **res = NULL;
629 int i, count;
630
631 switch (arg) {
632 case 1:
633 /* counter list */
634 count = sizeof(bss_counters) / sizeof(bss_counters[0]);
635 res = os_zalloc(count * sizeof(char *));
636 if (res == NULL)
637 return NULL;
638 for (i = 0; bss_counters[i].name; i++) {
639 res[i] = os_strdup(bss_counters[i].name);
640 if (res[i] == NULL)
641 break;
642 }
643 break;
644 case 2:
645 res = get_bssid_list(s);
646 break;
647 }
648
649 return res;
650}
651
652
7d23e971
JM
653struct inject_frames {
654 const char *name;
655 enum wlantest_inject_frame frame;
656};
657
658static const struct inject_frames inject_frames[] = {
659 { "auth", WLANTEST_FRAME_AUTH },
660 { "assocreq", WLANTEST_FRAME_ASSOCREQ },
661 { "reassocreq", WLANTEST_FRAME_REASSOCREQ },
662 { "deauth", WLANTEST_FRAME_DEAUTH },
663 { "disassoc", WLANTEST_FRAME_DISASSOC },
664 { "saqueryreq", WLANTEST_FRAME_SAQUERYREQ },
665 { NULL, 0 }
666};
667
668static int cmd_inject(int s, int argc, char *argv[])
669{
670 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
671 u8 buf[100], *end, *pos;
672 int rlen, i;
673 enum wlantest_inject_protection prot;
674
675 /* <frame> <prot> <sender> <BSSID> <STA/ff:ff:ff:ff:ff:ff> */
676
677 if (argc < 5) {
678 printf("inject needs five arguments: frame, protection, "
679 "sender, BSSID, STA/ff:ff:ff:ff:ff:ff\n");
680 return -1;
681 }
682
683 pos = buf;
684 end = buf + sizeof(buf);
685 WPA_PUT_BE32(pos, WLANTEST_CTRL_INJECT);
686 pos += 4;
687
688 for (i = 0; inject_frames[i].name; i++) {
689 if (os_strcasecmp(inject_frames[i].name, argv[0]) == 0)
690 break;
691 }
692 if (inject_frames[i].name == NULL) {
693 printf("Unknown inject frame '%s'\n", argv[0]);
694 printf("Frames:");
695 for (i = 0; inject_frames[i].name; i++)
696 printf(" %s", inject_frames[i].name);
697 printf("\n");
698 return -1;
699 }
700
701 pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_FRAME,
702 inject_frames[i].frame);
703
704 if (os_strcasecmp(argv[1], "normal") == 0)
705 prot = WLANTEST_INJECT_NORMAL;
706 else if (os_strcasecmp(argv[1], "protected") == 0)
707 prot = WLANTEST_INJECT_PROTECTED;
708 else if (os_strcasecmp(argv[1], "unprotected") == 0)
709 prot = WLANTEST_INJECT_UNPROTECTED;
710 else if (os_strcasecmp(argv[1], "incorrect") == 0)
711 prot = WLANTEST_INJECT_INCORRECT_KEY;
712 else {
713 printf("Unknown protection type '%s'\n", argv[1]);
714 printf("Protection types: normal protected unprotected "
715 "incorrect\n");
716 return -1;
717 }
718 pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_PROTECTION, prot);
719
720 if (os_strcasecmp(argv[2], "ap") == 0) {
721 pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_SENDER_AP,
722 1);
723 } else if (os_strcasecmp(argv[2], "sta") == 0) {
724 pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_SENDER_AP,
725 0);
726 } else {
727 printf("Unknown sender '%s'\n", argv[2]);
728 printf("Sender types: ap sta\n");
729 return -1;
730 }
731
732 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
733 if (hwaddr_aton(argv[3], pos) < 0) {
734 printf("Invalid BSSID '%s'\n", argv[3]);
735 return -1;
736 }
737 pos += ETH_ALEN;
738
739 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA_ADDR, ETH_ALEN);
740 if (hwaddr_aton(argv[4], pos) < 0) {
741 printf("Invalid STA '%s'\n", argv[4]);
742 return -1;
743 }
744 pos += ETH_ALEN;
745
746 rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
747 if (rlen < 0)
748 return -1;
749 printf("OK\n");
750 return 0;
751}
752
753
79a670cb
JM
754static char ** complete_inject(int s, const char *str, int pos)
755{
756 int arg = get_cmd_arg_num(str, pos);
757 char **res = NULL;
758 int i, count;
759 u8 addr[ETH_ALEN];
760
761 switch (arg) {
762 case 1:
763 /* frame list */
764 count = sizeof(inject_frames) / sizeof(inject_frames[0]);
765 res = os_zalloc(count * sizeof(char *));
766 if (res == NULL)
767 break;
768 for (i = 0; inject_frames[i].name; i++) {
769 res[i] = os_strdup(inject_frames[i].name);
770 if (res[i] == NULL)
771 break;
772 }
773 break;
774 case 2:
775 res = os_zalloc(5 * sizeof(char *));
776 if (res == NULL)
777 break;
778 res[0] = os_strdup("normal");
779 if (res[0] == NULL)
780 break;
781 res[1] = os_strdup("protected");
782 if (res[1] == NULL)
783 break;
784 res[2] = os_strdup("unprotected");
785 if (res[2] == NULL)
786 break;
787 res[3] = os_strdup("incorrect");
788 if (res[3] == NULL)
789 break;
790 break;
791 case 3:
792 res = os_zalloc(3 * sizeof(char *));
793 if (res == NULL)
794 break;
795 res[0] = os_strdup("ap");
796 if (res[0] == NULL)
797 break;
798 res[1] = os_strdup("sta");
799 if (res[1] == NULL)
800 break;
801 break;
802 case 4:
803 res = get_bssid_list(s);
804 break;
805 case 5:
806 if (hwaddr_aton(&str[get_prev_arg_pos(str, pos)], addr) < 0)
807 break;
808 res = get_sta_list(s, addr, 1);
809 break;
810 }
811
812 return res;
813}
814
815
a16c8590
JM
816static int cmd_version(int s, int argc, char *argv[])
817{
818 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
819 u8 buf[4];
820 char *version;
821 size_t len;
822 int rlen, i;
823
824 WPA_PUT_BE32(buf, WLANTEST_CTRL_VERSION);
825 rlen = cmd_send_and_recv(s, buf, sizeof(buf), resp, sizeof(resp));
826 if (rlen < 0)
827 return -1;
828
829 version = (char *) attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_VERSION,
830 &len);
831 if (version == NULL)
832 return -1;
833
834 for (i = 0; i < len; i++)
835 putchar(version[i]);
836 printf("\n");
837
838 return 0;
839}
840
841
fbdd2132
JM
842static int cmd_add_passphrase(int s, int argc, char *argv[])
843{
844 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
845 u8 buf[100], *pos, *end;
846 size_t len;
847 int rlen;
848
849 if (argc < 1) {
850 printf("add_passphrase needs one argument: passphrase\n");
851 return -1;
852 }
853
854 len = os_strlen(argv[0]);
855 if (len < 8 || len > 63) {
856 printf("Invalid passphrase '%s'\n", argv[0]);
857 return -1;
858 }
859 pos = buf;
860 end = buf + sizeof(buf);
861 WPA_PUT_BE32(pos, WLANTEST_CTRL_ADD_PASSPHRASE);
862 pos += 4;
863 pos = attr_add_str(pos, end, WLANTEST_ATTR_PASSPHRASE,
864 argv[0]);
865 if (argc > 1) {
866 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
867 if (hwaddr_aton(argv[1], pos) < 0) {
868 printf("Invalid BSSID '%s'\n", argv[3]);
869 return -1;
870 }
871 pos += ETH_ALEN;
872 }
873
874 rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
875 if (rlen < 0)
876 return -1;
877 return 0;
878}
879
880
644fb8c8
JM
881struct wlantest_cli_cmd {
882 const char *cmd;
883 int (*handler)(int s, int argc, char *argv[]);
884 const char *usage;
79a670cb 885 char ** (*complete)(int s, const char *str, int pos);
644fb8c8
JM
886};
887
888static const struct wlantest_cli_cmd wlantest_cli_commands[] = {
79a670cb
JM
889 { "ping", cmd_ping, "= test connection to wlantest", NULL },
890 { "terminate", cmd_terminate, "= terminate wlantest", NULL },
891 { "list_bss", cmd_list_bss, "= get BSS list", NULL },
892 { "list_sta", cmd_list_sta, "<BSSID> = get STA list",
893 complete_list_sta },
894 { "flush", cmd_flush, "= drop all collected BSS data", NULL },
6d5ce9fc 895 { "clear_sta_counters", cmd_clear_sta_counters,
79a670cb 896 "<BSSID> <STA> = clear STA counters", complete_clear_sta_counters },
6d5ce9fc 897 { "clear_bss_counters", cmd_clear_bss_counters,
79a670cb 898 "<BSSID> = clear BSS counters", complete_clear_bss_counters },
6d5ce9fc 899 { "get_sta_counter", cmd_get_sta_counter,
79a670cb
JM
900 "<counter> <BSSID> <STA> = get STA counter value",
901 complete_get_sta_counter},
6d5ce9fc 902 { "get_bss_counter", cmd_get_bss_counter,
79a670cb
JM
903 "<counter> <BSSID> = get BSS counter value",
904 complete_get_bss_counter },
7d23e971 905 { "inject", cmd_inject,
79a670cb
JM
906 "<frame> <prot> <sender> <BSSID> <STA/ff:ff:ff:ff:ff:ff>",
907 complete_inject },
908 { "version", cmd_version, "= get wlantest version", NULL },
fbdd2132 909 { "add_passphrase", cmd_add_passphrase,
79a670cb
JM
910 "<passphrase> = add a known passphrase", NULL },
911 { NULL, NULL, NULL, NULL }
644fb8c8
JM
912};
913
914
915static int ctrl_command(int s, int argc, char *argv[])
916{
917 const struct wlantest_cli_cmd *cmd, *match = NULL;
918 int count = 0;
919 int ret = 0;
920
921 for (cmd = wlantest_cli_commands; cmd->cmd; cmd++) {
922 if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0)
923 {
924 match = cmd;
925 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
926 /* exact match */
927 count = 1;
928 break;
929 }
930 count++;
931 }
932 }
933
934 if (count > 1) {
935 printf("Ambiguous command '%s'; possible commands:", argv[0]);
936 for (cmd = wlantest_cli_commands; cmd->cmd; cmd++) {
937 if (os_strncasecmp(cmd->cmd, argv[0],
938 os_strlen(argv[0])) == 0) {
939 printf(" %s", cmd->cmd);
940 }
644fb8c8
JM
941 }
942 printf("\n");
943 ret = 1;
944 } else if (count == 0) {
945 printf("Unknown command '%s'\n", argv[0]);
946 ret = 1;
947 } else {
948 ret = match->handler(s, argc - 1, &argv[1]);
949 }
950
951 return ret;
952}
953
954
ef49bb80
JM
955struct wlantest_cli {
956 int s;
957};
958
959
960#define max_args 10
961
962static int tokenize_cmd(char *cmd, char *argv[])
963{
964 char *pos;
965 int argc = 0;
966
967 pos = cmd;
968 for (;;) {
969 while (*pos == ' ')
970 pos++;
971 if (*pos == '\0')
972 break;
973 argv[argc] = pos;
974 argc++;
975 if (argc == max_args)
976 break;
977 if (*pos == '"') {
978 char *pos2 = os_strrchr(pos, '"');
979 if (pos2)
980 pos = pos2 + 1;
981 }
982 while (*pos != '\0' && *pos != ' ')
983 pos++;
984 if (*pos == ' ')
985 *pos++ = '\0';
986 }
987
988 return argc;
989}
990
991
992static void wlantest_cli_edit_cmd_cb(void *ctx, char *cmd)
993{
994 struct wlantest_cli *cli = ctx;
995 char *argv[max_args];
996 int argc;
997 argc = tokenize_cmd(cmd, argv);
998 if (argc) {
999 int ret = ctrl_command(cli->s, argc, argv);
1000 if (ret < 0)
1001 printf("FAIL\n");
1002 }
1003}
1004
1005
1006static void wlantest_cli_eloop_terminate(int sig, void *signal_ctx)
1007{
1008 eloop_terminate();
1009}
1010
1011
1012static void wlantest_cli_edit_eof_cb(void *ctx)
1013{
1014 eloop_terminate();
1015}
1016
1017
1018static char ** wlantest_cli_cmd_list(void)
1019{
1020 char **res;
1021 int i, count;
1022
1023 count = sizeof(wlantest_cli_commands) /
1024 sizeof(wlantest_cli_commands[0]);
1025 res = os_zalloc(count * sizeof(char *));
1026 if (res == NULL)
1027 return NULL;
1028
1029 for (i = 0; wlantest_cli_commands[i].cmd; i++) {
1030 res[i] = os_strdup(wlantest_cli_commands[i].cmd);
1031 if (res[i] == NULL)
1032 break;
1033 }
1034
1035 return res;
1036}
1037
1038
79a670cb
JM
1039static char ** wlantest_cli_cmd_completion(struct wlantest_cli *cli,
1040 const char *cmd, const char *str,
ef49bb80
JM
1041 int pos)
1042{
1043 int i;
1044
1045 for (i = 0; wlantest_cli_commands[i].cmd; i++) {
79a670cb
JM
1046 const struct wlantest_cli_cmd *c = &wlantest_cli_commands[i];
1047 if (os_strcasecmp(c->cmd, cmd) == 0) {
ef49bb80 1048 edit_clear_line();
79a670cb 1049 printf("\r%s\n", c->usage);
ef49bb80 1050 edit_redraw();
79a670cb
JM
1051 if (c->complete)
1052 return c->complete(cli->s, str, pos);
ef49bb80
JM
1053 break;
1054 }
1055 }
1056
1057 return NULL;
1058}
1059
1060
1061static char ** wlantest_cli_edit_completion_cb(void *ctx, const char *str,
1062 int pos)
1063{
79a670cb 1064 struct wlantest_cli *cli = ctx;
ef49bb80
JM
1065 char **res;
1066 const char *end;
1067 char *cmd;
1068
1069 end = os_strchr(str, ' ');
1070 if (end == NULL || str + pos < end)
1071 return wlantest_cli_cmd_list();
1072
1073 cmd = os_malloc(pos + 1);
1074 if (cmd == NULL)
1075 return NULL;
1076 os_memcpy(cmd, str, pos);
1077 cmd[end - str] = '\0';
79a670cb 1078 res = wlantest_cli_cmd_completion(cli, cmd, str, pos);
ef49bb80
JM
1079 os_free(cmd);
1080 return res;
1081}
1082
1083
1084static void wlantest_cli_interactive(int s)
1085{
1086 struct wlantest_cli cli;
1087
1088 if (eloop_init())
1089 return;
1090
1091 cli.s = s;
1092 eloop_register_signal_terminate(wlantest_cli_eloop_terminate, &cli);
1093 edit_init(wlantest_cli_edit_cmd_cb, wlantest_cli_edit_eof_cb, &cli);
1094 edit_set_completion_cb(wlantest_cli_edit_completion_cb);
1095
1096 eloop_run();
1097
1098 edit_deinit();
1099 eloop_destroy();
1100}
1101
1102
644fb8c8
JM
1103int main(int argc, char *argv[])
1104{
1105 int s;
1106 struct sockaddr_un addr;
1107 int ret = 0;
1108
ef49bb80
JM
1109 if (os_program_init())
1110 return -1;
1111
644fb8c8
JM
1112 s = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1113 if (s < 0) {
1114 perror("socket");
1115 return -1;
1116 }
1117
1118 os_memset(&addr, 0, sizeof(addr));
1119 addr.sun_family = AF_UNIX;
1120 os_strlcpy(addr.sun_path + 1, WLANTEST_SOCK_NAME,
1121 sizeof(addr.sun_path) - 1);
1122 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1123 perror("connect");
1124 close(s);
1125 return -1;
1126 }
1127
1128 if (argc > 1) {
1129 ret = ctrl_command(s, argc - 1, &argv[1]);
1130 if (ret < 0)
1131 printf("FAIL\n");
1132 } else {
ef49bb80 1133 wlantest_cli_interactive(s);
644fb8c8
JM
1134 }
1135
1136 close(s);
ef49bb80
JM
1137
1138 os_program_deinit();
1139
644fb8c8
JM
1140 return ret;
1141}