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