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