]> git.ipfire.org Git - thirdparty/hostap.git/blame - wlantest/wlantest_cli.c
edit: Sort completion list
[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;
209 rlen = cmd_send_and_recv(s, buf, sizeof(buf), resp, sizeof(resp));
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 },
464 { NULL, 0 }
465};
466
467static int cmd_get_sta_counter(int s, int argc, char *argv[])
468{
469 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
470 u8 buf[100], *end, *pos;
471 int rlen, i;
472 size_t len;
473
474 if (argc != 3) {
475 printf("get_sta_counter needs at three arguments: "
476 "counter name, BSSID, and STA address\n");
477 return -1;
478 }
479
480 pos = buf;
481 end = buf + sizeof(buf);
482 WPA_PUT_BE32(pos, WLANTEST_CTRL_GET_STA_COUNTER);
483 pos += 4;
484
485 for (i = 0; sta_counters[i].name; i++) {
486 if (os_strcasecmp(sta_counters[i].name, argv[0]) == 0)
487 break;
488 }
489 if (sta_counters[i].name == NULL) {
490 printf("Unknown STA counter '%s'\n", argv[0]);
491 printf("Counters:");
492 for (i = 0; sta_counters[i].name; i++)
493 printf(" %s", sta_counters[i].name);
494 printf("\n");
495 return -1;
496 }
497
498 pos = attr_add_be32(pos, end, WLANTEST_ATTR_STA_COUNTER,
499 sta_counters[i].num);
500 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
501 if (hwaddr_aton(argv[1], pos) < 0) {
502 printf("Invalid BSSID '%s'\n", argv[1]);
503 return -1;
504 }
505 pos += ETH_ALEN;
506
507 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA_ADDR, ETH_ALEN);
508 if (hwaddr_aton(argv[2], pos) < 0) {
509 printf("Invalid STA address '%s'\n", argv[2]);
510 return -1;
511 }
512 pos += ETH_ALEN;
513
514 rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
515 if (rlen < 0)
516 return -1;
517
518 pos = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_COUNTER, &len);
519 if (pos == NULL || len != 4)
520 return -1;
521 printf("%u\n", WPA_GET_BE32(pos));
522 return 0;
523}
524
525
79a670cb
JM
526static char ** complete_get_sta_counter(int s, const char *str, int pos)
527{
528 int arg = get_cmd_arg_num(str, pos);
529 char **res = NULL;
530 int i, count;
531 u8 addr[ETH_ALEN];
532
533 switch (arg) {
534 case 1:
535 /* counter list */
536 count = sizeof(sta_counters) / sizeof(sta_counters[0]);
537 res = os_zalloc(count * sizeof(char *));
538 if (res == NULL)
539 return NULL;
540 for (i = 0; sta_counters[i].name; i++) {
541 res[i] = os_strdup(sta_counters[i].name);
542 if (res[i] == NULL)
543 break;
544 }
545 break;
546 case 2:
547 res = get_bssid_list(s);
548 break;
549 case 3:
550 if (hwaddr_aton(&str[get_prev_arg_pos(str, pos)], addr) < 0)
551 break;
552 res = get_sta_list(s, addr, 0);
553 break;
554 }
555
556 return res;
557}
558
559
6d5ce9fc
JM
560struct bss_counters {
561 const char *name;
562 enum wlantest_bss_counter num;
563};
564
565static const struct bss_counters bss_counters[] = {
566 { "valid_bip_mmie", WLANTEST_BSS_COUNTER_VALID_BIP_MMIE },
567 { "invalid_bip_mmie", WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE },
568 { "missing_bip_mmie", WLANTEST_BSS_COUNTER_MISSING_BIP_MMIE },
569 { NULL, 0 }
570};
571
572static int cmd_get_bss_counter(int s, int argc, char *argv[])
573{
574 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
575 u8 buf[100], *end, *pos;
576 int rlen, i;
577 size_t len;
578
579 if (argc != 2) {
580 printf("get_bss_counter needs at three arguments: "
581 "counter name and BSSID\n");
582 return -1;
583 }
584
585 pos = buf;
586 end = buf + sizeof(buf);
587 WPA_PUT_BE32(pos, WLANTEST_CTRL_GET_BSS_COUNTER);
588 pos += 4;
589
590 for (i = 0; bss_counters[i].name; i++) {
591 if (os_strcasecmp(bss_counters[i].name, argv[0]) == 0)
592 break;
593 }
594 if (bss_counters[i].name == NULL) {
595 printf("Unknown BSS counter '%s'\n", argv[0]);
596 printf("Counters:");
597 for (i = 0; bss_counters[i].name; i++)
598 printf(" %s", bss_counters[i].name);
599 printf("\n");
600 return -1;
601 }
602
603 pos = attr_add_be32(pos, end, WLANTEST_ATTR_BSS_COUNTER,
604 bss_counters[i].num);
605 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
606 if (hwaddr_aton(argv[1], pos) < 0) {
607 printf("Invalid BSSID '%s'\n", argv[1]);
608 return -1;
609 }
610 pos += ETH_ALEN;
611
612 rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
613 if (rlen < 0)
614 return -1;
615
616 pos = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_COUNTER, &len);
617 if (pos == NULL || len != 4)
618 return -1;
619 printf("%u\n", WPA_GET_BE32(pos));
620 return 0;
621}
622
623
79a670cb
JM
624static char ** complete_get_bss_counter(int s, const char *str, int pos)
625{
626 int arg = get_cmd_arg_num(str, pos);
627 char **res = NULL;
628 int i, count;
629
630 switch (arg) {
631 case 1:
632 /* counter list */
633 count = sizeof(bss_counters) / sizeof(bss_counters[0]);
634 res = os_zalloc(count * sizeof(char *));
635 if (res == NULL)
636 return NULL;
637 for (i = 0; bss_counters[i].name; i++) {
638 res[i] = os_strdup(bss_counters[i].name);
639 if (res[i] == NULL)
640 break;
641 }
642 break;
643 case 2:
644 res = get_bssid_list(s);
645 break;
646 }
647
648 return res;
649}
650
651
7d23e971
JM
652struct inject_frames {
653 const char *name;
654 enum wlantest_inject_frame frame;
655};
656
657static const struct inject_frames inject_frames[] = {
658 { "auth", WLANTEST_FRAME_AUTH },
659 { "assocreq", WLANTEST_FRAME_ASSOCREQ },
660 { "reassocreq", WLANTEST_FRAME_REASSOCREQ },
661 { "deauth", WLANTEST_FRAME_DEAUTH },
662 { "disassoc", WLANTEST_FRAME_DISASSOC },
663 { "saqueryreq", WLANTEST_FRAME_SAQUERYREQ },
664 { NULL, 0 }
665};
666
667static int cmd_inject(int s, int argc, char *argv[])
668{
669 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
670 u8 buf[100], *end, *pos;
671 int rlen, i;
672 enum wlantest_inject_protection prot;
673
674 /* <frame> <prot> <sender> <BSSID> <STA/ff:ff:ff:ff:ff:ff> */
675
676 if (argc < 5) {
677 printf("inject needs five arguments: frame, protection, "
678 "sender, BSSID, STA/ff:ff:ff:ff:ff:ff\n");
679 return -1;
680 }
681
682 pos = buf;
683 end = buf + sizeof(buf);
684 WPA_PUT_BE32(pos, WLANTEST_CTRL_INJECT);
685 pos += 4;
686
687 for (i = 0; inject_frames[i].name; i++) {
688 if (os_strcasecmp(inject_frames[i].name, argv[0]) == 0)
689 break;
690 }
691 if (inject_frames[i].name == NULL) {
692 printf("Unknown inject frame '%s'\n", argv[0]);
693 printf("Frames:");
694 for (i = 0; inject_frames[i].name; i++)
695 printf(" %s", inject_frames[i].name);
696 printf("\n");
697 return -1;
698 }
699
700 pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_FRAME,
701 inject_frames[i].frame);
702
703 if (os_strcasecmp(argv[1], "normal") == 0)
704 prot = WLANTEST_INJECT_NORMAL;
705 else if (os_strcasecmp(argv[1], "protected") == 0)
706 prot = WLANTEST_INJECT_PROTECTED;
707 else if (os_strcasecmp(argv[1], "unprotected") == 0)
708 prot = WLANTEST_INJECT_UNPROTECTED;
709 else if (os_strcasecmp(argv[1], "incorrect") == 0)
710 prot = WLANTEST_INJECT_INCORRECT_KEY;
711 else {
712 printf("Unknown protection type '%s'\n", argv[1]);
713 printf("Protection types: normal protected unprotected "
714 "incorrect\n");
715 return -1;
716 }
717 pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_PROTECTION, prot);
718
719 if (os_strcasecmp(argv[2], "ap") == 0) {
720 pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_SENDER_AP,
721 1);
722 } else if (os_strcasecmp(argv[2], "sta") == 0) {
723 pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_SENDER_AP,
724 0);
725 } else {
726 printf("Unknown sender '%s'\n", argv[2]);
727 printf("Sender types: ap sta\n");
728 return -1;
729 }
730
731 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
732 if (hwaddr_aton(argv[3], pos) < 0) {
733 printf("Invalid BSSID '%s'\n", argv[3]);
734 return -1;
735 }
736 pos += ETH_ALEN;
737
738 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA_ADDR, ETH_ALEN);
739 if (hwaddr_aton(argv[4], pos) < 0) {
740 printf("Invalid STA '%s'\n", argv[4]);
741 return -1;
742 }
743 pos += ETH_ALEN;
744
745 rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
746 if (rlen < 0)
747 return -1;
748 printf("OK\n");
749 return 0;
750}
751
752
79a670cb
JM
753static char ** complete_inject(int s, const char *str, int pos)
754{
755 int arg = get_cmd_arg_num(str, pos);
756 char **res = NULL;
757 int i, count;
758 u8 addr[ETH_ALEN];
759
760 switch (arg) {
761 case 1:
762 /* frame list */
763 count = sizeof(inject_frames) / sizeof(inject_frames[0]);
764 res = os_zalloc(count * sizeof(char *));
765 if (res == NULL)
766 break;
767 for (i = 0; inject_frames[i].name; i++) {
768 res[i] = os_strdup(inject_frames[i].name);
769 if (res[i] == NULL)
770 break;
771 }
772 break;
773 case 2:
774 res = os_zalloc(5 * sizeof(char *));
775 if (res == NULL)
776 break;
777 res[0] = os_strdup("normal");
778 if (res[0] == NULL)
779 break;
780 res[1] = os_strdup("protected");
781 if (res[1] == NULL)
782 break;
783 res[2] = os_strdup("unprotected");
784 if (res[2] == NULL)
785 break;
786 res[3] = os_strdup("incorrect");
787 if (res[3] == NULL)
788 break;
789 break;
790 case 3:
791 res = os_zalloc(3 * sizeof(char *));
792 if (res == NULL)
793 break;
794 res[0] = os_strdup("ap");
795 if (res[0] == NULL)
796 break;
797 res[1] = os_strdup("sta");
798 if (res[1] == NULL)
799 break;
800 break;
801 case 4:
802 res = get_bssid_list(s);
803 break;
804 case 5:
805 if (hwaddr_aton(&str[get_prev_arg_pos(str, pos)], addr) < 0)
806 break;
807 res = get_sta_list(s, addr, 1);
808 break;
809 }
810
811 return res;
812}
813
814
a16c8590
JM
815static int cmd_version(int s, int argc, char *argv[])
816{
817 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
818 u8 buf[4];
819 char *version;
820 size_t len;
821 int rlen, i;
822
823 WPA_PUT_BE32(buf, WLANTEST_CTRL_VERSION);
824 rlen = cmd_send_and_recv(s, buf, sizeof(buf), resp, sizeof(resp));
825 if (rlen < 0)
826 return -1;
827
828 version = (char *) attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_VERSION,
829 &len);
830 if (version == NULL)
831 return -1;
832
833 for (i = 0; i < len; i++)
834 putchar(version[i]);
835 printf("\n");
836
837 return 0;
838}
839
840
fbdd2132
JM
841static int cmd_add_passphrase(int s, int argc, char *argv[])
842{
843 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
844 u8 buf[100], *pos, *end;
845 size_t len;
846 int rlen;
847
848 if (argc < 1) {
849 printf("add_passphrase needs one argument: passphrase\n");
850 return -1;
851 }
852
853 len = os_strlen(argv[0]);
854 if (len < 8 || len > 63) {
855 printf("Invalid passphrase '%s'\n", argv[0]);
856 return -1;
857 }
858 pos = buf;
859 end = buf + sizeof(buf);
860 WPA_PUT_BE32(pos, WLANTEST_CTRL_ADD_PASSPHRASE);
861 pos += 4;
862 pos = attr_add_str(pos, end, WLANTEST_ATTR_PASSPHRASE,
863 argv[0]);
864 if (argc > 1) {
865 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
866 if (hwaddr_aton(argv[1], pos) < 0) {
867 printf("Invalid BSSID '%s'\n", argv[3]);
868 return -1;
869 }
870 pos += ETH_ALEN;
871 }
872
873 rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
874 if (rlen < 0)
875 return -1;
876 return 0;
877}
878
879
644fb8c8
JM
880struct wlantest_cli_cmd {
881 const char *cmd;
882 int (*handler)(int s, int argc, char *argv[]);
883 const char *usage;
79a670cb 884 char ** (*complete)(int s, const char *str, int pos);
644fb8c8
JM
885};
886
887static const struct wlantest_cli_cmd wlantest_cli_commands[] = {
79a670cb
JM
888 { "ping", cmd_ping, "= test connection to wlantest", NULL },
889 { "terminate", cmd_terminate, "= terminate wlantest", NULL },
890 { "list_bss", cmd_list_bss, "= get BSS list", NULL },
891 { "list_sta", cmd_list_sta, "<BSSID> = get STA list",
892 complete_list_sta },
893 { "flush", cmd_flush, "= drop all collected BSS data", NULL },
6d5ce9fc 894 { "clear_sta_counters", cmd_clear_sta_counters,
79a670cb 895 "<BSSID> <STA> = clear STA counters", complete_clear_sta_counters },
6d5ce9fc 896 { "clear_bss_counters", cmd_clear_bss_counters,
79a670cb 897 "<BSSID> = clear BSS counters", complete_clear_bss_counters },
6d5ce9fc 898 { "get_sta_counter", cmd_get_sta_counter,
79a670cb
JM
899 "<counter> <BSSID> <STA> = get STA counter value",
900 complete_get_sta_counter},
6d5ce9fc 901 { "get_bss_counter", cmd_get_bss_counter,
79a670cb
JM
902 "<counter> <BSSID> = get BSS counter value",
903 complete_get_bss_counter },
7d23e971 904 { "inject", cmd_inject,
79a670cb
JM
905 "<frame> <prot> <sender> <BSSID> <STA/ff:ff:ff:ff:ff:ff>",
906 complete_inject },
907 { "version", cmd_version, "= get wlantest version", NULL },
fbdd2132 908 { "add_passphrase", cmd_add_passphrase,
79a670cb
JM
909 "<passphrase> = add a known passphrase", NULL },
910 { NULL, NULL, NULL, NULL }
644fb8c8
JM
911};
912
913
914static int ctrl_command(int s, int argc, char *argv[])
915{
916 const struct wlantest_cli_cmd *cmd, *match = NULL;
917 int count = 0;
918 int ret = 0;
919
920 for (cmd = wlantest_cli_commands; cmd->cmd; cmd++) {
921 if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0)
922 {
923 match = cmd;
924 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
925 /* exact match */
926 count = 1;
927 break;
928 }
929 count++;
930 }
931 }
932
933 if (count > 1) {
934 printf("Ambiguous command '%s'; possible commands:", argv[0]);
935 for (cmd = wlantest_cli_commands; cmd->cmd; cmd++) {
936 if (os_strncasecmp(cmd->cmd, argv[0],
937 os_strlen(argv[0])) == 0) {
938 printf(" %s", cmd->cmd);
939 }
644fb8c8
JM
940 }
941 printf("\n");
942 ret = 1;
943 } else if (count == 0) {
944 printf("Unknown command '%s'\n", argv[0]);
945 ret = 1;
946 } else {
947 ret = match->handler(s, argc - 1, &argv[1]);
948 }
949
950 return ret;
951}
952
953
ef49bb80
JM
954struct wlantest_cli {
955 int s;
956};
957
958
959#define max_args 10
960
961static int tokenize_cmd(char *cmd, char *argv[])
962{
963 char *pos;
964 int argc = 0;
965
966 pos = cmd;
967 for (;;) {
968 while (*pos == ' ')
969 pos++;
970 if (*pos == '\0')
971 break;
972 argv[argc] = pos;
973 argc++;
974 if (argc == max_args)
975 break;
976 if (*pos == '"') {
977 char *pos2 = os_strrchr(pos, '"');
978 if (pos2)
979 pos = pos2 + 1;
980 }
981 while (*pos != '\0' && *pos != ' ')
982 pos++;
983 if (*pos == ' ')
984 *pos++ = '\0';
985 }
986
987 return argc;
988}
989
990
991static void wlantest_cli_edit_cmd_cb(void *ctx, char *cmd)
992{
993 struct wlantest_cli *cli = ctx;
994 char *argv[max_args];
995 int argc;
996 argc = tokenize_cmd(cmd, argv);
997 if (argc) {
998 int ret = ctrl_command(cli->s, argc, argv);
999 if (ret < 0)
1000 printf("FAIL\n");
1001 }
1002}
1003
1004
1005static void wlantest_cli_eloop_terminate(int sig, void *signal_ctx)
1006{
1007 eloop_terminate();
1008}
1009
1010
1011static void wlantest_cli_edit_eof_cb(void *ctx)
1012{
1013 eloop_terminate();
1014}
1015
1016
1017static char ** wlantest_cli_cmd_list(void)
1018{
1019 char **res;
1020 int i, count;
1021
1022 count = sizeof(wlantest_cli_commands) /
1023 sizeof(wlantest_cli_commands[0]);
1024 res = os_zalloc(count * sizeof(char *));
1025 if (res == NULL)
1026 return NULL;
1027
1028 for (i = 0; wlantest_cli_commands[i].cmd; i++) {
1029 res[i] = os_strdup(wlantest_cli_commands[i].cmd);
1030 if (res[i] == NULL)
1031 break;
1032 }
1033
1034 return res;
1035}
1036
1037
79a670cb
JM
1038static char ** wlantest_cli_cmd_completion(struct wlantest_cli *cli,
1039 const char *cmd, const char *str,
ef49bb80
JM
1040 int pos)
1041{
1042 int i;
1043
1044 for (i = 0; wlantest_cli_commands[i].cmd; i++) {
79a670cb
JM
1045 const struct wlantest_cli_cmd *c = &wlantest_cli_commands[i];
1046 if (os_strcasecmp(c->cmd, cmd) == 0) {
ef49bb80 1047 edit_clear_line();
79a670cb 1048 printf("\r%s\n", c->usage);
ef49bb80 1049 edit_redraw();
79a670cb
JM
1050 if (c->complete)
1051 return c->complete(cli->s, str, pos);
ef49bb80
JM
1052 break;
1053 }
1054 }
1055
1056 return NULL;
1057}
1058
1059
1060static char ** wlantest_cli_edit_completion_cb(void *ctx, const char *str,
1061 int pos)
1062{
79a670cb 1063 struct wlantest_cli *cli = ctx;
ef49bb80
JM
1064 char **res;
1065 const char *end;
1066 char *cmd;
1067
1068 end = os_strchr(str, ' ');
1069 if (end == NULL || str + pos < end)
1070 return wlantest_cli_cmd_list();
1071
1072 cmd = os_malloc(pos + 1);
1073 if (cmd == NULL)
1074 return NULL;
1075 os_memcpy(cmd, str, pos);
1076 cmd[end - str] = '\0';
79a670cb 1077 res = wlantest_cli_cmd_completion(cli, cmd, str, pos);
ef49bb80
JM
1078 os_free(cmd);
1079 return res;
1080}
1081
1082
1083static void wlantest_cli_interactive(int s)
1084{
1085 struct wlantest_cli cli;
1086
1087 if (eloop_init())
1088 return;
1089
1090 cli.s = s;
1091 eloop_register_signal_terminate(wlantest_cli_eloop_terminate, &cli);
1092 edit_init(wlantest_cli_edit_cmd_cb, wlantest_cli_edit_eof_cb, &cli);
1093 edit_set_completion_cb(wlantest_cli_edit_completion_cb);
1094
1095 eloop_run();
1096
1097 edit_deinit();
1098 eloop_destroy();
1099}
1100
1101
644fb8c8
JM
1102int main(int argc, char *argv[])
1103{
1104 int s;
1105 struct sockaddr_un addr;
1106 int ret = 0;
1107
ef49bb80
JM
1108 if (os_program_init())
1109 return -1;
1110
644fb8c8
JM
1111 s = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1112 if (s < 0) {
1113 perror("socket");
1114 return -1;
1115 }
1116
1117 os_memset(&addr, 0, sizeof(addr));
1118 addr.sun_family = AF_UNIX;
1119 os_strlcpy(addr.sun_path + 1, WLANTEST_SOCK_NAME,
1120 sizeof(addr.sun_path) - 1);
1121 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1122 perror("connect");
1123 close(s);
1124 return -1;
1125 }
1126
1127 if (argc > 1) {
1128 ret = ctrl_command(s, argc - 1, &argv[1]);
1129 if (ret < 0)
1130 printf("FAIL\n");
1131 } else {
ef49bb80 1132 wlantest_cli_interactive(s);
644fb8c8
JM
1133 }
1134
1135 close(s);
ef49bb80
JM
1136
1137 os_program_deinit();
1138
644fb8c8
JM
1139 return ret;
1140}