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