0212335d05980bf32db4ed0a348d827695f09470
[mech_eap.git] / hostapd / hostapd_cli.c
1 /*
2  * hostapd - command line interface for hostapd daemon
3  * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8
9 #include "includes.h"
10 #include <dirent.h>
11
12 #include "common/wpa_ctrl.h"
13 #include "common/ieee802_11_defs.h"
14 #include "utils/common.h"
15 #include "utils/eloop.h"
16 #include "utils/edit.h"
17 #include "common/version.h"
18
19 #ifndef CONFIG_NO_CTRL_IFACE
20
21 static const char *const hostapd_cli_version =
22 "hostapd_cli v" VERSION_STR "\n"
23 "Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors";
24
25
26 static const char *const hostapd_cli_license =
27 "This software may be distributed under the terms of the BSD license.\n"
28 "See README for more details.\n";
29
30 static const char *const hostapd_cli_full_license =
31 "This software may be distributed under the terms of the BSD license.\n"
32 "\n"
33 "Redistribution and use in source and binary forms, with or without\n"
34 "modification, are permitted provided that the following conditions are\n"
35 "met:\n"
36 "\n"
37 "1. Redistributions of source code must retain the above copyright\n"
38 "   notice, this list of conditions and the following disclaimer.\n"
39 "\n"
40 "2. Redistributions in binary form must reproduce the above copyright\n"
41 "   notice, this list of conditions and the following disclaimer in the\n"
42 "   documentation and/or other materials provided with the distribution.\n"
43 "\n"
44 "3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
45 "   names of its contributors may be used to endorse or promote products\n"
46 "   derived from this software without specific prior written permission.\n"
47 "\n"
48 "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
49 "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
50 "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
51 "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
52 "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
53 "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
54 "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
55 "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
56 "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
57 "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
58 "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
59 "\n";
60
61 static struct wpa_ctrl *ctrl_conn;
62 static int hostapd_cli_quit = 0;
63 static int hostapd_cli_attached = 0;
64
65 #ifndef CONFIG_CTRL_IFACE_DIR
66 #define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd"
67 #endif /* CONFIG_CTRL_IFACE_DIR */
68 static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
69 static const char *client_socket_dir = NULL;
70
71 static char *ctrl_ifname = NULL;
72 static const char *pid_file = NULL;
73 static const char *action_file = NULL;
74 static int ping_interval = 5;
75 static int interactive = 0;
76
77 static void print_help(FILE *stream, const char *cmd);
78
79
80 static void usage(void)
81 {
82         fprintf(stderr, "%s\n", hostapd_cli_version);
83         fprintf(stderr,
84                 "\n"
85                 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
86                 "[-a<path>] \\\n"
87                 "                   [-P<pid file>] [-G<ping interval>] [command..]\n"
88                 "\n"
89                 "Options:\n"
90                 "   -h           help (show this usage text)\n"
91                 "   -v           shown version information\n"
92                 "   -p<path>     path to find control sockets (default: "
93                 "/var/run/hostapd)\n"
94                 "   -s<dir_path> dir path to open client sockets (default: "
95                 CONFIG_CTRL_IFACE_DIR ")\n"
96                 "   -a<file>     run in daemon mode executing the action file "
97                 "based on events\n"
98                 "                from hostapd\n"
99                 "   -B           run a daemon in the background\n"
100                 "   -i<ifname>   Interface to listen on (default: first "
101                 "interface found in the\n"
102                 "                socket path)\n\n");
103         print_help(stderr, NULL);
104 }
105
106
107 static int str_starts(const char *src, const char *match)
108 {
109         return os_strncmp(src, match, os_strlen(match)) == 0;
110 }
111
112
113 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
114 {
115 #ifndef CONFIG_CTRL_IFACE_UDP
116         char *cfile;
117         int flen;
118 #endif /* !CONFIG_CTRL_IFACE_UDP */
119
120         if (ifname == NULL)
121                 return NULL;
122
123 #ifdef CONFIG_CTRL_IFACE_UDP
124         ctrl_conn = wpa_ctrl_open(ifname);
125         return ctrl_conn;
126 #else /* CONFIG_CTRL_IFACE_UDP */
127         flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
128         cfile = malloc(flen);
129         if (cfile == NULL)
130                 return NULL;
131         snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
132
133         if (client_socket_dir && client_socket_dir[0] &&
134             access(client_socket_dir, F_OK) < 0) {
135                 perror(client_socket_dir);
136                 free(cfile);
137                 return NULL;
138         }
139
140         ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir);
141         free(cfile);
142         return ctrl_conn;
143 #endif /* CONFIG_CTRL_IFACE_UDP */
144 }
145
146
147 static void hostapd_cli_close_connection(void)
148 {
149         if (ctrl_conn == NULL)
150                 return;
151
152         if (hostapd_cli_attached) {
153                 wpa_ctrl_detach(ctrl_conn);
154                 hostapd_cli_attached = 0;
155         }
156         wpa_ctrl_close(ctrl_conn);
157         ctrl_conn = NULL;
158 }
159
160
161 static void hostapd_cli_msg_cb(char *msg, size_t len)
162 {
163         printf("%s\n", msg);
164 }
165
166
167 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
168 {
169         char buf[4096];
170         size_t len;
171         int ret;
172
173         if (ctrl_conn == NULL) {
174                 printf("Not connected to hostapd - command dropped.\n");
175                 return -1;
176         }
177         len = sizeof(buf) - 1;
178         ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
179                                hostapd_cli_msg_cb);
180         if (ret == -2) {
181                 printf("'%s' command timed out.\n", cmd);
182                 return -2;
183         } else if (ret < 0) {
184                 printf("'%s' command failed.\n", cmd);
185                 return -1;
186         }
187         if (print) {
188                 buf[len] = '\0';
189                 printf("%s", buf);
190         }
191         return 0;
192 }
193
194
195 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
196 {
197         return _wpa_ctrl_command(ctrl, cmd, 1);
198 }
199
200
201 static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
202                      char *argv[])
203 {
204         int i, res;
205         char *pos, *end;
206
207         pos = buf;
208         end = buf + buflen;
209
210         res = os_snprintf(pos, end - pos, "%s", cmd);
211         if (os_snprintf_error(end - pos, res))
212                 goto fail;
213         pos += res;
214
215         for (i = 0; i < argc; i++) {
216                 res = os_snprintf(pos, end - pos, " %s", argv[i]);
217                 if (os_snprintf_error(end - pos, res))
218                         goto fail;
219                 pos += res;
220         }
221
222         buf[buflen - 1] = '\0';
223         return 0;
224
225 fail:
226         printf("Too long command\n");
227         return -1;
228 }
229
230
231 static int hostapd_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd,
232                            int min_args, int argc, char *argv[])
233 {
234         char buf[4096];
235
236         if (argc < min_args) {
237                 printf("Invalid %s command - at least %d argument%s required.\n",
238                        cmd, min_args, min_args > 1 ? "s are" : " is");
239                 return -1;
240         }
241         if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0)
242                 return -1;
243         return wpa_ctrl_command(ctrl, buf);
244 }
245
246
247 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
248 {
249         return wpa_ctrl_command(ctrl, "PING");
250 }
251
252
253 static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
254 {
255         return wpa_ctrl_command(ctrl, "RELOG");
256 }
257
258
259 static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
260 {
261         if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
262                 return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
263         return wpa_ctrl_command(ctrl, "STATUS");
264 }
265
266
267 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
268 {
269         if (argc > 0) {
270                 char buf[100];
271                 os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]);
272                 return wpa_ctrl_command(ctrl, buf);
273         }
274         return wpa_ctrl_command(ctrl, "MIB");
275 }
276
277
278 static int hostapd_cli_exec(const char *program, const char *arg1,
279                             const char *arg2)
280 {
281         char *arg;
282         size_t len;
283         int res;
284
285         len = os_strlen(arg1) + os_strlen(arg2) + 2;
286         arg = os_malloc(len);
287         if (arg == NULL)
288                 return -1;
289         os_snprintf(arg, len, "%s %s", arg1, arg2);
290         res = os_exec(program, arg, 1);
291         os_free(arg);
292
293         return res;
294 }
295
296
297 static void hostapd_cli_action_process(char *msg, size_t len)
298 {
299         const char *pos;
300
301         pos = msg;
302         if (*pos == '<') {
303                 pos = os_strchr(pos, '>');
304                 if (pos)
305                         pos++;
306                 else
307                         pos = msg;
308         }
309
310         hostapd_cli_exec(action_file, ctrl_ifname, pos);
311 }
312
313
314 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
315 {
316         char buf[64];
317         if (argc < 1) {
318                 printf("Invalid 'sta' command - at least one argument, STA "
319                        "address, is required.\n");
320                 return -1;
321         }
322         if (argc > 1)
323                 snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]);
324         else
325                 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
326         return wpa_ctrl_command(ctrl, buf);
327 }
328
329
330 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
331                                    char *argv[])
332 {
333         char buf[64];
334         if (argc != 1) {
335                 printf("Invalid 'new_sta' command - exactly one argument, STA "
336                        "address, is required.\n");
337                 return -1;
338         }
339         snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
340         return wpa_ctrl_command(ctrl, buf);
341 }
342
343
344 static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
345                                           char *argv[])
346 {
347         char buf[64];
348         if (argc < 1) {
349                 printf("Invalid 'deauthenticate' command - exactly one "
350                        "argument, STA address, is required.\n");
351                 return -1;
352         }
353         if (argc > 1)
354                 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
355                             argv[0], argv[1]);
356         else
357                 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
358         return wpa_ctrl_command(ctrl, buf);
359 }
360
361
362 static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
363                                         char *argv[])
364 {
365         char buf[64];
366         if (argc < 1) {
367                 printf("Invalid 'disassociate' command - exactly one "
368                        "argument, STA address, is required.\n");
369                 return -1;
370         }
371         if (argc > 1)
372                 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
373                             argv[0], argv[1]);
374         else
375                 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
376         return wpa_ctrl_command(ctrl, buf);
377 }
378
379
380 #ifdef CONFIG_IEEE80211W
381 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
382                                     char *argv[])
383 {
384         char buf[64];
385         if (argc != 1) {
386                 printf("Invalid 'sa_query' command - exactly one argument, "
387                        "STA address, is required.\n");
388                 return -1;
389         }
390         snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
391         return wpa_ctrl_command(ctrl, buf);
392 }
393 #endif /* CONFIG_IEEE80211W */
394
395
396 #ifdef CONFIG_WPS
397 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
398                                    char *argv[])
399 {
400         char buf[256];
401         if (argc < 2) {
402                 printf("Invalid 'wps_pin' command - at least two arguments, "
403                        "UUID and PIN, are required.\n");
404                 return -1;
405         }
406         if (argc > 3)
407                 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
408                          argv[0], argv[1], argv[2], argv[3]);
409         else if (argc > 2)
410                 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
411                          argv[0], argv[1], argv[2]);
412         else
413                 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
414         return wpa_ctrl_command(ctrl, buf);
415 }
416
417
418 static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
419                                          char *argv[])
420 {
421         char cmd[256];
422         int res;
423
424         if (argc != 1 && argc != 2) {
425                 printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
426                        "- PIN to be verified\n");
427                 return -1;
428         }
429
430         if (argc == 2)
431                 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
432                                   argv[0], argv[1]);
433         else
434                 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
435                                   argv[0]);
436         if (os_snprintf_error(sizeof(cmd), res)) {
437                 printf("Too long WPS_CHECK_PIN command.\n");
438                 return -1;
439         }
440         return wpa_ctrl_command(ctrl, cmd);
441 }
442
443
444 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
445                                    char *argv[])
446 {
447         return wpa_ctrl_command(ctrl, "WPS_PBC");
448 }
449
450
451 static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
452                                       char *argv[])
453 {
454         return wpa_ctrl_command(ctrl, "WPS_CANCEL");
455 }
456
457
458 #ifdef CONFIG_WPS_NFC
459 static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
460                                             char *argv[])
461 {
462         int ret;
463         char *buf;
464         size_t buflen;
465
466         if (argc != 1) {
467                 printf("Invalid 'wps_nfc_tag_read' command - one argument "
468                        "is required.\n");
469                 return -1;
470         }
471
472         buflen = 18 + os_strlen(argv[0]);
473         buf = os_malloc(buflen);
474         if (buf == NULL)
475                 return -1;
476         os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
477
478         ret = wpa_ctrl_command(ctrl, buf);
479         os_free(buf);
480
481         return ret;
482 }
483
484
485 static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
486                                                 int argc, char *argv[])
487 {
488         char cmd[64];
489         int res;
490
491         if (argc != 1) {
492                 printf("Invalid 'wps_nfc_config_token' command - one argument "
493                        "is required.\n");
494                 return -1;
495         }
496
497         res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
498                           argv[0]);
499         if (os_snprintf_error(sizeof(cmd), res)) {
500                 printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
501                 return -1;
502         }
503         return wpa_ctrl_command(ctrl, cmd);
504 }
505
506
507 static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
508                                          int argc, char *argv[])
509 {
510         char cmd[64];
511         int res;
512
513         if (argc != 1) {
514                 printf("Invalid 'wps_nfc_token' command - one argument is "
515                        "required.\n");
516                 return -1;
517         }
518
519         res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
520         if (os_snprintf_error(sizeof(cmd), res)) {
521                 printf("Too long WPS_NFC_TOKEN command.\n");
522                 return -1;
523         }
524         return wpa_ctrl_command(ctrl, cmd);
525 }
526
527
528 static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
529                                                 int argc, char *argv[])
530 {
531         char cmd[64];
532         int res;
533
534         if (argc != 2) {
535                 printf("Invalid 'nfc_get_handover_sel' command - two arguments "
536                        "are required.\n");
537                 return -1;
538         }
539
540         res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
541                           argv[0], argv[1]);
542         if (os_snprintf_error(sizeof(cmd), res)) {
543                 printf("Too long NFC_GET_HANDOVER_SEL command.\n");
544                 return -1;
545         }
546         return wpa_ctrl_command(ctrl, cmd);
547 }
548
549 #endif /* CONFIG_WPS_NFC */
550
551
552 static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
553                                       char *argv[])
554 {
555         char buf[64];
556         if (argc < 1) {
557                 printf("Invalid 'wps_ap_pin' command - at least one argument "
558                        "is required.\n");
559                 return -1;
560         }
561         if (argc > 2)
562                 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
563                          argv[0], argv[1], argv[2]);
564         else if (argc > 1)
565                 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
566                          argv[0], argv[1]);
567         else
568                 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
569         return wpa_ctrl_command(ctrl, buf);
570 }
571
572
573 static int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc,
574                                           char *argv[])
575 {
576         return wpa_ctrl_command(ctrl, "WPS_GET_STATUS");
577 }
578
579
580 static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
581                                       char *argv[])
582 {
583         char buf[256];
584         char ssid_hex[2 * SSID_MAX_LEN + 1];
585         char key_hex[2 * 64 + 1];
586         int i;
587
588         if (argc < 1) {
589                 printf("Invalid 'wps_config' command - at least two arguments "
590                        "are required.\n");
591                 return -1;
592         }
593
594         ssid_hex[0] = '\0';
595         for (i = 0; i < SSID_MAX_LEN; i++) {
596                 if (argv[0][i] == '\0')
597                         break;
598                 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
599         }
600
601         key_hex[0] = '\0';
602         if (argc > 3) {
603                 for (i = 0; i < 64; i++) {
604                         if (argv[3][i] == '\0')
605                                 break;
606                         os_snprintf(&key_hex[i * 2], 3, "%02x",
607                                     argv[3][i]);
608                 }
609         }
610
611         if (argc > 3)
612                 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
613                          ssid_hex, argv[1], argv[2], key_hex);
614         else if (argc > 2)
615                 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
616                          ssid_hex, argv[1], argv[2]);
617         else
618                 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
619                          ssid_hex, argv[1]);
620         return wpa_ctrl_command(ctrl, buf);
621 }
622 #endif /* CONFIG_WPS */
623
624
625 static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
626                                              char *argv[])
627 {
628         char buf[300];
629         int res;
630
631         if (argc < 2) {
632                 printf("Invalid 'disassoc_imminent' command - two arguments "
633                        "(STA addr and Disassociation Timer) are needed\n");
634                 return -1;
635         }
636
637         res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
638                           argv[0], argv[1]);
639         if (os_snprintf_error(sizeof(buf), res))
640                 return -1;
641         return wpa_ctrl_command(ctrl, buf);
642 }
643
644
645 static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
646                                         char *argv[])
647 {
648         char buf[300];
649         int res;
650
651         if (argc < 3) {
652                 printf("Invalid 'ess_disassoc' command - three arguments (STA "
653                        "addr, disassoc timer, and URL) are needed\n");
654                 return -1;
655         }
656
657         res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
658                           argv[0], argv[1], argv[2]);
659         if (os_snprintf_error(sizeof(buf), res))
660                 return -1;
661         return wpa_ctrl_command(ctrl, buf);
662 }
663
664
665 static int hostapd_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc,
666                                       char *argv[])
667 {
668         char buf[2000], *tmp;
669         int res, i, total;
670
671         if (argc < 1) {
672                 printf("Invalid 'bss_tm_req' command - at least one argument (STA addr) is needed\n");
673                 return -1;
674         }
675
676         res = os_snprintf(buf, sizeof(buf), "BSS_TM_REQ %s", argv[0]);
677         if (os_snprintf_error(sizeof(buf), res))
678                 return -1;
679
680         total = res;
681         for (i = 1; i < argc; i++) {
682                 tmp = &buf[total];
683                 res = os_snprintf(tmp, sizeof(buf) - total, " %s", argv[i]);
684                 if (os_snprintf_error(sizeof(buf) - total, res))
685                         return -1;
686                 total += res;
687         }
688         return wpa_ctrl_command(ctrl, buf);
689 }
690
691
692 static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
693                                       char *argv[])
694 {
695         return wpa_ctrl_command(ctrl, "GET_CONFIG");
696 }
697
698
699 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
700                                 char *addr, size_t addr_len)
701 {
702         char buf[4096], *pos;
703         size_t len;
704         int ret;
705
706         if (ctrl_conn == NULL) {
707                 printf("Not connected to hostapd - command dropped.\n");
708                 return -1;
709         }
710         len = sizeof(buf) - 1;
711         ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
712                                hostapd_cli_msg_cb);
713         if (ret == -2) {
714                 printf("'%s' command timed out.\n", cmd);
715                 return -2;
716         } else if (ret < 0) {
717                 printf("'%s' command failed.\n", cmd);
718                 return -1;
719         }
720
721         buf[len] = '\0';
722         if (memcmp(buf, "FAIL", 4) == 0)
723                 return -1;
724         printf("%s", buf);
725
726         pos = buf;
727         while (*pos != '\0' && *pos != '\n')
728                 pos++;
729         *pos = '\0';
730         os_strlcpy(addr, buf, addr_len);
731         return 0;
732 }
733
734
735 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
736                                    char *argv[])
737 {
738         char addr[32], cmd[64];
739
740         if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
741                 return 0;
742         do {
743                 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
744         } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
745
746         return -1;
747 }
748
749
750 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
751 {
752         print_help(stdout, argc > 0 ? argv[0] : NULL);
753         return 0;
754 }
755
756
757 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
758                                    char *argv[])
759 {
760         printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
761         return 0;
762 }
763
764
765 static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl,
766                                            int argc, char *argv[])
767 {
768         char buf[200];
769         int res;
770
771         if (argc != 1) {
772                 printf("Invalid 'set_qos_map_set' command - "
773                        "one argument (comma delimited QoS map set) "
774                        "is needed\n");
775                 return -1;
776         }
777
778         res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
779         if (os_snprintf_error(sizeof(buf), res))
780                 return -1;
781         return wpa_ctrl_command(ctrl, buf);
782 }
783
784
785 static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
786                                              int argc, char *argv[])
787 {
788         char buf[50];
789         int res;
790
791         if (argc != 1) {
792                 printf("Invalid 'send_qos_map_conf' command - "
793                        "one argument (STA addr) is needed\n");
794                 return -1;
795         }
796
797         res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
798         if (os_snprintf_error(sizeof(buf), res))
799                 return -1;
800         return wpa_ctrl_command(ctrl, buf);
801 }
802
803
804 static int hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc,
805                                           char *argv[])
806 {
807         char buf[300];
808         int res;
809
810         if (argc < 2) {
811                 printf("Invalid 'hs20_wnm_notif' command - two arguments (STA "
812                        "addr and URL) are needed\n");
813                 return -1;
814         }
815
816         res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s",
817                           argv[0], argv[1]);
818         if (os_snprintf_error(sizeof(buf), res))
819                 return -1;
820         return wpa_ctrl_command(ctrl, buf);
821 }
822
823
824 static int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc,
825                                            char *argv[])
826 {
827         char buf[300];
828         int res;
829
830         if (argc < 3) {
831                 printf("Invalid 'hs20_deauth_req' command - at least three arguments (STA addr, Code, Re-auth Delay) are needed\n");
832                 return -1;
833         }
834
835         if (argc > 3)
836                 res = os_snprintf(buf, sizeof(buf),
837                                   "HS20_DEAUTH_REQ %s %s %s %s",
838                                   argv[0], argv[1], argv[2], argv[3]);
839         else
840                 res = os_snprintf(buf, sizeof(buf),
841                                   "HS20_DEAUTH_REQ %s %s %s",
842                                   argv[0], argv[1], argv[2]);
843         if (os_snprintf_error(sizeof(buf), res))
844                 return -1;
845         return wpa_ctrl_command(ctrl, buf);
846 }
847
848
849 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
850 {
851         hostapd_cli_quit = 1;
852         if (interactive)
853                 eloop_terminate();
854         return 0;
855 }
856
857
858 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
859 {
860         char cmd[256];
861         if (argc != 1) {
862                 printf("Invalid LEVEL command: needs one argument (debug "
863                        "level)\n");
864                 return 0;
865         }
866         snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
867         return wpa_ctrl_command(ctrl, cmd);
868 }
869
870
871 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
872 {
873         struct dirent *dent;
874         DIR *dir;
875
876         dir = opendir(ctrl_iface_dir);
877         if (dir == NULL) {
878                 printf("Control interface directory '%s' could not be "
879                        "openned.\n", ctrl_iface_dir);
880                 return;
881         }
882
883         printf("Available interfaces:\n");
884         while ((dent = readdir(dir))) {
885                 if (strcmp(dent->d_name, ".") == 0 ||
886                     strcmp(dent->d_name, "..") == 0)
887                         continue;
888                 printf("%s\n", dent->d_name);
889         }
890         closedir(dir);
891 }
892
893
894 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
895                                      char *argv[])
896 {
897         if (argc < 1) {
898                 hostapd_cli_list_interfaces(ctrl);
899                 return 0;
900         }
901
902         hostapd_cli_close_connection();
903         os_free(ctrl_ifname);
904         ctrl_ifname = os_strdup(argv[0]);
905         if (ctrl_ifname == NULL)
906                 return -1;
907
908         if (hostapd_cli_open_connection(ctrl_ifname)) {
909                 printf("Connected to interface '%s.\n", ctrl_ifname);
910                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
911                         hostapd_cli_attached = 1;
912                 } else {
913                         printf("Warning: Failed to attach to "
914                                "hostapd.\n");
915                 }
916         } else {
917                 printf("Could not connect to interface '%s' - re-trying\n",
918                         ctrl_ifname);
919         }
920         return 0;
921 }
922
923
924 static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
925 {
926         char cmd[256];
927         int res;
928
929         if (argc != 2) {
930                 printf("Invalid SET command: needs two arguments (variable "
931                        "name and value)\n");
932                 return -1;
933         }
934
935         res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
936         if (os_snprintf_error(sizeof(cmd), res)) {
937                 printf("Too long SET command.\n");
938                 return -1;
939         }
940         return wpa_ctrl_command(ctrl, cmd);
941 }
942
943
944 static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
945 {
946         char cmd[256];
947         int res;
948
949         if (argc != 1) {
950                 printf("Invalid GET command: needs one argument (variable "
951                        "name)\n");
952                 return -1;
953         }
954
955         res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
956         if (os_snprintf_error(sizeof(cmd), res)) {
957                 printf("Too long GET command.\n");
958                 return -1;
959         }
960         return wpa_ctrl_command(ctrl, cmd);
961 }
962
963
964 #ifdef CONFIG_FST
965 static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[])
966 {
967         char cmd[256];
968         int res;
969         int i;
970         int total;
971
972         if (argc <= 0) {
973                 printf("FST command: parameters are required.\n");
974                 return -1;
975         }
976
977         total = os_snprintf(cmd, sizeof(cmd), "FST-MANAGER");
978
979         for (i = 0; i < argc; i++) {
980                 res = os_snprintf(cmd + total, sizeof(cmd) - total, " %s",
981                                   argv[i]);
982                 if (os_snprintf_error(sizeof(cmd) - total, res)) {
983                         printf("Too long fst command.\n");
984                         return -1;
985                 }
986                 total += res;
987         }
988         return wpa_ctrl_command(ctrl, cmd);
989 }
990 #endif /* CONFIG_FST */
991
992
993 static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
994                                        int argc, char *argv[])
995 {
996         char cmd[256];
997         int res;
998         int i;
999         char *tmp;
1000         int total;
1001
1002         if (argc < 2) {
1003                 printf("Invalid chan_switch command: needs at least two "
1004                        "arguments (count and freq)\n"
1005                        "usage: <cs_count> <freq> [sec_channel_offset=] "
1006                        "[center_freq1=] [center_freq2=] [bandwidth=] "
1007                        "[blocktx] [ht|vht]\n");
1008                 return -1;
1009         }
1010
1011         res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
1012                           argv[0], argv[1]);
1013         if (os_snprintf_error(sizeof(cmd), res)) {
1014                 printf("Too long CHAN_SWITCH command.\n");
1015                 return -1;
1016         }
1017
1018         total = res;
1019         for (i = 2; i < argc; i++) {
1020                 tmp = cmd + total;
1021                 res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
1022                 if (os_snprintf_error(sizeof(cmd) - total, res)) {
1023                         printf("Too long CHAN_SWITCH command.\n");
1024                         return -1;
1025                 }
1026                 total += res;
1027         }
1028         return wpa_ctrl_command(ctrl, cmd);
1029 }
1030
1031
1032 static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc,
1033                                       char *argv[])
1034 {
1035         return wpa_ctrl_command(ctrl, "ENABLE");
1036 }
1037
1038
1039 static int hostapd_cli_cmd_reload(struct wpa_ctrl *ctrl, int argc,
1040                                       char *argv[])
1041 {
1042         return wpa_ctrl_command(ctrl, "RELOAD");
1043 }
1044
1045
1046 static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc,
1047                                       char *argv[])
1048 {
1049         return wpa_ctrl_command(ctrl, "DISABLE");
1050 }
1051
1052
1053 static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
1054 {
1055         char cmd[256];
1056         int res;
1057
1058         if (argc < 2 || argc > 3) {
1059                 printf("Invalid vendor command\n"
1060                        "usage: <vendor id> <command id> [<hex formatted command argument>]\n");
1061                 return -1;
1062         }
1063
1064         res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
1065                           argc == 3 ? argv[2] : "");
1066         if (os_snprintf_error(sizeof(cmd), res)) {
1067                 printf("Too long VENDOR command.\n");
1068                 return -1;
1069         }
1070         return wpa_ctrl_command(ctrl, cmd);
1071 }
1072
1073
1074 static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc,
1075                                      char *argv[])
1076 {
1077         return wpa_ctrl_command(ctrl, "ERP_FLUSH");
1078 }
1079
1080
1081 static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc,
1082                                      char *argv[])
1083 {
1084         char cmd[256];
1085         int res;
1086
1087         res = os_snprintf(cmd, sizeof(cmd), "LOG_LEVEL%s%s%s%s",
1088                           argc >= 1 ? " " : "",
1089                           argc >= 1 ? argv[0] : "",
1090                           argc == 2 ? " " : "",
1091                           argc == 2 ? argv[1] : "");
1092         if (os_snprintf_error(sizeof(cmd), res)) {
1093                 printf("Too long option\n");
1094                 return -1;
1095         }
1096         return wpa_ctrl_command(ctrl, cmd);
1097 }
1098
1099
1100 static int hostapd_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
1101 {
1102         if (argc == 0)
1103                 return -1;
1104         return hostapd_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]);
1105 }
1106
1107
1108 static int hostapd_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
1109 {
1110         return wpa_ctrl_command(ctrl, "PMKSA");
1111 }
1112
1113
1114 static int hostapd_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc,
1115                                        char *argv[])
1116 {
1117         return wpa_ctrl_command(ctrl, "PMKSA_FLUSH");
1118 }
1119
1120
1121 static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc,
1122                                         char *argv[])
1123 {
1124         char cmd[2048];
1125         int res;
1126
1127         if (argc < 3 || argc > 5) {
1128                 printf("Invalid set_neighbor command: needs 3-5 arguments\n");
1129                 return -1;
1130         }
1131
1132         res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s",
1133                           argv[0], argv[1], argv[2], argc >= 4 ? argv[3] : "",
1134                           argc == 5 ? argv[4] : "");
1135         if (os_snprintf_error(sizeof(cmd), res)) {
1136                 printf("Too long SET_NEIGHBOR command.\n");
1137                 return -1;
1138         }
1139         return wpa_ctrl_command(ctrl, cmd);
1140 }
1141
1142
1143 static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc,
1144                                            char *argv[])
1145 {
1146         char cmd[400];
1147         int res;
1148
1149         if (argc != 2) {
1150                 printf("Invalid remove_neighbor command: needs 2 arguments\n");
1151                 return -1;
1152         }
1153
1154         res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NEIGHBOR %s %s",
1155                           argv[0], argv[1]);
1156         if (os_snprintf_error(sizeof(cmd), res)) {
1157                 printf("Too long REMOVE_NEIGHBOR command.\n");
1158                 return -1;
1159         }
1160         return wpa_ctrl_command(ctrl, cmd);
1161 }
1162
1163
1164 static int hostapd_cli_cmd_req_lci(struct wpa_ctrl *ctrl, int argc,
1165                                    char *argv[])
1166 {
1167         char cmd[256];
1168         int res;
1169
1170         if (argc != 1) {
1171                 printf("Invalid req_lci command - requires destination address\n");
1172                 return -1;
1173         }
1174
1175         res = os_snprintf(cmd, sizeof(cmd), "REQ_LCI %s", argv[0]);
1176         if (os_snprintf_error(sizeof(cmd), res)) {
1177                 printf("Too long REQ_LCI command.\n");
1178                 return -1;
1179         }
1180         return wpa_ctrl_command(ctrl, cmd);
1181 }
1182
1183
1184 static int hostapd_cli_cmd_req_range(struct wpa_ctrl *ctrl, int argc,
1185                                      char *argv[])
1186 {
1187         if (argc < 4) {
1188                 printf("Invalid req_range command: needs at least 4 arguments - dest address, randomization interval, min AP count, and 1 to 16 AP addresses\n");
1189                 return -1;
1190         }
1191
1192         return hostapd_cli_cmd(ctrl, "REQ_RANGE", 4, argc, argv);
1193 }
1194
1195
1196 static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
1197                                         char *argv[])
1198 {
1199         return wpa_ctrl_command(ctrl, "DRIVER_FLAGS");
1200 }
1201
1202
1203 struct hostapd_cli_cmd {
1204         const char *cmd;
1205         int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
1206         char ** (*completion)(const char *str, int pos);
1207         const char *usage;
1208 };
1209
1210 static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
1211         { "ping", hostapd_cli_cmd_ping, NULL,
1212           "= pings hostapd" },
1213         { "mib", hostapd_cli_cmd_mib, NULL,
1214           "= get MIB variables (dot1x, dot11, radius)" },
1215         { "relog", hostapd_cli_cmd_relog, NULL, NULL },
1216         { "status", hostapd_cli_cmd_status, NULL, NULL },
1217         { "sta", hostapd_cli_cmd_sta, NULL,
1218           "<addr> = get MIB variables for one station" },
1219         { "all_sta", hostapd_cli_cmd_all_sta, NULL,
1220            "= get MIB variables for all stations" },
1221         { "new_sta", hostapd_cli_cmd_new_sta, NULL,
1222           "<addr> = add a new station" },
1223         { "deauthenticate", hostapd_cli_cmd_deauthenticate, NULL,
1224           "<addr> = deauthenticate a station" },
1225         { "disassociate", hostapd_cli_cmd_disassociate, NULL,
1226           "<addr> = disassociate a station" },
1227 #ifdef CONFIG_IEEE80211W
1228         { "sa_query", hostapd_cli_cmd_sa_query, NULL,
1229           "<addr> = send SA Query to a station" },
1230 #endif /* CONFIG_IEEE80211W */
1231 #ifdef CONFIG_WPS
1232         { "wps_pin", hostapd_cli_cmd_wps_pin, NULL,
1233           "<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" },
1234         { "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL,
1235           "<PIN> = verify PIN checksum" },
1236         { "wps_pbc", hostapd_cli_cmd_wps_pbc, NULL,
1237           "= indicate button pushed to initiate PBC" },
1238         { "wps_cancel", hostapd_cli_cmd_wps_cancel, NULL,
1239           "= cancel the pending WPS operation" },
1240 #ifdef CONFIG_WPS_NFC
1241         { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read, NULL,
1242           "<hexdump> = report read NFC tag with WPS data" },
1243         { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token, NULL,
1244           "<WPS/NDEF> = build NFC configuration token" },
1245         { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token, NULL,
1246           "<WPS/NDEF/enable/disable> = manager NFC password token" },
1247         { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel, NULL,
1248           NULL },
1249 #endif /* CONFIG_WPS_NFC */
1250         { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin, NULL,
1251           "<cmd> [params..] = enable/disable AP PIN" },
1252         { "wps_config", hostapd_cli_cmd_wps_config, NULL,
1253           "<SSID> <auth> <encr> <key> = configure AP" },
1254         { "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL,
1255           "= show current WPS status" },
1256 #endif /* CONFIG_WPS */
1257         { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL, NULL },
1258         { "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL, NULL },
1259         { "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL, NULL },
1260         { "get_config", hostapd_cli_cmd_get_config, NULL,
1261           "= show current configuration" },
1262         { "help", hostapd_cli_cmd_help, NULL,
1263           "= show this usage help" },
1264         { "interface", hostapd_cli_cmd_interface, NULL,
1265           "[ifname] = show interfaces/select interface" },
1266 #ifdef CONFIG_FST
1267         { "fst", hostapd_cli_cmd_fst, NULL, NULL },
1268 #endif /* CONFIG_FST */
1269         { "raw", hostapd_cli_cmd_raw, NULL, NULL },
1270         { "level", hostapd_cli_cmd_level, NULL,
1271           "<debug level> = change debug level" },
1272         { "license", hostapd_cli_cmd_license, NULL,
1273           "= show full hostapd_cli license" },
1274         { "quit", hostapd_cli_cmd_quit, NULL,
1275           "= exit hostapd_cli" },
1276         { "set", hostapd_cli_cmd_set, NULL, NULL },
1277         { "get", hostapd_cli_cmd_get, NULL, NULL },
1278         { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL, NULL },
1279         { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf, NULL, NULL },
1280         { "chan_switch", hostapd_cli_cmd_chan_switch, NULL, NULL },
1281         { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL, NULL },
1282         { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL, NULL },
1283         { "vendor", hostapd_cli_cmd_vendor, NULL, NULL },
1284         { "enable", hostapd_cli_cmd_enable, NULL, NULL },
1285         { "reload", hostapd_cli_cmd_reload, NULL, NULL },
1286         { "disable", hostapd_cli_cmd_disable, NULL, NULL },
1287         { "erp_flush", hostapd_cli_cmd_erp_flush, NULL, NULL },
1288         { "log_level", hostapd_cli_cmd_log_level, NULL, NULL },
1289         { "pmksa", hostapd_cli_cmd_pmksa, NULL, NULL },
1290         { "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL, NULL },
1291         { "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL, NULL },
1292         { "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL, NULL },
1293         { "req_lci", hostapd_cli_cmd_req_lci, NULL, NULL },
1294         { "req_range", hostapd_cli_cmd_req_range, NULL, NULL },
1295         { "driver_flags", hostapd_cli_cmd_driver_flags, NULL, NULL },
1296         { NULL, NULL, NULL, NULL }
1297 };
1298
1299
1300 /*
1301  * Prints command usage, lines are padded with the specified string.
1302  */
1303 static void print_cmd_help(FILE *stream, const struct hostapd_cli_cmd *cmd,
1304                            const char *pad)
1305 {
1306         char c;
1307         size_t n;
1308
1309         if (cmd->usage == NULL)
1310                 return;
1311         fprintf(stream, "%s%s ", pad, cmd->cmd);
1312         for (n = 0; (c = cmd->usage[n]); n++) {
1313                 fprintf(stream, "%c", c);
1314                 if (c == '\n')
1315                         fprintf(stream, "%s", pad);
1316         }
1317         fprintf(stream, "\n");
1318 }
1319
1320
1321 static void print_help(FILE *stream, const char *cmd)
1322 {
1323         int n;
1324
1325         fprintf(stream, "commands:\n");
1326         for (n = 0; hostapd_cli_commands[n].cmd; n++) {
1327                 if (cmd == NULL || str_starts(hostapd_cli_commands[n].cmd, cmd))
1328                         print_cmd_help(stream, &hostapd_cli_commands[n], "  ");
1329         }
1330 }
1331
1332
1333 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
1334 {
1335         const struct hostapd_cli_cmd *cmd, *match = NULL;
1336         int count;
1337
1338         count = 0;
1339         cmd = hostapd_cli_commands;
1340         while (cmd->cmd) {
1341                 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
1342                         match = cmd;
1343                         if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1344                                 /* we have an exact match */
1345                                 count = 1;
1346                                 break;
1347                         }
1348                         count++;
1349                 }
1350                 cmd++;
1351         }
1352
1353         if (count > 1) {
1354                 printf("Ambiguous command '%s'; possible commands:", argv[0]);
1355                 cmd = hostapd_cli_commands;
1356                 while (cmd->cmd) {
1357                         if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
1358                             0) {
1359                                 printf(" %s", cmd->cmd);
1360                         }
1361                         cmd++;
1362                 }
1363                 printf("\n");
1364         } else if (count == 0) {
1365                 printf("Unknown command '%s'\n", argv[0]);
1366         } else {
1367                 match->handler(ctrl, argc - 1, &argv[1]);
1368         }
1369 }
1370
1371
1372 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
1373                                      int action_monitor)
1374 {
1375         int first = 1;
1376         if (ctrl_conn == NULL)
1377                 return;
1378         while (wpa_ctrl_pending(ctrl)) {
1379                 char buf[256];
1380                 size_t len = sizeof(buf) - 1;
1381                 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
1382                         buf[len] = '\0';
1383                         if (action_monitor)
1384                                 hostapd_cli_action_process(buf, len);
1385                         else {
1386                                 if (in_read && first)
1387                                         printf("\n");
1388                                 first = 0;
1389                                 printf("%s\n", buf);
1390                         }
1391                 } else {
1392                         printf("Could not read pending message.\n");
1393                         break;
1394                 }
1395         }
1396 }
1397
1398
1399 #define max_args 10
1400
1401 static int tokenize_cmd(char *cmd, char *argv[])
1402 {
1403         char *pos;
1404         int argc = 0;
1405
1406         pos = cmd;
1407         for (;;) {
1408                 while (*pos == ' ')
1409                         pos++;
1410                 if (*pos == '\0')
1411                         break;
1412                 argv[argc] = pos;
1413                 argc++;
1414                 if (argc == max_args)
1415                         break;
1416                 if (*pos == '"') {
1417                         char *pos2 = os_strrchr(pos, '"');
1418                         if (pos2)
1419                                 pos = pos2 + 1;
1420                 }
1421                 while (*pos != '\0' && *pos != ' ')
1422                         pos++;
1423                 if (*pos == ' ')
1424                         *pos++ = '\0';
1425         }
1426
1427         return argc;
1428 }
1429
1430
1431 static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
1432 {
1433         if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
1434                 printf("Connection to hostapd lost - trying to reconnect\n");
1435                 hostapd_cli_close_connection();
1436         }
1437         if (!ctrl_conn) {
1438                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1439                 if (ctrl_conn) {
1440                         printf("Connection to hostapd re-established\n");
1441                         if (wpa_ctrl_attach(ctrl_conn) == 0) {
1442                                 hostapd_cli_attached = 1;
1443                         } else {
1444                                 printf("Warning: Failed to attach to "
1445                                        "hostapd.\n");
1446                         }
1447                 }
1448         }
1449         if (ctrl_conn)
1450                 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
1451         eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1452 }
1453
1454
1455 static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
1456 {
1457         eloop_terminate();
1458 }
1459
1460
1461 static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
1462 {
1463         char *argv[max_args];
1464         int argc;
1465         argc = tokenize_cmd(cmd, argv);
1466         if (argc)
1467                 wpa_request(ctrl_conn, argc, argv);
1468 }
1469
1470
1471 static void hostapd_cli_edit_eof_cb(void *ctx)
1472 {
1473         eloop_terminate();
1474 }
1475
1476
1477 static char ** list_cmd_list(void)
1478 {
1479         char **res;
1480         int i, count;
1481
1482         count = ARRAY_SIZE(hostapd_cli_commands);
1483         res = os_calloc(count + 1, sizeof(char *));
1484         if (res == NULL)
1485                 return NULL;
1486
1487         for (i = 0; hostapd_cli_commands[i].cmd; i++) {
1488                 res[i] = os_strdup(hostapd_cli_commands[i].cmd);
1489                 if (res[i] == NULL)
1490                         break;
1491         }
1492
1493         return res;
1494 }
1495
1496
1497 static char ** hostapd_cli_cmd_completion(const char *cmd, const char *str,
1498                                       int pos)
1499 {
1500         int i;
1501
1502         for (i = 0; hostapd_cli_commands[i].cmd; i++) {
1503                 if (os_strcasecmp(hostapd_cli_commands[i].cmd, cmd) != 0)
1504                         continue;
1505                 if (hostapd_cli_commands[i].completion)
1506                         return hostapd_cli_commands[i].completion(str, pos);
1507                 if (!hostapd_cli_commands[i].usage)
1508                         return NULL;
1509                 edit_clear_line();
1510                 printf("\r%s\n", hostapd_cli_commands[i].usage);
1511                 edit_redraw();
1512                 break;
1513         }
1514
1515         return NULL;
1516 }
1517
1518
1519 static char ** hostapd_cli_edit_completion_cb(void *ctx, const char *str,
1520                                               int pos)
1521 {
1522         char **res;
1523         const char *end;
1524         char *cmd;
1525
1526         end = os_strchr(str, ' ');
1527         if (end == NULL || str + pos < end)
1528                 return list_cmd_list();
1529
1530         cmd = os_malloc(pos + 1);
1531         if (cmd == NULL)
1532                 return NULL;
1533         os_memcpy(cmd, str, pos);
1534         cmd[end - str] = '\0';
1535         res = hostapd_cli_cmd_completion(cmd, str, pos);
1536         os_free(cmd);
1537         return res;
1538 }
1539
1540
1541 static void hostapd_cli_interactive(void)
1542 {
1543         printf("\nInteractive mode\n\n");
1544
1545         eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
1546         edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
1547                   hostapd_cli_edit_completion_cb, NULL, NULL, NULL);
1548         eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1549
1550         eloop_run();
1551
1552         edit_deinit(NULL, NULL);
1553         eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
1554 }
1555
1556
1557 static void hostapd_cli_cleanup(void)
1558 {
1559         hostapd_cli_close_connection();
1560         if (pid_file)
1561                 os_daemonize_terminate(pid_file);
1562
1563         os_program_deinit();
1564 }
1565
1566
1567 static void hostapd_cli_action(struct wpa_ctrl *ctrl)
1568 {
1569         fd_set rfds;
1570         int fd, res;
1571         struct timeval tv;
1572         char buf[256];
1573         size_t len;
1574
1575         fd = wpa_ctrl_get_fd(ctrl);
1576
1577         while (!hostapd_cli_quit) {
1578                 FD_ZERO(&rfds);
1579                 FD_SET(fd, &rfds);
1580                 tv.tv_sec = ping_interval;
1581                 tv.tv_usec = 0;
1582                 res = select(fd + 1, &rfds, NULL, NULL, &tv);
1583                 if (res < 0 && errno != EINTR) {
1584                         perror("select");
1585                         break;
1586                 }
1587
1588                 if (FD_ISSET(fd, &rfds))
1589                         hostapd_cli_recv_pending(ctrl, 0, 1);
1590                 else {
1591                         len = sizeof(buf) - 1;
1592                         if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1593                                              hostapd_cli_action_process) < 0 ||
1594                             len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
1595                                 printf("hostapd did not reply to PING "
1596                                        "command - exiting\n");
1597                                 break;
1598                         }
1599                 }
1600         }
1601 }
1602
1603
1604 int main(int argc, char *argv[])
1605 {
1606         int warning_displayed = 0;
1607         int c;
1608         int daemonize = 0;
1609
1610         if (os_program_init())
1611                 return -1;
1612
1613         for (;;) {
1614                 c = getopt(argc, argv, "a:BhG:i:p:P:s:v");
1615                 if (c < 0)
1616                         break;
1617                 switch (c) {
1618                 case 'a':
1619                         action_file = optarg;
1620                         break;
1621                 case 'B':
1622                         daemonize = 1;
1623                         break;
1624                 case 'G':
1625                         ping_interval = atoi(optarg);
1626                         break;
1627                 case 'h':
1628                         usage();
1629                         return 0;
1630                 case 'v':
1631                         printf("%s\n", hostapd_cli_version);
1632                         return 0;
1633                 case 'i':
1634                         os_free(ctrl_ifname);
1635                         ctrl_ifname = os_strdup(optarg);
1636                         break;
1637                 case 'p':
1638                         ctrl_iface_dir = optarg;
1639                         break;
1640                 case 'P':
1641                         pid_file = optarg;
1642                         break;
1643                 case 's':
1644                         client_socket_dir = optarg;
1645                         break;
1646                 default:
1647                         usage();
1648                         return -1;
1649                 }
1650         }
1651
1652         interactive = (argc == optind) && (action_file == NULL);
1653
1654         if (interactive) {
1655                 printf("%s\n\n%s\n\n", hostapd_cli_version,
1656                        hostapd_cli_license);
1657         }
1658
1659         if (eloop_init())
1660                 return -1;
1661
1662         for (;;) {
1663                 if (ctrl_ifname == NULL) {
1664                         struct dirent *dent;
1665                         DIR *dir = opendir(ctrl_iface_dir);
1666                         if (dir) {
1667                                 while ((dent = readdir(dir))) {
1668                                         if (os_strcmp(dent->d_name, ".") == 0
1669                                             ||
1670                                             os_strcmp(dent->d_name, "..") == 0)
1671                                                 continue;
1672                                         printf("Selected interface '%s'\n",
1673                                                dent->d_name);
1674                                         ctrl_ifname = os_strdup(dent->d_name);
1675                                         break;
1676                                 }
1677                                 closedir(dir);
1678                         }
1679                 }
1680                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1681                 if (ctrl_conn) {
1682                         if (warning_displayed)
1683                                 printf("Connection established.\n");
1684                         break;
1685                 }
1686
1687                 if (!interactive) {
1688                         perror("Failed to connect to hostapd - "
1689                                "wpa_ctrl_open");
1690                         return -1;
1691                 }
1692
1693                 if (!warning_displayed) {
1694                         printf("Could not connect to hostapd - re-trying\n");
1695                         warning_displayed = 1;
1696                 }
1697                 os_sleep(1, 0);
1698                 continue;
1699         }
1700
1701         if (interactive || action_file) {
1702                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1703                         hostapd_cli_attached = 1;
1704                 } else {
1705                         printf("Warning: Failed to attach to hostapd.\n");
1706                         if (action_file)
1707                                 return -1;
1708                 }
1709         }
1710
1711         if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
1712                 return -1;
1713
1714         if (interactive)
1715                 hostapd_cli_interactive();
1716         else if (action_file)
1717                 hostapd_cli_action(ctrl_conn);
1718         else
1719                 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1720
1721         os_free(ctrl_ifname);
1722         eloop_destroy();
1723         hostapd_cli_cleanup();
1724         return 0;
1725 }
1726
1727 #else /* CONFIG_NO_CTRL_IFACE */
1728
1729 int main(int argc, char *argv[])
1730 {
1731         return -1;
1732 }
1733
1734 #endif /* CONFIG_NO_CTRL_IFACE */