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