]> git.ipfire.org Git - thirdparty/hostap.git/blame - wlantest/wlantest_cli.c
wlantest: Add ping_ok_first_assoc STA counter
[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
0e42fff3
JM
433static int cmd_clear_tdls_counters(int s, int argc, char *argv[])
434{
435 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
436 u8 buf[100], *pos;
437 int rlen;
438
439 if (argc < 3) {
440 printf("clear_tdls_counters needs three arguments: BSSID, "
441 "STA1 address, STA2 address\n");
442 return -1;
443 }
444
445 pos = buf;
446 WPA_PUT_BE32(pos, WLANTEST_CTRL_CLEAR_TDLS_COUNTERS);
447 pos += 4;
448 WPA_PUT_BE32(pos, WLANTEST_ATTR_BSSID);
449 pos += 4;
450 WPA_PUT_BE32(pos, ETH_ALEN);
451 pos += 4;
452 if (hwaddr_aton(argv[0], pos) < 0) {
453 printf("Invalid BSSID '%s'\n", argv[0]);
454 return -1;
455 }
456 pos += ETH_ALEN;
457
458 WPA_PUT_BE32(pos, WLANTEST_ATTR_STA_ADDR);
459 pos += 4;
460 WPA_PUT_BE32(pos, ETH_ALEN);
461 pos += 4;
462 if (hwaddr_aton(argv[1], pos) < 0) {
463 printf("Invalid STA1 address '%s'\n", argv[1]);
464 return -1;
465 }
466 pos += ETH_ALEN;
467
468 WPA_PUT_BE32(pos, WLANTEST_ATTR_STA2_ADDR);
469 pos += 4;
470 WPA_PUT_BE32(pos, ETH_ALEN);
471 pos += 4;
472 if (hwaddr_aton(argv[2], pos) < 0) {
473 printf("Invalid STA2 address '%s'\n", argv[2]);
474 return -1;
475 }
476 pos += ETH_ALEN;
477
478 rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
479 if (rlen < 0)
480 return -1;
481 printf("OK\n");
482 return 0;
483}
484
485
486static char ** complete_clear_tdls_counters(int s, const char *str, int pos)
487{
488 int arg = get_cmd_arg_num(str, pos);
489 char **res = NULL;
490 u8 addr[ETH_ALEN];
491
492 switch (arg) {
493 case 1:
494 res = get_bssid_list(s);
495 break;
496 case 2:
497 case 3:
498 if (hwaddr_aton(&str[get_prev_arg_pos(str, pos)], addr) < 0)
499 break;
500 res = get_sta_list(s, addr, 0);
501 break;
502 }
503
504 return res;
505}
506
507
6d5ce9fc
JM
508struct sta_counters {
509 const char *name;
510 enum wlantest_sta_counter num;
511};
512
513static const struct sta_counters sta_counters[] = {
514 { "auth_tx", WLANTEST_STA_COUNTER_AUTH_TX },
515 { "auth_rx", WLANTEST_STA_COUNTER_AUTH_RX },
516 { "assocreq_tx", WLANTEST_STA_COUNTER_ASSOCREQ_TX },
517 { "reassocreq_tx", WLANTEST_STA_COUNTER_REASSOCREQ_TX },
518 { "ptk_learned", WLANTEST_STA_COUNTER_PTK_LEARNED },
519 { "valid_deauth_tx", WLANTEST_STA_COUNTER_VALID_DEAUTH_TX },
520 { "valid_deauth_rx", WLANTEST_STA_COUNTER_VALID_DEAUTH_RX },
521 { "invalid_deauth_tx", WLANTEST_STA_COUNTER_INVALID_DEAUTH_TX },
522 { "invalid_deauth_rx", WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX },
523 { "valid_disassoc_tx", WLANTEST_STA_COUNTER_VALID_DISASSOC_TX },
524 { "valid_disassoc_rx", WLANTEST_STA_COUNTER_VALID_DISASSOC_RX },
525 { "invalid_disassoc_tx", WLANTEST_STA_COUNTER_INVALID_DISASSOC_TX },
526 { "invalid_disassoc_rx", WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX },
527 { "valid_saqueryreq_tx", WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_TX },
528 { "valid_saqueryreq_rx", WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_RX },
529 { "invalid_saqueryreq_tx",
530 WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_TX },
531 { "invalid_saqueryreq_rx",
532 WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_RX },
533 { "valid_saqueryresp_tx", WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_TX },
534 { "valid_saqueryresp_rx", WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_RX },
535 { "invalid_saqueryresp_tx",
536 WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_TX },
537 { "invalid_saqueryresp_rx",
538 WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_RX },
ee3b84be 539 { "ping_ok", WLANTEST_STA_COUNTER_PING_OK },
cdd71e30
JM
540 { "assocresp_comeback", WLANTEST_STA_COUNTER_ASSOCRESP_COMEBACK },
541 { "reassocresp_comeback", WLANTEST_STA_COUNTER_REASSOCRESP_COMEBACK },
1da4da6f 542 { "ping_ok_first_assoc", WLANTEST_STA_COUNTER_PING_OK_FIRST_ASSOC },
6d5ce9fc
JM
543 { NULL, 0 }
544};
545
546static int cmd_get_sta_counter(int s, int argc, char *argv[])
547{
548 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
549 u8 buf[100], *end, *pos;
550 int rlen, i;
551 size_t len;
552
553 if (argc != 3) {
554 printf("get_sta_counter needs at three arguments: "
555 "counter name, BSSID, and STA address\n");
556 return -1;
557 }
558
559 pos = buf;
560 end = buf + sizeof(buf);
561 WPA_PUT_BE32(pos, WLANTEST_CTRL_GET_STA_COUNTER);
562 pos += 4;
563
564 for (i = 0; sta_counters[i].name; i++) {
565 if (os_strcasecmp(sta_counters[i].name, argv[0]) == 0)
566 break;
567 }
568 if (sta_counters[i].name == NULL) {
569 printf("Unknown STA counter '%s'\n", argv[0]);
570 printf("Counters:");
571 for (i = 0; sta_counters[i].name; i++)
572 printf(" %s", sta_counters[i].name);
573 printf("\n");
574 return -1;
575 }
576
577 pos = attr_add_be32(pos, end, WLANTEST_ATTR_STA_COUNTER,
578 sta_counters[i].num);
579 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
580 if (hwaddr_aton(argv[1], pos) < 0) {
581 printf("Invalid BSSID '%s'\n", argv[1]);
582 return -1;
583 }
584 pos += ETH_ALEN;
585
586 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA_ADDR, ETH_ALEN);
587 if (hwaddr_aton(argv[2], pos) < 0) {
588 printf("Invalid STA address '%s'\n", argv[2]);
589 return -1;
590 }
591 pos += ETH_ALEN;
592
593 rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
594 if (rlen < 0)
595 return -1;
596
597 pos = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_COUNTER, &len);
598 if (pos == NULL || len != 4)
599 return -1;
600 printf("%u\n", WPA_GET_BE32(pos));
601 return 0;
602}
603
604
79a670cb
JM
605static char ** complete_get_sta_counter(int s, const char *str, int pos)
606{
607 int arg = get_cmd_arg_num(str, pos);
608 char **res = NULL;
609 int i, count;
610 u8 addr[ETH_ALEN];
611
612 switch (arg) {
613 case 1:
614 /* counter list */
615 count = sizeof(sta_counters) / sizeof(sta_counters[0]);
616 res = os_zalloc(count * sizeof(char *));
617 if (res == NULL)
618 return NULL;
619 for (i = 0; sta_counters[i].name; i++) {
620 res[i] = os_strdup(sta_counters[i].name);
621 if (res[i] == NULL)
622 break;
623 }
624 break;
625 case 2:
626 res = get_bssid_list(s);
627 break;
628 case 3:
629 if (hwaddr_aton(&str[get_prev_arg_pos(str, pos)], addr) < 0)
630 break;
631 res = get_sta_list(s, addr, 0);
632 break;
633 }
634
635 return res;
636}
637
638
6d5ce9fc
JM
639struct bss_counters {
640 const char *name;
641 enum wlantest_bss_counter num;
642};
643
644static const struct bss_counters bss_counters[] = {
645 { "valid_bip_mmie", WLANTEST_BSS_COUNTER_VALID_BIP_MMIE },
646 { "invalid_bip_mmie", WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE },
647 { "missing_bip_mmie", WLANTEST_BSS_COUNTER_MISSING_BIP_MMIE },
783a082c
JM
648 { "bip_deauth", WLANTEST_BSS_COUNTER_BIP_DEAUTH },
649 { "bip_disassoc", WLANTEST_BSS_COUNTER_BIP_DISASSOC },
6d5ce9fc
JM
650 { NULL, 0 }
651};
652
653static int cmd_get_bss_counter(int s, int argc, char *argv[])
654{
655 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
656 u8 buf[100], *end, *pos;
657 int rlen, i;
658 size_t len;
659
660 if (argc != 2) {
2fc0cd54 661 printf("get_bss_counter needs at two arguments: "
6d5ce9fc
JM
662 "counter name and BSSID\n");
663 return -1;
664 }
665
666 pos = buf;
667 end = buf + sizeof(buf);
668 WPA_PUT_BE32(pos, WLANTEST_CTRL_GET_BSS_COUNTER);
669 pos += 4;
670
671 for (i = 0; bss_counters[i].name; i++) {
672 if (os_strcasecmp(bss_counters[i].name, argv[0]) == 0)
673 break;
674 }
675 if (bss_counters[i].name == NULL) {
676 printf("Unknown BSS counter '%s'\n", argv[0]);
677 printf("Counters:");
678 for (i = 0; bss_counters[i].name; i++)
679 printf(" %s", bss_counters[i].name);
680 printf("\n");
681 return -1;
682 }
683
684 pos = attr_add_be32(pos, end, WLANTEST_ATTR_BSS_COUNTER,
685 bss_counters[i].num);
686 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
687 if (hwaddr_aton(argv[1], pos) < 0) {
688 printf("Invalid BSSID '%s'\n", argv[1]);
689 return -1;
690 }
691 pos += ETH_ALEN;
692
693 rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
694 if (rlen < 0)
695 return -1;
696
697 pos = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_COUNTER, &len);
698 if (pos == NULL || len != 4)
699 return -1;
700 printf("%u\n", WPA_GET_BE32(pos));
701 return 0;
702}
703
704
79a670cb
JM
705static char ** complete_get_bss_counter(int s, const char *str, int pos)
706{
707 int arg = get_cmd_arg_num(str, pos);
708 char **res = NULL;
709 int i, count;
710
711 switch (arg) {
712 case 1:
713 /* counter list */
714 count = sizeof(bss_counters) / sizeof(bss_counters[0]);
715 res = os_zalloc(count * sizeof(char *));
716 if (res == NULL)
717 return NULL;
718 for (i = 0; bss_counters[i].name; i++) {
719 res[i] = os_strdup(bss_counters[i].name);
720 if (res[i] == NULL)
721 break;
722 }
723 break;
724 case 2:
725 res = get_bssid_list(s);
726 break;
727 }
728
729 return res;
730}
731
732
0e42fff3
JM
733struct tdls_counters {
734 const char *name;
735 enum wlantest_tdls_counter num;
736};
737
738static const struct tdls_counters tdls_counters[] = {
739 { "valid_direct_link", WLANTEST_TDLS_COUNTER_VALID_DIRECT_LINK },
740 { "invalid_direct_link", WLANTEST_TDLS_COUNTER_INVALID_DIRECT_LINK },
741 { "valid_ap_path", WLANTEST_TDLS_COUNTER_VALID_AP_PATH },
742 { "invalid_ap_path", WLANTEST_TDLS_COUNTER_INVALID_AP_PATH },
743 { NULL, 0 }
744};
745
746static int cmd_get_tdls_counter(int s, int argc, char *argv[])
747{
748 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
749 u8 buf[100], *end, *pos;
750 int rlen, i;
751 size_t len;
752
753 if (argc != 4) {
754 printf("get_tdls_counter needs four arguments: "
755 "counter name, BSSID, STA1 address, STA2 address\n");
756 return -1;
757 }
758
759 pos = buf;
760 end = buf + sizeof(buf);
761 WPA_PUT_BE32(pos, WLANTEST_CTRL_GET_TDLS_COUNTER);
762 pos += 4;
763
764 for (i = 0; tdls_counters[i].name; i++) {
765 if (os_strcasecmp(tdls_counters[i].name, argv[0]) == 0)
766 break;
767 }
768 if (tdls_counters[i].name == NULL) {
769 printf("Unknown TDLS counter '%s'\n", argv[0]);
770 printf("Counters:");
771 for (i = 0; tdls_counters[i].name; i++)
772 printf(" %s", tdls_counters[i].name);
773 printf("\n");
774 return -1;
775 }
776
777 pos = attr_add_be32(pos, end, WLANTEST_ATTR_TDLS_COUNTER,
778 tdls_counters[i].num);
779 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
780 if (hwaddr_aton(argv[1], pos) < 0) {
781 printf("Invalid BSSID '%s'\n", argv[1]);
782 return -1;
783 }
784 pos += ETH_ALEN;
785
786 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA_ADDR, ETH_ALEN);
787 if (hwaddr_aton(argv[2], pos) < 0) {
788 printf("Invalid STA1 address '%s'\n", argv[2]);
789 return -1;
790 }
791 pos += ETH_ALEN;
792
793 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA2_ADDR, ETH_ALEN);
794 if (hwaddr_aton(argv[3], pos) < 0) {
795 printf("Invalid STA2 address '%s'\n", argv[3]);
796 return -1;
797 }
798 pos += ETH_ALEN;
799
800 rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
801 if (rlen < 0)
802 return -1;
803
804 pos = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_COUNTER, &len);
805 if (pos == NULL || len != 4)
806 return -1;
807 printf("%u\n", WPA_GET_BE32(pos));
808 return 0;
809}
810
811
812static char ** complete_get_tdls_counter(int s, const char *str, int pos)
813{
814 int arg = get_cmd_arg_num(str, pos);
815 char **res = NULL;
816 int i, count;
817 u8 addr[ETH_ALEN];
818
819 switch (arg) {
820 case 1:
821 /* counter list */
822 count = sizeof(tdls_counters) / sizeof(tdls_counters[0]);
823 res = os_zalloc(count * sizeof(char *));
824 if (res == NULL)
825 return NULL;
826 for (i = 0; tdls_counters[i].name; i++) {
827 res[i] = os_strdup(tdls_counters[i].name);
828 if (res[i] == NULL)
829 break;
830 }
831 break;
832 case 2:
833 res = get_bssid_list(s);
834 break;
835 case 3:
836 case 4:
837 if (hwaddr_aton(&str[get_prev_arg_pos(str, pos)], addr) < 0)
838 break;
839 res = get_sta_list(s, addr, 0);
840 break;
841 }
842
843 return res;
844}
845
846
7d23e971
JM
847struct inject_frames {
848 const char *name;
849 enum wlantest_inject_frame frame;
850};
851
852static const struct inject_frames inject_frames[] = {
853 { "auth", WLANTEST_FRAME_AUTH },
854 { "assocreq", WLANTEST_FRAME_ASSOCREQ },
855 { "reassocreq", WLANTEST_FRAME_REASSOCREQ },
856 { "deauth", WLANTEST_FRAME_DEAUTH },
857 { "disassoc", WLANTEST_FRAME_DISASSOC },
858 { "saqueryreq", WLANTEST_FRAME_SAQUERYREQ },
859 { NULL, 0 }
860};
861
862static int cmd_inject(int s, int argc, char *argv[])
863{
864 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
865 u8 buf[100], *end, *pos;
866 int rlen, i;
867 enum wlantest_inject_protection prot;
868
869 /* <frame> <prot> <sender> <BSSID> <STA/ff:ff:ff:ff:ff:ff> */
870
871 if (argc < 5) {
872 printf("inject needs five arguments: frame, protection, "
873 "sender, BSSID, STA/ff:ff:ff:ff:ff:ff\n");
874 return -1;
875 }
876
877 pos = buf;
878 end = buf + sizeof(buf);
879 WPA_PUT_BE32(pos, WLANTEST_CTRL_INJECT);
880 pos += 4;
881
882 for (i = 0; inject_frames[i].name; i++) {
883 if (os_strcasecmp(inject_frames[i].name, argv[0]) == 0)
884 break;
885 }
886 if (inject_frames[i].name == NULL) {
887 printf("Unknown inject frame '%s'\n", argv[0]);
888 printf("Frames:");
889 for (i = 0; inject_frames[i].name; i++)
890 printf(" %s", inject_frames[i].name);
891 printf("\n");
892 return -1;
893 }
894
895 pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_FRAME,
896 inject_frames[i].frame);
897
898 if (os_strcasecmp(argv[1], "normal") == 0)
899 prot = WLANTEST_INJECT_NORMAL;
900 else if (os_strcasecmp(argv[1], "protected") == 0)
901 prot = WLANTEST_INJECT_PROTECTED;
902 else if (os_strcasecmp(argv[1], "unprotected") == 0)
903 prot = WLANTEST_INJECT_UNPROTECTED;
904 else if (os_strcasecmp(argv[1], "incorrect") == 0)
905 prot = WLANTEST_INJECT_INCORRECT_KEY;
906 else {
907 printf("Unknown protection type '%s'\n", argv[1]);
908 printf("Protection types: normal protected unprotected "
909 "incorrect\n");
910 return -1;
911 }
912 pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_PROTECTION, prot);
913
914 if (os_strcasecmp(argv[2], "ap") == 0) {
915 pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_SENDER_AP,
916 1);
917 } else if (os_strcasecmp(argv[2], "sta") == 0) {
918 pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_SENDER_AP,
919 0);
920 } else {
921 printf("Unknown sender '%s'\n", argv[2]);
922 printf("Sender types: ap sta\n");
923 return -1;
924 }
925
926 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
927 if (hwaddr_aton(argv[3], pos) < 0) {
928 printf("Invalid BSSID '%s'\n", argv[3]);
929 return -1;
930 }
931 pos += ETH_ALEN;
932
933 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA_ADDR, ETH_ALEN);
934 if (hwaddr_aton(argv[4], pos) < 0) {
935 printf("Invalid STA '%s'\n", argv[4]);
936 return -1;
937 }
938 pos += ETH_ALEN;
939
940 rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
941 if (rlen < 0)
942 return -1;
943 printf("OK\n");
944 return 0;
945}
946
947
79a670cb
JM
948static char ** complete_inject(int s, const char *str, int pos)
949{
950 int arg = get_cmd_arg_num(str, pos);
951 char **res = NULL;
952 int i, count;
953 u8 addr[ETH_ALEN];
954
955 switch (arg) {
956 case 1:
957 /* frame list */
958 count = sizeof(inject_frames) / sizeof(inject_frames[0]);
959 res = os_zalloc(count * sizeof(char *));
960 if (res == NULL)
961 break;
962 for (i = 0; inject_frames[i].name; i++) {
963 res[i] = os_strdup(inject_frames[i].name);
964 if (res[i] == NULL)
965 break;
966 }
967 break;
968 case 2:
969 res = os_zalloc(5 * sizeof(char *));
970 if (res == NULL)
971 break;
972 res[0] = os_strdup("normal");
973 if (res[0] == NULL)
974 break;
975 res[1] = os_strdup("protected");
976 if (res[1] == NULL)
977 break;
978 res[2] = os_strdup("unprotected");
979 if (res[2] == NULL)
980 break;
981 res[3] = os_strdup("incorrect");
982 if (res[3] == NULL)
983 break;
984 break;
985 case 3:
986 res = os_zalloc(3 * sizeof(char *));
987 if (res == NULL)
988 break;
989 res[0] = os_strdup("ap");
990 if (res[0] == NULL)
991 break;
992 res[1] = os_strdup("sta");
993 if (res[1] == NULL)
994 break;
995 break;
996 case 4:
997 res = get_bssid_list(s);
998 break;
999 case 5:
1000 if (hwaddr_aton(&str[get_prev_arg_pos(str, pos)], addr) < 0)
1001 break;
1002 res = get_sta_list(s, addr, 1);
1003 break;
1004 }
1005
1006 return res;
1007}
1008
1009
b3a6d9d4
JM
1010static u8 * add_hex(u8 *pos, u8 *end, const char *str)
1011{
1012 const char *s;
1013 int val;
1014
1015 s = str;
1016 while (*s) {
1017 while (*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n' ||
1018 *s == ':')
1019 s++;
1020 if (*s == '\0')
1021 break;
1022 if (*s == '#') {
1023 while (*s != '\0' && *s != '\r' && *s != '\n')
1024 s++;
1025 continue;
1026 }
1027
1028 val = hex2byte(s);
1029 if (val < 0) {
1030 printf("Invalid hex encoding '%s'\n", s);
1031 return NULL;
1032 }
1033 if (pos == end) {
1034 printf("Too long frame\n");
1035 return NULL;
1036 }
1037 *pos++ = val;
1038 s += 2;
1039 }
1040
1041 return pos;
1042}
1043
1044
1045static int cmd_send(int s, int argc, char *argv[])
1046{
1047 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
1048 u8 buf[WLANTEST_CTRL_MAX_CMD_LEN], *end, *pos, *len_pos;
1049 int rlen;
1050 enum wlantest_inject_protection prot;
1051 int arg;
1052
1053 /* <prot> <raw frame as hex dump> */
1054
1055 if (argc < 2) {
1056 printf("send needs two arguments: protected/unprotected, "
1057 "raw frame as hex dump\n");
1058 return -1;
1059 }
1060
1061 pos = buf;
1062 end = buf + sizeof(buf);
1063 WPA_PUT_BE32(pos, WLANTEST_CTRL_SEND);
1064 pos += 4;
1065
1066 if (os_strcasecmp(argv[0], "normal") == 0)
1067 prot = WLANTEST_INJECT_NORMAL;
1068 else if (os_strcasecmp(argv[0], "protected") == 0)
1069 prot = WLANTEST_INJECT_PROTECTED;
1070 else if (os_strcasecmp(argv[0], "unprotected") == 0)
1071 prot = WLANTEST_INJECT_UNPROTECTED;
1072 else if (os_strcasecmp(argv[0], "incorrect") == 0)
1073 prot = WLANTEST_INJECT_INCORRECT_KEY;
1074 else {
1075 printf("Unknown protection type '%s'\n", argv[1]);
1076 printf("Protection types: normal protected unprotected "
1077 "incorrect\n");
1078 return -1;
1079 }
1080 pos = attr_add_be32(pos, end, WLANTEST_ATTR_INJECT_PROTECTION, prot);
1081
1082 WPA_PUT_BE32(pos, WLANTEST_ATTR_FRAME);
1083 pos += 4;
1084 len_pos = pos;
1085 pos += 4;
1086
1087 for (arg = 1; pos && arg < argc; arg++)
1088 pos = add_hex(pos, end, argv[arg]);
1089 if (pos == NULL)
1090 return -1;
1091
1092 WPA_PUT_BE32(len_pos, pos - len_pos - 4);
1093
1094 rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
1095 if (rlen < 0)
1096 return -1;
1097 printf("OK\n");
1098 return 0;
1099}
1100
1101
1102static char ** complete_send(int s, const char *str, int pos)
1103{
1104 int arg = get_cmd_arg_num(str, pos);
1105 char **res = NULL;
1106
1107 switch (arg) {
1108 case 1:
1109 res = os_zalloc(5 * sizeof(char *));
1110 if (res == NULL)
1111 break;
1112 res[0] = os_strdup("normal");
1113 if (res[0] == NULL)
1114 break;
1115 res[1] = os_strdup("protected");
1116 if (res[1] == NULL)
1117 break;
1118 res[2] = os_strdup("unprotected");
1119 if (res[2] == NULL)
1120 break;
1121 res[3] = os_strdup("incorrect");
1122 if (res[3] == NULL)
1123 break;
1124 break;
1125 }
1126
1127 return res;
1128}
1129
1130
a16c8590
JM
1131static int cmd_version(int s, int argc, char *argv[])
1132{
1133 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
1134 u8 buf[4];
1135 char *version;
1136 size_t len;
1137 int rlen, i;
1138
1139 WPA_PUT_BE32(buf, WLANTEST_CTRL_VERSION);
1140 rlen = cmd_send_and_recv(s, buf, sizeof(buf), resp, sizeof(resp));
1141 if (rlen < 0)
1142 return -1;
1143
1144 version = (char *) attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_VERSION,
1145 &len);
1146 if (version == NULL)
1147 return -1;
1148
1149 for (i = 0; i < len; i++)
1150 putchar(version[i]);
1151 printf("\n");
1152
1153 return 0;
1154}
1155
1156
fbdd2132
JM
1157static int cmd_add_passphrase(int s, int argc, char *argv[])
1158{
1159 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
1160 u8 buf[100], *pos, *end;
1161 size_t len;
1162 int rlen;
1163
1164 if (argc < 1) {
1165 printf("add_passphrase needs one argument: passphrase\n");
1166 return -1;
1167 }
1168
1169 len = os_strlen(argv[0]);
1170 if (len < 8 || len > 63) {
1171 printf("Invalid passphrase '%s'\n", argv[0]);
1172 return -1;
1173 }
1174 pos = buf;
1175 end = buf + sizeof(buf);
1176 WPA_PUT_BE32(pos, WLANTEST_CTRL_ADD_PASSPHRASE);
1177 pos += 4;
1178 pos = attr_add_str(pos, end, WLANTEST_ATTR_PASSPHRASE,
1179 argv[0]);
1180 if (argc > 1) {
1181 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
1182 if (hwaddr_aton(argv[1], pos) < 0) {
1183 printf("Invalid BSSID '%s'\n", argv[3]);
1184 return -1;
1185 }
1186 pos += ETH_ALEN;
1187 }
1188
1189 rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
1190 if (rlen < 0)
1191 return -1;
1192 return 0;
1193}
1194
1195
2fc0cd54
JM
1196struct sta_infos {
1197 const char *name;
1198 enum wlantest_sta_info num;
1199};
1200
1201static const struct sta_infos sta_infos[] = {
1202 { "proto", WLANTEST_STA_INFO_PROTO },
1203 { "pairwise", WLANTEST_STA_INFO_PAIRWISE },
1204 { "key_mgmt", WLANTEST_STA_INFO_KEY_MGMT },
1205 { "rsn_capab", WLANTEST_STA_INFO_RSN_CAPAB },
1206 { "state", WLANTEST_STA_INFO_STATE },
1207 { NULL, 0 }
1208};
1209
1210static int cmd_info_sta(int s, int argc, char *argv[])
1211{
1212 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
1213 u8 buf[100], *end, *pos;
1214 int rlen, i;
1215 size_t len;
1216 char info[100];
1217
1218 if (argc != 3) {
1219 printf("sta_info needs at three arguments: "
1220 "counter name, BSSID, and STA address\n");
1221 return -1;
1222 }
1223
1224 pos = buf;
1225 end = buf + sizeof(buf);
1226 WPA_PUT_BE32(pos, WLANTEST_CTRL_INFO_STA);
1227 pos += 4;
1228
1229 for (i = 0; sta_infos[i].name; i++) {
1230 if (os_strcasecmp(sta_infos[i].name, argv[0]) == 0)
1231 break;
1232 }
1233 if (sta_infos[i].name == NULL) {
1234 printf("Unknown STA info '%s'\n", argv[0]);
1235 printf("Info fields:");
1236 for (i = 0; sta_infos[i].name; i++)
1237 printf(" %s", sta_infos[i].name);
1238 printf("\n");
1239 return -1;
1240 }
1241
1242 pos = attr_add_be32(pos, end, WLANTEST_ATTR_STA_INFO,
1243 sta_infos[i].num);
1244 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
1245 if (hwaddr_aton(argv[1], pos) < 0) {
1246 printf("Invalid BSSID '%s'\n", argv[1]);
1247 return -1;
1248 }
1249 pos += ETH_ALEN;
1250
1251 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA_ADDR, ETH_ALEN);
1252 if (hwaddr_aton(argv[2], pos) < 0) {
1253 printf("Invalid STA address '%s'\n", argv[2]);
1254 return -1;
1255 }
1256 pos += ETH_ALEN;
1257
1258 rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
1259 if (rlen < 0)
1260 return -1;
1261
1262 pos = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_INFO, &len);
1263 if (pos == NULL)
1264 return -1;
1265 if (len >= sizeof(info))
1266 len = sizeof(info) - 1;
1267 os_memcpy(info, pos, len);
1268 info[len] = '\0';
1269 printf("%s\n", info);
1270 return 0;
1271}
1272
1273
1274static char ** complete_info_sta(int s, const char *str, int pos)
1275{
1276 int arg = get_cmd_arg_num(str, pos);
1277 char **res = NULL;
1278 int i, count;
1279 u8 addr[ETH_ALEN];
1280
1281 switch (arg) {
1282 case 1:
1283 /* counter list */
1284 count = sizeof(sta_infos) / sizeof(sta_infos[0]);
1285 res = os_zalloc(count * sizeof(char *));
1286 if (res == NULL)
1287 return NULL;
1288 for (i = 0; sta_infos[i].name; i++) {
1289 res[i] = os_strdup(sta_infos[i].name);
1290 if (res[i] == NULL)
1291 break;
1292 }
1293 break;
1294 case 2:
1295 res = get_bssid_list(s);
1296 break;
1297 case 3:
1298 if (hwaddr_aton(&str[get_prev_arg_pos(str, pos)], addr) < 0)
1299 break;
1300 res = get_sta_list(s, addr, 0);
1301 break;
1302 }
1303
1304 return res;
1305}
1306
1307
1308struct bss_infos {
1309 const char *name;
1310 enum wlantest_bss_info num;
1311};
1312
1313static const struct bss_infos bss_infos[] = {
1314 { "proto", WLANTEST_BSS_INFO_PROTO },
1315 { "pairwise", WLANTEST_BSS_INFO_PAIRWISE },
1316 { "group", WLANTEST_BSS_INFO_GROUP },
1317 { "group_mgmt", WLANTEST_BSS_INFO_GROUP_MGMT },
1318 { "key_mgmt", WLANTEST_BSS_INFO_KEY_MGMT },
1319 { "rsn_capab", WLANTEST_BSS_INFO_RSN_CAPAB },
1320 { NULL, 0 }
1321};
1322
1323static int cmd_info_bss(int s, int argc, char *argv[])
1324{
1325 u8 resp[WLANTEST_CTRL_MAX_RESP_LEN];
1326 u8 buf[100], *end, *pos;
1327 int rlen, i;
1328 size_t len;
1329 char info[100];
1330
1331 if (argc != 2) {
1332 printf("bss_info needs at two arguments: "
1333 "field name and BSSID\n");
1334 return -1;
1335 }
1336
1337 pos = buf;
1338 end = buf + sizeof(buf);
1339 WPA_PUT_BE32(pos, WLANTEST_CTRL_INFO_BSS);
1340 pos += 4;
1341
1342 for (i = 0; bss_infos[i].name; i++) {
1343 if (os_strcasecmp(bss_infos[i].name, argv[0]) == 0)
1344 break;
1345 }
1346 if (bss_infos[i].name == NULL) {
1347 printf("Unknown BSS info '%s'\n", argv[0]);
1348 printf("Info fields:");
1349 for (i = 0; bss_infos[i].name; i++)
1350 printf(" %s", bss_infos[i].name);
1351 printf("\n");
1352 return -1;
1353 }
1354
1355 pos = attr_add_be32(pos, end, WLANTEST_ATTR_BSS_INFO,
1356 bss_infos[i].num);
1357 pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN);
1358 if (hwaddr_aton(argv[1], pos) < 0) {
1359 printf("Invalid BSSID '%s'\n", argv[1]);
1360 return -1;
1361 }
1362 pos += ETH_ALEN;
1363
1364 rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp));
1365 if (rlen < 0)
1366 return -1;
1367
1368 pos = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_INFO, &len);
1369 if (pos == NULL)
1370 return -1;
1371 if (len >= sizeof(info))
1372 len = sizeof(info) - 1;
1373 os_memcpy(info, pos, len);
1374 info[len] = '\0';
1375 printf("%s\n", info);
1376 return 0;
1377}
1378
1379
1380static char ** complete_info_bss(int s, const char *str, int pos)
1381{
1382 int arg = get_cmd_arg_num(str, pos);
1383 char **res = NULL;
1384 int i, count;
1385
1386 switch (arg) {
1387 case 1:
1388 /* counter list */
1389 count = sizeof(bss_infos) / sizeof(bss_infos[0]);
1390 res = os_zalloc(count * sizeof(char *));
1391 if (res == NULL)
1392 return NULL;
1393 for (i = 0; bss_infos[i].name; i++) {
1394 res[i] = os_strdup(bss_infos[i].name);
1395 if (res[i] == NULL)
1396 break;
1397 }
1398 break;
1399 case 2:
1400 res = get_bssid_list(s);
1401 break;
1402 }
1403
1404 return res;
1405}
1406
1407
644fb8c8
JM
1408struct wlantest_cli_cmd {
1409 const char *cmd;
1410 int (*handler)(int s, int argc, char *argv[]);
1411 const char *usage;
79a670cb 1412 char ** (*complete)(int s, const char *str, int pos);
644fb8c8
JM
1413};
1414
1415static const struct wlantest_cli_cmd wlantest_cli_commands[] = {
79a670cb
JM
1416 { "ping", cmd_ping, "= test connection to wlantest", NULL },
1417 { "terminate", cmd_terminate, "= terminate wlantest", NULL },
1418 { "list_bss", cmd_list_bss, "= get BSS list", NULL },
1419 { "list_sta", cmd_list_sta, "<BSSID> = get STA list",
1420 complete_list_sta },
1421 { "flush", cmd_flush, "= drop all collected BSS data", NULL },
6d5ce9fc 1422 { "clear_sta_counters", cmd_clear_sta_counters,
79a670cb 1423 "<BSSID> <STA> = clear STA counters", complete_clear_sta_counters },
6d5ce9fc 1424 { "clear_bss_counters", cmd_clear_bss_counters,
79a670cb 1425 "<BSSID> = clear BSS counters", complete_clear_bss_counters },
6d5ce9fc 1426 { "get_sta_counter", cmd_get_sta_counter,
79a670cb 1427 "<counter> <BSSID> <STA> = get STA counter value",
2fc0cd54 1428 complete_get_sta_counter },
6d5ce9fc 1429 { "get_bss_counter", cmd_get_bss_counter,
79a670cb
JM
1430 "<counter> <BSSID> = get BSS counter value",
1431 complete_get_bss_counter },
7d23e971 1432 { "inject", cmd_inject,
79a670cb
JM
1433 "<frame> <prot> <sender> <BSSID> <STA/ff:ff:ff:ff:ff:ff>",
1434 complete_inject },
b3a6d9d4
JM
1435 { "send", cmd_send,
1436 "<prot> <raw frame as hex dump>",
1437 complete_send },
79a670cb 1438 { "version", cmd_version, "= get wlantest version", NULL },
fbdd2132 1439 { "add_passphrase", cmd_add_passphrase,
79a670cb 1440 "<passphrase> = add a known passphrase", NULL },
2fc0cd54
JM
1441 { "info_sta", cmd_info_sta,
1442 "<field> <BSSID> <STA> = get STA information",
1443 complete_info_sta },
1444 { "info_bss", cmd_info_bss,
1445 "<field> <BSSID> = get BSS information",
1446 complete_info_bss },
0e42fff3
JM
1447 { "clear_tdls_counters", cmd_clear_tdls_counters,
1448 "<BSSID> <STA1> <STA2> = clear TDLS counters",
1449 complete_clear_tdls_counters },
1450 { "get_tdls_counter", cmd_get_tdls_counter,
1451 "<counter> <BSSID> <STA1> <STA2> = get TDLS counter value",
1452 complete_get_tdls_counter },
1453 { "get_bss_counter", cmd_get_bss_counter,
1454 "<counter> <BSSID> = get BSS counter value",
1455 complete_get_bss_counter },
79a670cb 1456 { NULL, NULL, NULL, NULL }
644fb8c8
JM
1457};
1458
1459
1460static int ctrl_command(int s, int argc, char *argv[])
1461{
1462 const struct wlantest_cli_cmd *cmd, *match = NULL;
1463 int count = 0;
1464 int ret = 0;
1465
1466 for (cmd = wlantest_cli_commands; cmd->cmd; cmd++) {
1467 if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0)
1468 {
1469 match = cmd;
1470 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1471 /* exact match */
1472 count = 1;
1473 break;
1474 }
1475 count++;
1476 }
1477 }
1478
1479 if (count > 1) {
1480 printf("Ambiguous command '%s'; possible commands:", argv[0]);
1481 for (cmd = wlantest_cli_commands; cmd->cmd; cmd++) {
1482 if (os_strncasecmp(cmd->cmd, argv[0],
1483 os_strlen(argv[0])) == 0) {
1484 printf(" %s", cmd->cmd);
1485 }
644fb8c8
JM
1486 }
1487 printf("\n");
1488 ret = 1;
1489 } else if (count == 0) {
1490 printf("Unknown command '%s'\n", argv[0]);
1491 ret = 1;
1492 } else {
1493 ret = match->handler(s, argc - 1, &argv[1]);
1494 }
1495
1496 return ret;
1497}
1498
1499
ef49bb80
JM
1500struct wlantest_cli {
1501 int s;
1502};
1503
1504
1505#define max_args 10
1506
1507static int tokenize_cmd(char *cmd, char *argv[])
1508{
1509 char *pos;
1510 int argc = 0;
1511
1512 pos = cmd;
1513 for (;;) {
1514 while (*pos == ' ')
1515 pos++;
1516 if (*pos == '\0')
1517 break;
1518 argv[argc] = pos;
1519 argc++;
1520 if (argc == max_args)
1521 break;
1522 if (*pos == '"') {
1523 char *pos2 = os_strrchr(pos, '"');
1524 if (pos2)
1525 pos = pos2 + 1;
1526 }
1527 while (*pos != '\0' && *pos != ' ')
1528 pos++;
1529 if (*pos == ' ')
1530 *pos++ = '\0';
1531 }
1532
1533 return argc;
1534}
1535
1536
1537static void wlantest_cli_edit_cmd_cb(void *ctx, char *cmd)
1538{
1539 struct wlantest_cli *cli = ctx;
1540 char *argv[max_args];
1541 int argc;
1542 argc = tokenize_cmd(cmd, argv);
1543 if (argc) {
1544 int ret = ctrl_command(cli->s, argc, argv);
1545 if (ret < 0)
1546 printf("FAIL\n");
1547 }
1548}
1549
1550
1551static void wlantest_cli_eloop_terminate(int sig, void *signal_ctx)
1552{
1553 eloop_terminate();
1554}
1555
1556
1557static void wlantest_cli_edit_eof_cb(void *ctx)
1558{
1559 eloop_terminate();
1560}
1561
1562
1563static char ** wlantest_cli_cmd_list(void)
1564{
1565 char **res;
1566 int i, count;
1567
1568 count = sizeof(wlantest_cli_commands) /
1569 sizeof(wlantest_cli_commands[0]);
1570 res = os_zalloc(count * sizeof(char *));
1571 if (res == NULL)
1572 return NULL;
1573
1574 for (i = 0; wlantest_cli_commands[i].cmd; i++) {
1575 res[i] = os_strdup(wlantest_cli_commands[i].cmd);
1576 if (res[i] == NULL)
1577 break;
1578 }
1579
1580 return res;
1581}
1582
1583
79a670cb
JM
1584static char ** wlantest_cli_cmd_completion(struct wlantest_cli *cli,
1585 const char *cmd, const char *str,
ef49bb80
JM
1586 int pos)
1587{
1588 int i;
1589
1590 for (i = 0; wlantest_cli_commands[i].cmd; i++) {
79a670cb
JM
1591 const struct wlantest_cli_cmd *c = &wlantest_cli_commands[i];
1592 if (os_strcasecmp(c->cmd, cmd) == 0) {
ef49bb80 1593 edit_clear_line();
79a670cb 1594 printf("\r%s\n", c->usage);
ef49bb80 1595 edit_redraw();
79a670cb
JM
1596 if (c->complete)
1597 return c->complete(cli->s, str, pos);
ef49bb80
JM
1598 break;
1599 }
1600 }
1601
1602 return NULL;
1603}
1604
1605
1606static char ** wlantest_cli_edit_completion_cb(void *ctx, const char *str,
1607 int pos)
1608{
79a670cb 1609 struct wlantest_cli *cli = ctx;
ef49bb80
JM
1610 char **res;
1611 const char *end;
1612 char *cmd;
1613
1614 end = os_strchr(str, ' ');
1615 if (end == NULL || str + pos < end)
1616 return wlantest_cli_cmd_list();
1617
1618 cmd = os_malloc(pos + 1);
1619 if (cmd == NULL)
1620 return NULL;
1621 os_memcpy(cmd, str, pos);
1622 cmd[end - str] = '\0';
79a670cb 1623 res = wlantest_cli_cmd_completion(cli, cmd, str, pos);
ef49bb80
JM
1624 os_free(cmd);
1625 return res;
1626}
1627
1628
1629static void wlantest_cli_interactive(int s)
1630{
1631 struct wlantest_cli cli;
13b9f3a1 1632 char *home, *hfile = NULL;
ef49bb80
JM
1633
1634 if (eloop_init())
1635 return;
1636
13b9f3a1
JM
1637 home = getenv("HOME");
1638 if (home) {
1639 const char *fname = ".wlantest_cli_history";
1640 int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
1641 hfile = os_malloc(hfile_len);
1642 if (hfile)
1643 os_snprintf(hfile, hfile_len, "%s/%s", home, fname);
1644 }
1645
ef49bb80
JM
1646 cli.s = s;
1647 eloop_register_signal_terminate(wlantest_cli_eloop_terminate, &cli);
8953e968 1648 edit_init(wlantest_cli_edit_cmd_cb, wlantest_cli_edit_eof_cb,
13b9f3a1 1649 wlantest_cli_edit_completion_cb, &cli, hfile);
ef49bb80
JM
1650
1651 eloop_run();
1652
13b9f3a1
JM
1653 edit_deinit(hfile, NULL);
1654 os_free(hfile);
ef49bb80
JM
1655 eloop_destroy();
1656}
1657
1658
644fb8c8
JM
1659int main(int argc, char *argv[])
1660{
1661 int s;
1662 struct sockaddr_un addr;
1663 int ret = 0;
1664
ef49bb80
JM
1665 if (os_program_init())
1666 return -1;
1667
644fb8c8
JM
1668 s = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1669 if (s < 0) {
1670 perror("socket");
1671 return -1;
1672 }
1673
1674 os_memset(&addr, 0, sizeof(addr));
1675 addr.sun_family = AF_UNIX;
1676 os_strlcpy(addr.sun_path + 1, WLANTEST_SOCK_NAME,
1677 sizeof(addr.sun_path) - 1);
1678 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1679 perror("connect");
1680 close(s);
1681 return -1;
1682 }
1683
1684 if (argc > 1) {
1685 ret = ctrl_command(s, argc - 1, &argv[1]);
1686 if (ret < 0)
1687 printf("FAIL\n");
1688 } else {
ef49bb80 1689 wlantest_cli_interactive(s);
644fb8c8
JM
1690 }
1691
1692 close(s);
ef49bb80
JM
1693
1694 os_program_deinit();
1695
644fb8c8
JM
1696 return ret;
1697}