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