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