4f22e853cc3f0488470b98b6ab1e5c0676be6a1c
[libeap.git] / hostapd / hostapd_cli.c
1 /*
2  * hostapd - command line interface for hostapd daemon
3  * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include "includes.h"
16 #include <dirent.h>
17
18 #include "common/wpa_ctrl.h"
19 #include "common.h"
20 #include "common/version.h"
21
22
23 static const char *hostapd_cli_version =
24 "hostapd_cli v" VERSION_STR "\n"
25 "Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi> and contributors";
26
27
28 static const char *hostapd_cli_license =
29 "This program is free software. You can distribute it and/or modify it\n"
30 "under the terms of the GNU General Public License version 2.\n"
31 "\n"
32 "Alternatively, this software may be distributed under the terms of the\n"
33 "BSD license. See README and COPYING for more details.\n";
34
35 static const char *hostapd_cli_full_license =
36 "This program is free software; you can redistribute it and/or modify\n"
37 "it under the terms of the GNU General Public License version 2 as\n"
38 "published by the Free Software Foundation.\n"
39 "\n"
40 "This program is distributed in the hope that it will be useful,\n"
41 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
42 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
43 "GNU General Public License for more details.\n"
44 "\n"
45 "You should have received a copy of the GNU General Public License\n"
46 "along with this program; if not, write to the Free Software\n"
47 "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n"
48 "\n"
49 "Alternatively, this software may be distributed under the terms of the\n"
50 "BSD license.\n"
51 "\n"
52 "Redistribution and use in source and binary forms, with or without\n"
53 "modification, are permitted provided that the following conditions are\n"
54 "met:\n"
55 "\n"
56 "1. Redistributions of source code must retain the above copyright\n"
57 "   notice, this list of conditions and the following disclaimer.\n"
58 "\n"
59 "2. Redistributions in binary form must reproduce the above copyright\n"
60 "   notice, this list of conditions and the following disclaimer in the\n"
61 "   documentation and/or other materials provided with the distribution.\n"
62 "\n"
63 "3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
64 "   names of its contributors may be used to endorse or promote products\n"
65 "   derived from this software without specific prior written permission.\n"
66 "\n"
67 "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
68 "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
69 "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
70 "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
71 "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
72 "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
73 "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
74 "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
75 "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
76 "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
77 "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
78 "\n";
79
80 static const char *commands_help =
81 "Commands:\n"
82 "   mib                  get MIB variables (dot1x, dot11, radius)\n"
83 "   sta <addr>           get MIB variables for one station\n"
84 "   all_sta              get MIB variables for all stations\n"
85 "   new_sta <addr>       add a new station\n"
86 "   deauthenticate <addr>  deauthenticate a station\n"
87 "   disassociate <addr>  disassociate a station\n"
88 #ifdef CONFIG_IEEE80211W
89 "   sa_query <addr>      send SA Query to a station\n"
90 #endif /* CONFIG_IEEE80211W */
91 #ifdef CONFIG_WPS
92 "   wps_pin <uuid> <pin> [timeout] [addr]  add WPS Enrollee PIN\n"
93 "   wps_pbc              indicate button pushed to initiate PBC\n"
94 #ifdef CONFIG_WPS_OOB
95 "   wps_oob <type> <path> <method>  use WPS with out-of-band (UFD)\n"
96 #endif /* CONFIG_WPS_OOB */
97 "   wps_ap_pin <cmd> [params..]  enable/disable AP PIN\n"
98 #endif /* CONFIG_WPS */
99 "   help                 show this usage help\n"
100 "   interface [ifname]   show interfaces/select interface\n"
101 "   level <debug level>  change debug level\n"
102 "   license              show full hostapd_cli license\n"
103 "   quit                 exit hostapd_cli\n";
104
105 static struct wpa_ctrl *ctrl_conn;
106 static int hostapd_cli_quit = 0;
107 static int hostapd_cli_attached = 0;
108 static const char *ctrl_iface_dir = "/var/run/hostapd";
109 static char *ctrl_ifname = NULL;
110 static const char *pid_file = NULL;
111 static const char *action_file = NULL;
112 static int ping_interval = 5;
113
114
115 static void usage(void)
116 {
117         fprintf(stderr, "%s\n", hostapd_cli_version);
118         fprintf(stderr,
119                 "\n"
120                 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
121                 "[-a<path>] \\\n"
122                 "                   [-G<ping interval>] [command..]\n"
123                 "\n"
124                 "Options:\n"
125                 "   -h           help (show this usage text)\n"
126                 "   -v           shown version information\n"
127                 "   -p<path>     path to find control sockets (default: "
128                 "/var/run/hostapd)\n"
129                 "   -a<file>     run in daemon mode executing the action file "
130                 "based on events\n"
131                 "                from hostapd\n"
132                 "   -B           run a daemon in the background\n"
133                 "   -i<ifname>   Interface to listen on (default: first "
134                 "interface found in the\n"
135                 "                socket path)\n\n"
136                 "%s",
137                 commands_help);
138 }
139
140
141 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
142 {
143         char *cfile;
144         int flen;
145
146         if (ifname == NULL)
147                 return NULL;
148
149         flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
150         cfile = malloc(flen);
151         if (cfile == NULL)
152                 return NULL;
153         snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
154
155         ctrl_conn = wpa_ctrl_open(cfile);
156         free(cfile);
157         return ctrl_conn;
158 }
159
160
161 static void hostapd_cli_close_connection(void)
162 {
163         if (ctrl_conn == NULL)
164                 return;
165
166         if (hostapd_cli_attached) {
167                 wpa_ctrl_detach(ctrl_conn);
168                 hostapd_cli_attached = 0;
169         }
170         wpa_ctrl_close(ctrl_conn);
171         ctrl_conn = NULL;
172 }
173
174
175 static void hostapd_cli_msg_cb(char *msg, size_t len)
176 {
177         printf("%s\n", msg);
178 }
179
180
181 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
182 {
183         char buf[4096];
184         size_t len;
185         int ret;
186
187         if (ctrl_conn == NULL) {
188                 printf("Not connected to hostapd - command dropped.\n");
189                 return -1;
190         }
191         len = sizeof(buf) - 1;
192         ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
193                                hostapd_cli_msg_cb);
194         if (ret == -2) {
195                 printf("'%s' command timed out.\n", cmd);
196                 return -2;
197         } else if (ret < 0) {
198                 printf("'%s' command failed.\n", cmd);
199                 return -1;
200         }
201         if (print) {
202                 buf[len] = '\0';
203                 printf("%s", buf);
204         }
205         return 0;
206 }
207
208
209 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
210 {
211         return _wpa_ctrl_command(ctrl, cmd, 1);
212 }
213
214
215 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
216 {
217         return wpa_ctrl_command(ctrl, "PING");
218 }
219
220
221 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
222 {
223         return wpa_ctrl_command(ctrl, "MIB");
224 }
225
226
227 static int hostapd_cli_exec(const char *program, const char *arg1,
228                             const char *arg2)
229 {
230         char *cmd;
231         size_t len;
232         int res;
233         int ret = 0;
234
235         len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
236         cmd = os_malloc(len);
237         if (cmd == NULL)
238                 return -1;
239         res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
240         if (res < 0 || (size_t) res >= len) {
241                 os_free(cmd);
242                 return -1;
243         }
244         cmd[len - 1] = '\0';
245 #ifndef _WIN32_WCE
246         if (system(cmd) < 0)
247                 ret = -1;
248 #endif /* _WIN32_WCE */
249         os_free(cmd);
250
251         return ret;
252 }
253
254
255 static void hostapd_cli_action_process(char *msg, size_t len)
256 {
257         const char *pos;
258
259         pos = msg;
260         if (*pos == '<') {
261                 pos = os_strchr(pos, '>');
262                 if (pos)
263                         pos++;
264                 else
265                         pos = msg;
266         }
267
268         hostapd_cli_exec(action_file, ctrl_ifname, pos);
269 }
270
271
272 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
273 {
274         char buf[64];
275         if (argc != 1) {
276                 printf("Invalid 'sta' command - exactly one argument, STA "
277                        "address, is required.\n");
278                 return -1;
279         }
280         snprintf(buf, sizeof(buf), "STA %s", argv[0]);
281         return wpa_ctrl_command(ctrl, buf);
282 }
283
284
285 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
286                                    char *argv[])
287 {
288         char buf[64];
289         if (argc != 1) {
290                 printf("Invalid 'new_sta' command - exactly one argument, STA "
291                        "address, is required.\n");
292                 return -1;
293         }
294         snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
295         return wpa_ctrl_command(ctrl, buf);
296 }
297
298
299 static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
300                                           char *argv[])
301 {
302         char buf[64];
303         if (argc < 1) {
304                 printf("Invalid 'deauthenticate' command - exactly one "
305                        "argument, STA address, is required.\n");
306                 return -1;
307         }
308         if (argc > 1)
309                 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
310                             argv[0], argv[1]);
311         else
312                 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
313         return wpa_ctrl_command(ctrl, buf);
314 }
315
316
317 static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
318                                         char *argv[])
319 {
320         char buf[64];
321         if (argc < 1) {
322                 printf("Invalid 'disassociate' command - exactly one "
323                        "argument, STA address, is required.\n");
324                 return -1;
325         }
326         if (argc > 1)
327                 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
328                             argv[0], argv[1]);
329         else
330                 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
331         return wpa_ctrl_command(ctrl, buf);
332 }
333
334
335 #ifdef CONFIG_IEEE80211W
336 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
337                                     char *argv[])
338 {
339         char buf[64];
340         if (argc != 1) {
341                 printf("Invalid 'sa_query' command - exactly one argument, "
342                        "STA address, is required.\n");
343                 return -1;
344         }
345         snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
346         return wpa_ctrl_command(ctrl, buf);
347 }
348 #endif /* CONFIG_IEEE80211W */
349
350
351 #ifdef CONFIG_WPS
352 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
353                                    char *argv[])
354 {
355         char buf[256];
356         if (argc < 2) {
357                 printf("Invalid 'wps_pin' command - at least two arguments, "
358                        "UUID and PIN, are required.\n");
359                 return -1;
360         }
361         if (argc > 3)
362                 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
363                          argv[0], argv[1], argv[2], argv[3]);
364         else if (argc > 2)
365                 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
366                          argv[0], argv[1], argv[2]);
367         else
368                 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
369         return wpa_ctrl_command(ctrl, buf);
370 }
371
372
373 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
374                                    char *argv[])
375 {
376         return wpa_ctrl_command(ctrl, "WPS_PBC");
377 }
378
379
380 #ifdef CONFIG_WPS_OOB
381 static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
382                                    char *argv[])
383 {
384         char cmd[256];
385         int res;
386
387         if (argc != 3 && argc != 4) {
388                 printf("Invalid WPS_OOB command: need three or four "
389                        "arguments:\n"
390                        "- DEV_TYPE: use 'ufd' or 'nfc'\n"
391                        "- PATH: path of OOB device like '/mnt'\n"
392                        "- METHOD: OOB method 'pin-e' or 'pin-r', "
393                        "'cred'\n"
394                        "- DEV_NAME: (only for NFC) device name like "
395                        "'pn531'\n");
396                 return -1;
397         }
398
399         if (argc == 3)
400                 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
401                                   argv[0], argv[1], argv[2]);
402         else
403                 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
404                                   argv[0], argv[1], argv[2], argv[3]);
405         if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
406                 printf("Too long WPS_OOB command.\n");
407                 return -1;
408         }
409         return wpa_ctrl_command(ctrl, cmd);
410 }
411 #endif /* CONFIG_WPS_OOB */
412
413
414 static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
415                                       char *argv[])
416 {
417         char buf[64];
418         if (argc < 1) {
419                 printf("Invalid 'wps_ap_pin' command - at least one argument "
420                        "is required.\n");
421                 return -1;
422         }
423         if (argc > 2)
424                 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
425                          argv[0], argv[1], argv[2]);
426         else if (argc > 1)
427                 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
428                          argv[0], argv[1]);
429         else
430                 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
431         return wpa_ctrl_command(ctrl, buf);
432 }
433 #endif /* CONFIG_WPS */
434
435
436 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
437                                 char *addr, size_t addr_len)
438 {
439         char buf[4096], *pos;
440         size_t len;
441         int ret;
442
443         if (ctrl_conn == NULL) {
444                 printf("Not connected to hostapd - command dropped.\n");
445                 return -1;
446         }
447         len = sizeof(buf) - 1;
448         ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
449                                hostapd_cli_msg_cb);
450         if (ret == -2) {
451                 printf("'%s' command timed out.\n", cmd);
452                 return -2;
453         } else if (ret < 0) {
454                 printf("'%s' command failed.\n", cmd);
455                 return -1;
456         }
457
458         buf[len] = '\0';
459         if (memcmp(buf, "FAIL", 4) == 0)
460                 return -1;
461         printf("%s", buf);
462
463         pos = buf;
464         while (*pos != '\0' && *pos != '\n')
465                 pos++;
466         *pos = '\0';
467         os_strlcpy(addr, buf, addr_len);
468         return 0;
469 }
470
471
472 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
473                                    char *argv[])
474 {
475         char addr[32], cmd[64];
476
477         if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
478                 return 0;
479         do {
480                 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
481         } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
482
483         return -1;
484 }
485
486
487 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
488 {
489         printf("%s", commands_help);
490         return 0;
491 }
492
493
494 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
495                                    char *argv[])
496 {
497         printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
498         return 0;
499 }
500
501
502 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
503 {
504         hostapd_cli_quit = 1;
505         return 0;
506 }
507
508
509 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
510 {
511         char cmd[256];
512         if (argc != 1) {
513                 printf("Invalid LEVEL command: needs one argument (debug "
514                        "level)\n");
515                 return 0;
516         }
517         snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
518         return wpa_ctrl_command(ctrl, cmd);
519 }
520
521
522 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
523 {
524         struct dirent *dent;
525         DIR *dir;
526
527         dir = opendir(ctrl_iface_dir);
528         if (dir == NULL) {
529                 printf("Control interface directory '%s' could not be "
530                        "openned.\n", ctrl_iface_dir);
531                 return;
532         }
533
534         printf("Available interfaces:\n");
535         while ((dent = readdir(dir))) {
536                 if (strcmp(dent->d_name, ".") == 0 ||
537                     strcmp(dent->d_name, "..") == 0)
538                         continue;
539                 printf("%s\n", dent->d_name);
540         }
541         closedir(dir);
542 }
543
544
545 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
546                                      char *argv[])
547 {
548         if (argc < 1) {
549                 hostapd_cli_list_interfaces(ctrl);
550                 return 0;
551         }
552
553         hostapd_cli_close_connection();
554         free(ctrl_ifname);
555         ctrl_ifname = strdup(argv[0]);
556
557         if (hostapd_cli_open_connection(ctrl_ifname)) {
558                 printf("Connected to interface '%s.\n", ctrl_ifname);
559                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
560                         hostapd_cli_attached = 1;
561                 } else {
562                         printf("Warning: Failed to attach to "
563                                "hostapd.\n");
564                 }
565         } else {
566                 printf("Could not connect to interface '%s' - re-trying\n",
567                         ctrl_ifname);
568         }
569         return 0;
570 }
571
572
573 struct hostapd_cli_cmd {
574         const char *cmd;
575         int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
576 };
577
578 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
579         { "ping", hostapd_cli_cmd_ping },
580         { "mib", hostapd_cli_cmd_mib },
581         { "sta", hostapd_cli_cmd_sta },
582         { "all_sta", hostapd_cli_cmd_all_sta },
583         { "new_sta", hostapd_cli_cmd_new_sta },
584         { "deauthenticate", hostapd_cli_cmd_deauthenticate },
585         { "disassociate", hostapd_cli_cmd_disassociate },
586 #ifdef CONFIG_IEEE80211W
587         { "sa_query", hostapd_cli_cmd_sa_query },
588 #endif /* CONFIG_IEEE80211W */
589 #ifdef CONFIG_WPS
590         { "wps_pin", hostapd_cli_cmd_wps_pin },
591         { "wps_pbc", hostapd_cli_cmd_wps_pbc },
592 #ifdef CONFIG_WPS_OOB
593         { "wps_oob", hostapd_cli_cmd_wps_oob },
594 #endif /* CONFIG_WPS_OOB */
595         { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
596 #endif /* CONFIG_WPS */
597         { "help", hostapd_cli_cmd_help },
598         { "interface", hostapd_cli_cmd_interface },
599         { "level", hostapd_cli_cmd_level },
600         { "license", hostapd_cli_cmd_license },
601         { "quit", hostapd_cli_cmd_quit },
602         { NULL, NULL }
603 };
604
605
606 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
607 {
608         struct hostapd_cli_cmd *cmd, *match = NULL;
609         int count;
610
611         count = 0;
612         cmd = hostapd_cli_commands;
613         while (cmd->cmd) {
614                 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
615                         match = cmd;
616                         count++;
617                 }
618                 cmd++;
619         }
620
621         if (count > 1) {
622                 printf("Ambiguous command '%s'; possible commands:", argv[0]);
623                 cmd = hostapd_cli_commands;
624                 while (cmd->cmd) {
625                         if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
626                             0) {
627                                 printf(" %s", cmd->cmd);
628                         }
629                         cmd++;
630                 }
631                 printf("\n");
632         } else if (count == 0) {
633                 printf("Unknown command '%s'\n", argv[0]);
634         } else {
635                 match->handler(ctrl, argc - 1, &argv[1]);
636         }
637 }
638
639
640 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
641                                      int action_monitor)
642 {
643         int first = 1;
644         if (ctrl_conn == NULL)
645                 return;
646         while (wpa_ctrl_pending(ctrl)) {
647                 char buf[256];
648                 size_t len = sizeof(buf) - 1;
649                 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
650                         buf[len] = '\0';
651                         if (action_monitor)
652                                 hostapd_cli_action_process(buf, len);
653                         else {
654                                 if (in_read && first)
655                                         printf("\n");
656                                 first = 0;
657                                 printf("%s\n", buf);
658                         }
659                 } else {
660                         printf("Could not read pending message.\n");
661                         break;
662                 }
663         }
664 }
665
666
667 static void hostapd_cli_interactive(void)
668 {
669         const int max_args = 10;
670         char cmd[256], *res, *argv[max_args], *pos;
671         int argc;
672
673         printf("\nInteractive mode\n\n");
674
675         do {
676                 hostapd_cli_recv_pending(ctrl_conn, 0, 0);
677                 printf("> ");
678                 alarm(ping_interval);
679                 res = fgets(cmd, sizeof(cmd), stdin);
680                 alarm(0);
681                 if (res == NULL)
682                         break;
683                 pos = cmd;
684                 while (*pos != '\0') {
685                         if (*pos == '\n') {
686                                 *pos = '\0';
687                                 break;
688                         }
689                         pos++;
690                 }
691                 argc = 0;
692                 pos = cmd;
693                 for (;;) {
694                         while (*pos == ' ')
695                                 pos++;
696                         if (*pos == '\0')
697                                 break;
698                         argv[argc] = pos;
699                         argc++;
700                         if (argc == max_args)
701                                 break;
702                         while (*pos != '\0' && *pos != ' ')
703                                 pos++;
704                         if (*pos == ' ')
705                                 *pos++ = '\0';
706                 }
707                 if (argc)
708                         wpa_request(ctrl_conn, argc, argv);
709         } while (!hostapd_cli_quit);
710 }
711
712
713 static void hostapd_cli_cleanup(void)
714 {
715         hostapd_cli_close_connection();
716         if (pid_file)
717                 os_daemonize_terminate(pid_file);
718
719         os_program_deinit();
720 }
721
722
723 static void hostapd_cli_terminate(int sig)
724 {
725         hostapd_cli_cleanup();
726         exit(0);
727 }
728
729
730 static void hostapd_cli_alarm(int sig)
731 {
732         if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
733                 printf("Connection to hostapd lost - trying to reconnect\n");
734                 hostapd_cli_close_connection();
735         }
736         if (!ctrl_conn) {
737                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
738                 if (ctrl_conn) {
739                         printf("Connection to hostapd re-established\n");
740                         if (wpa_ctrl_attach(ctrl_conn) == 0) {
741                                 hostapd_cli_attached = 1;
742                         } else {
743                                 printf("Warning: Failed to attach to "
744                                        "hostapd.\n");
745                         }
746                 }
747         }
748         if (ctrl_conn)
749                 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
750         alarm(ping_interval);
751 }
752
753
754 static void hostapd_cli_action(struct wpa_ctrl *ctrl)
755 {
756         fd_set rfds;
757         int fd, res;
758         struct timeval tv;
759         char buf[256];
760         size_t len;
761
762         fd = wpa_ctrl_get_fd(ctrl);
763
764         while (!hostapd_cli_quit) {
765                 FD_ZERO(&rfds);
766                 FD_SET(fd, &rfds);
767                 tv.tv_sec = ping_interval;
768                 tv.tv_usec = 0;
769                 res = select(fd + 1, &rfds, NULL, NULL, &tv);
770                 if (res < 0 && errno != EINTR) {
771                         perror("select");
772                         break;
773                 }
774
775                 if (FD_ISSET(fd, &rfds))
776                         hostapd_cli_recv_pending(ctrl, 0, 1);
777                 else {
778                         len = sizeof(buf) - 1;
779                         if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
780                                              hostapd_cli_action_process) < 0 ||
781                             len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
782                                 printf("hostapd did not reply to PING "
783                                        "command - exiting\n");
784                                 break;
785                         }
786                 }
787         }
788 }
789
790
791 int main(int argc, char *argv[])
792 {
793         int interactive;
794         int warning_displayed = 0;
795         int c;
796         int daemonize = 0;
797
798         if (os_program_init())
799                 return -1;
800
801         for (;;) {
802                 c = getopt(argc, argv, "a:BhG:i:p:v");
803                 if (c < 0)
804                         break;
805                 switch (c) {
806                 case 'a':
807                         action_file = optarg;
808                         break;
809                 case 'B':
810                         daemonize = 1;
811                         break;
812                 case 'G':
813                         ping_interval = atoi(optarg);
814                         break;
815                 case 'h':
816                         usage();
817                         return 0;
818                 case 'v':
819                         printf("%s\n", hostapd_cli_version);
820                         return 0;
821                 case 'i':
822                         os_free(ctrl_ifname);
823                         ctrl_ifname = os_strdup(optarg);
824                         break;
825                 case 'p':
826                         ctrl_iface_dir = optarg;
827                         break;
828                 default:
829                         usage();
830                         return -1;
831                 }
832         }
833
834         interactive = (argc == optind) && (action_file == NULL);
835
836         if (interactive) {
837                 printf("%s\n\n%s\n\n", hostapd_cli_version,
838                        hostapd_cli_license);
839         }
840
841         for (;;) {
842                 if (ctrl_ifname == NULL) {
843                         struct dirent *dent;
844                         DIR *dir = opendir(ctrl_iface_dir);
845                         if (dir) {
846                                 while ((dent = readdir(dir))) {
847                                         if (os_strcmp(dent->d_name, ".") == 0
848                                             ||
849                                             os_strcmp(dent->d_name, "..") == 0)
850                                                 continue;
851                                         printf("Selected interface '%s'\n",
852                                                dent->d_name);
853                                         ctrl_ifname = os_strdup(dent->d_name);
854                                         break;
855                                 }
856                                 closedir(dir);
857                         }
858                 }
859                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
860                 if (ctrl_conn) {
861                         if (warning_displayed)
862                                 printf("Connection established.\n");
863                         break;
864                 }
865
866                 if (!interactive) {
867                         perror("Failed to connect to hostapd - "
868                                "wpa_ctrl_open");
869                         return -1;
870                 }
871
872                 if (!warning_displayed) {
873                         printf("Could not connect to hostapd - re-trying\n");
874                         warning_displayed = 1;
875                 }
876                 os_sleep(1, 0);
877                 continue;
878         }
879
880         signal(SIGINT, hostapd_cli_terminate);
881         signal(SIGTERM, hostapd_cli_terminate);
882         signal(SIGALRM, hostapd_cli_alarm);
883
884         if (interactive || action_file) {
885                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
886                         hostapd_cli_attached = 1;
887                 } else {
888                         printf("Warning: Failed to attach to hostapd.\n");
889                         if (action_file)
890                                 return -1;
891                 }
892         }
893
894         if (daemonize && os_daemonize(pid_file))
895                 return -1;
896
897         if (interactive)
898                 hostapd_cli_interactive();
899         else if (action_file)
900                 hostapd_cli_action(ctrl_conn);
901         else
902                 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
903
904         os_free(ctrl_ifname);
905         hostapd_cli_cleanup();
906         return 0;
907 }