hostapd_cli: Add deauth/disassoc commands to usage help
[mech_eap.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]  add WPS Enrollee PIN (Device Password)\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 #endif /* CONFIG_WPS */
98 "   help                 show this usage help\n"
99 "   interface [ifname]   show interfaces/select interface\n"
100 "   level <debug level>  change debug level\n"
101 "   license              show full hostapd_cli license\n"
102 "   quit                 exit hostapd_cli\n";
103
104 static struct wpa_ctrl *ctrl_conn;
105 static int hostapd_cli_quit = 0;
106 static int hostapd_cli_attached = 0;
107 static const char *ctrl_iface_dir = "/var/run/hostapd";
108 static char *ctrl_ifname = NULL;
109 static const char *pid_file = NULL;
110 static const char *action_file = NULL;
111 static int ping_interval = 5;
112
113
114 static void usage(void)
115 {
116         fprintf(stderr, "%s\n", hostapd_cli_version);
117         fprintf(stderr,
118                 "\n"
119                 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
120                 "[-a<path>] \\\n"
121                 "                   [-G<ping interval>] [command..]\n"
122                 "\n"
123                 "Options:\n"
124                 "   -h           help (show this usage text)\n"
125                 "   -v           shown version information\n"
126                 "   -p<path>     path to find control sockets (default: "
127                 "/var/run/hostapd)\n"
128                 "   -a<file>     run in daemon mode executing the action file "
129                 "based on events\n"
130                 "                from hostapd\n"
131                 "   -B           run a daemon in the background\n"
132                 "   -i<ifname>   Interface to listen on (default: first "
133                 "interface found in the\n"
134                 "                socket path)\n\n"
135                 "%s",
136                 commands_help);
137 }
138
139
140 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
141 {
142         char *cfile;
143         int flen;
144
145         if (ifname == NULL)
146                 return NULL;
147
148         flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
149         cfile = malloc(flen);
150         if (cfile == NULL)
151                 return NULL;
152         snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
153
154         ctrl_conn = wpa_ctrl_open(cfile);
155         free(cfile);
156         return ctrl_conn;
157 }
158
159
160 static void hostapd_cli_close_connection(void)
161 {
162         if (ctrl_conn == NULL)
163                 return;
164
165         if (hostapd_cli_attached) {
166                 wpa_ctrl_detach(ctrl_conn);
167                 hostapd_cli_attached = 0;
168         }
169         wpa_ctrl_close(ctrl_conn);
170         ctrl_conn = NULL;
171 }
172
173
174 static void hostapd_cli_msg_cb(char *msg, size_t len)
175 {
176         printf("%s\n", msg);
177 }
178
179
180 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
181 {
182         char buf[4096];
183         size_t len;
184         int ret;
185
186         if (ctrl_conn == NULL) {
187                 printf("Not connected to hostapd - command dropped.\n");
188                 return -1;
189         }
190         len = sizeof(buf) - 1;
191         ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
192                                hostapd_cli_msg_cb);
193         if (ret == -2) {
194                 printf("'%s' command timed out.\n", cmd);
195                 return -2;
196         } else if (ret < 0) {
197                 printf("'%s' command failed.\n", cmd);
198                 return -1;
199         }
200         if (print) {
201                 buf[len] = '\0';
202                 printf("%s", buf);
203         }
204         return 0;
205 }
206
207
208 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
209 {
210         return _wpa_ctrl_command(ctrl, cmd, 1);
211 }
212
213
214 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
215 {
216         return wpa_ctrl_command(ctrl, "PING");
217 }
218
219
220 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
221 {
222         return wpa_ctrl_command(ctrl, "MIB");
223 }
224
225
226 static int hostapd_cli_exec(const char *program, const char *arg1,
227                             const char *arg2)
228 {
229         char *cmd;
230         size_t len;
231         int res;
232         int ret = 0;
233
234         len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
235         cmd = os_malloc(len);
236         if (cmd == NULL)
237                 return -1;
238         res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
239         if (res < 0 || (size_t) res >= len) {
240                 os_free(cmd);
241                 return -1;
242         }
243         cmd[len - 1] = '\0';
244 #ifndef _WIN32_WCE
245         if (system(cmd) < 0)
246                 ret = -1;
247 #endif /* _WIN32_WCE */
248         os_free(cmd);
249
250         return ret;
251 }
252
253
254 static void hostapd_cli_action_process(char *msg, size_t len)
255 {
256         const char *pos;
257
258         pos = msg;
259         if (*pos == '<') {
260                 pos = os_strchr(pos, '>');
261                 if (pos)
262                         pos++;
263                 else
264                         pos = msg;
265         }
266
267         hostapd_cli_exec(action_file, ctrl_ifname, pos);
268 }
269
270
271 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
272 {
273         char buf[64];
274         if (argc != 1) {
275                 printf("Invalid 'sta' command - exactly one argument, STA "
276                        "address, is required.\n");
277                 return -1;
278         }
279         snprintf(buf, sizeof(buf), "STA %s", argv[0]);
280         return wpa_ctrl_command(ctrl, buf);
281 }
282
283
284 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
285                                    char *argv[])
286 {
287         char buf[64];
288         if (argc != 1) {
289                 printf("Invalid 'new_sta' command - exactly one argument, STA "
290                        "address, is required.\n");
291                 return -1;
292         }
293         snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
294         return wpa_ctrl_command(ctrl, buf);
295 }
296
297
298 static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
299                                           char *argv[])
300 {
301         char buf[64];
302         if (argc < 1) {
303                 printf("Invalid 'deauthenticate' command - exactly one "
304                        "argument, STA address, is required.\n");
305                 return -1;
306         }
307         if (argc > 1)
308                 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
309                             argv[0], argv[1]);
310         else
311                 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
312         return wpa_ctrl_command(ctrl, buf);
313 }
314
315
316 static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
317                                         char *argv[])
318 {
319         char buf[64];
320         if (argc < 1) {
321                 printf("Invalid 'disassociate' command - exactly one "
322                        "argument, STA address, is required.\n");
323                 return -1;
324         }
325         if (argc > 1)
326                 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
327                             argv[0], argv[1]);
328         else
329                 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
330         return wpa_ctrl_command(ctrl, buf);
331 }
332
333
334 #ifdef CONFIG_IEEE80211W
335 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
336                                     char *argv[])
337 {
338         char buf[64];
339         if (argc != 1) {
340                 printf("Invalid 'sa_query' command - exactly one argument, "
341                        "STA address, is required.\n");
342                 return -1;
343         }
344         snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
345         return wpa_ctrl_command(ctrl, buf);
346 }
347 #endif /* CONFIG_IEEE80211W */
348
349
350 #ifdef CONFIG_WPS
351 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
352                                    char *argv[])
353 {
354         char buf[64];
355         if (argc < 2) {
356                 printf("Invalid 'wps_pin' command - at least two arguments, "
357                        "UUID and PIN, are required.\n");
358                 return -1;
359         }
360         if (argc > 2)
361                 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
362                          argv[0], argv[1], argv[2]);
363         else
364                 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
365         return wpa_ctrl_command(ctrl, buf);
366 }
367
368
369 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
370                                    char *argv[])
371 {
372         return wpa_ctrl_command(ctrl, "WPS_PBC");
373 }
374
375
376 #ifdef CONFIG_WPS_OOB
377 static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
378                                    char *argv[])
379 {
380         char cmd[256];
381         int res;
382
383         if (argc != 3 && argc != 4) {
384                 printf("Invalid WPS_OOB command: need three or four "
385                        "arguments:\n"
386                        "- DEV_TYPE: use 'ufd' or 'nfc'\n"
387                        "- PATH: path of OOB device like '/mnt'\n"
388                        "- METHOD: OOB method 'pin-e' or 'pin-r', "
389                        "'cred'\n"
390                        "- DEV_NAME: (only for NFC) device name like "
391                        "'pn531'\n");
392                 return -1;
393         }
394
395         if (argc == 3)
396                 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
397                                   argv[0], argv[1], argv[2]);
398         else
399                 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
400                                   argv[0], argv[1], argv[2], argv[3]);
401         if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
402                 printf("Too long WPS_OOB command.\n");
403                 return -1;
404         }
405         return wpa_ctrl_command(ctrl, cmd);
406 }
407 #endif /* CONFIG_WPS_OOB */
408 #endif /* CONFIG_WPS */
409
410
411 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
412                                 char *addr, size_t addr_len)
413 {
414         char buf[4096], *pos;
415         size_t len;
416         int ret;
417
418         if (ctrl_conn == NULL) {
419                 printf("Not connected to hostapd - command dropped.\n");
420                 return -1;
421         }
422         len = sizeof(buf) - 1;
423         ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
424                                hostapd_cli_msg_cb);
425         if (ret == -2) {
426                 printf("'%s' command timed out.\n", cmd);
427                 return -2;
428         } else if (ret < 0) {
429                 printf("'%s' command failed.\n", cmd);
430                 return -1;
431         }
432
433         buf[len] = '\0';
434         if (memcmp(buf, "FAIL", 4) == 0)
435                 return -1;
436         printf("%s", buf);
437
438         pos = buf;
439         while (*pos != '\0' && *pos != '\n')
440                 pos++;
441         *pos = '\0';
442         os_strlcpy(addr, buf, addr_len);
443         return 0;
444 }
445
446
447 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
448                                    char *argv[])
449 {
450         char addr[32], cmd[64];
451
452         if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
453                 return 0;
454         do {
455                 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
456         } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
457
458         return -1;
459 }
460
461
462 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
463 {
464         printf("%s", commands_help);
465         return 0;
466 }
467
468
469 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
470                                    char *argv[])
471 {
472         printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
473         return 0;
474 }
475
476
477 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
478 {
479         hostapd_cli_quit = 1;
480         return 0;
481 }
482
483
484 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
485 {
486         char cmd[256];
487         if (argc != 1) {
488                 printf("Invalid LEVEL command: needs one argument (debug "
489                        "level)\n");
490                 return 0;
491         }
492         snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
493         return wpa_ctrl_command(ctrl, cmd);
494 }
495
496
497 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
498 {
499         struct dirent *dent;
500         DIR *dir;
501
502         dir = opendir(ctrl_iface_dir);
503         if (dir == NULL) {
504                 printf("Control interface directory '%s' could not be "
505                        "openned.\n", ctrl_iface_dir);
506                 return;
507         }
508
509         printf("Available interfaces:\n");
510         while ((dent = readdir(dir))) {
511                 if (strcmp(dent->d_name, ".") == 0 ||
512                     strcmp(dent->d_name, "..") == 0)
513                         continue;
514                 printf("%s\n", dent->d_name);
515         }
516         closedir(dir);
517 }
518
519
520 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
521                                      char *argv[])
522 {
523         if (argc < 1) {
524                 hostapd_cli_list_interfaces(ctrl);
525                 return 0;
526         }
527
528         hostapd_cli_close_connection();
529         free(ctrl_ifname);
530         ctrl_ifname = strdup(argv[0]);
531
532         if (hostapd_cli_open_connection(ctrl_ifname)) {
533                 printf("Connected to interface '%s.\n", ctrl_ifname);
534                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
535                         hostapd_cli_attached = 1;
536                 } else {
537                         printf("Warning: Failed to attach to "
538                                "hostapd.\n");
539                 }
540         } else {
541                 printf("Could not connect to interface '%s' - re-trying\n",
542                         ctrl_ifname);
543         }
544         return 0;
545 }
546
547
548 struct hostapd_cli_cmd {
549         const char *cmd;
550         int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
551 };
552
553 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
554         { "ping", hostapd_cli_cmd_ping },
555         { "mib", hostapd_cli_cmd_mib },
556         { "sta", hostapd_cli_cmd_sta },
557         { "all_sta", hostapd_cli_cmd_all_sta },
558         { "new_sta", hostapd_cli_cmd_new_sta },
559         { "deauthenticate", hostapd_cli_cmd_deauthenticate },
560         { "disassociate", hostapd_cli_cmd_disassociate },
561 #ifdef CONFIG_IEEE80211W
562         { "sa_query", hostapd_cli_cmd_sa_query },
563 #endif /* CONFIG_IEEE80211W */
564 #ifdef CONFIG_WPS
565         { "wps_pin", hostapd_cli_cmd_wps_pin },
566         { "wps_pbc", hostapd_cli_cmd_wps_pbc },
567 #ifdef CONFIG_WPS_OOB
568         { "wps_oob", hostapd_cli_cmd_wps_oob },
569 #endif /* CONFIG_WPS_OOB */
570 #endif /* CONFIG_WPS */
571         { "help", hostapd_cli_cmd_help },
572         { "interface", hostapd_cli_cmd_interface },
573         { "level", hostapd_cli_cmd_level },
574         { "license", hostapd_cli_cmd_license },
575         { "quit", hostapd_cli_cmd_quit },
576         { NULL, NULL }
577 };
578
579
580 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
581 {
582         struct hostapd_cli_cmd *cmd, *match = NULL;
583         int count;
584
585         count = 0;
586         cmd = hostapd_cli_commands;
587         while (cmd->cmd) {
588                 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
589                         match = cmd;
590                         count++;
591                 }
592                 cmd++;
593         }
594
595         if (count > 1) {
596                 printf("Ambiguous command '%s'; possible commands:", argv[0]);
597                 cmd = hostapd_cli_commands;
598                 while (cmd->cmd) {
599                         if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
600                             0) {
601                                 printf(" %s", cmd->cmd);
602                         }
603                         cmd++;
604                 }
605                 printf("\n");
606         } else if (count == 0) {
607                 printf("Unknown command '%s'\n", argv[0]);
608         } else {
609                 match->handler(ctrl, argc - 1, &argv[1]);
610         }
611 }
612
613
614 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
615                                      int action_monitor)
616 {
617         int first = 1;
618         if (ctrl_conn == NULL)
619                 return;
620         while (wpa_ctrl_pending(ctrl)) {
621                 char buf[256];
622                 size_t len = sizeof(buf) - 1;
623                 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
624                         buf[len] = '\0';
625                         if (action_monitor)
626                                 hostapd_cli_action_process(buf, len);
627                         else {
628                                 if (in_read && first)
629                                         printf("\n");
630                                 first = 0;
631                                 printf("%s\n", buf);
632                         }
633                 } else {
634                         printf("Could not read pending message.\n");
635                         break;
636                 }
637         }
638 }
639
640
641 static void hostapd_cli_interactive(void)
642 {
643         const int max_args = 10;
644         char cmd[256], *res, *argv[max_args], *pos;
645         int argc;
646
647         printf("\nInteractive mode\n\n");
648
649         do {
650                 hostapd_cli_recv_pending(ctrl_conn, 0, 0);
651                 printf("> ");
652                 alarm(ping_interval);
653                 res = fgets(cmd, sizeof(cmd), stdin);
654                 alarm(0);
655                 if (res == NULL)
656                         break;
657                 pos = cmd;
658                 while (*pos != '\0') {
659                         if (*pos == '\n') {
660                                 *pos = '\0';
661                                 break;
662                         }
663                         pos++;
664                 }
665                 argc = 0;
666                 pos = cmd;
667                 for (;;) {
668                         while (*pos == ' ')
669                                 pos++;
670                         if (*pos == '\0')
671                                 break;
672                         argv[argc] = pos;
673                         argc++;
674                         if (argc == max_args)
675                                 break;
676                         while (*pos != '\0' && *pos != ' ')
677                                 pos++;
678                         if (*pos == ' ')
679                                 *pos++ = '\0';
680                 }
681                 if (argc)
682                         wpa_request(ctrl_conn, argc, argv);
683         } while (!hostapd_cli_quit);
684 }
685
686
687 static void hostapd_cli_cleanup(void)
688 {
689         hostapd_cli_close_connection();
690         if (pid_file)
691                 os_daemonize_terminate(pid_file);
692
693         os_program_deinit();
694 }
695
696
697 static void hostapd_cli_terminate(int sig)
698 {
699         hostapd_cli_cleanup();
700         exit(0);
701 }
702
703
704 static void hostapd_cli_alarm(int sig)
705 {
706         if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
707                 printf("Connection to hostapd lost - trying to reconnect\n");
708                 hostapd_cli_close_connection();
709         }
710         if (!ctrl_conn) {
711                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
712                 if (ctrl_conn) {
713                         printf("Connection to hostapd re-established\n");
714                         if (wpa_ctrl_attach(ctrl_conn) == 0) {
715                                 hostapd_cli_attached = 1;
716                         } else {
717                                 printf("Warning: Failed to attach to "
718                                        "hostapd.\n");
719                         }
720                 }
721         }
722         if (ctrl_conn)
723                 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
724         alarm(ping_interval);
725 }
726
727
728 static void hostapd_cli_action(struct wpa_ctrl *ctrl)
729 {
730         fd_set rfds;
731         int fd, res;
732         struct timeval tv;
733         char buf[256];
734         size_t len;
735
736         fd = wpa_ctrl_get_fd(ctrl);
737
738         while (!hostapd_cli_quit) {
739                 FD_ZERO(&rfds);
740                 FD_SET(fd, &rfds);
741                 tv.tv_sec = ping_interval;
742                 tv.tv_usec = 0;
743                 res = select(fd + 1, &rfds, NULL, NULL, &tv);
744                 if (res < 0 && errno != EINTR) {
745                         perror("select");
746                         break;
747                 }
748
749                 if (FD_ISSET(fd, &rfds))
750                         hostapd_cli_recv_pending(ctrl, 0, 1);
751                 else {
752                         len = sizeof(buf) - 1;
753                         if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
754                                              hostapd_cli_action_process) < 0 ||
755                             len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
756                                 printf("hostapd did not reply to PING "
757                                        "command - exiting\n");
758                                 break;
759                         }
760                 }
761         }
762 }
763
764
765 int main(int argc, char *argv[])
766 {
767         int interactive;
768         int warning_displayed = 0;
769         int c;
770         int daemonize = 0;
771
772         if (os_program_init())
773                 return -1;
774
775         for (;;) {
776                 c = getopt(argc, argv, "a:BhG:i:p:v");
777                 if (c < 0)
778                         break;
779                 switch (c) {
780                 case 'a':
781                         action_file = optarg;
782                         break;
783                 case 'B':
784                         daemonize = 1;
785                         break;
786                 case 'G':
787                         ping_interval = atoi(optarg);
788                         break;
789                 case 'h':
790                         usage();
791                         return 0;
792                 case 'v':
793                         printf("%s\n", hostapd_cli_version);
794                         return 0;
795                 case 'i':
796                         os_free(ctrl_ifname);
797                         ctrl_ifname = os_strdup(optarg);
798                         break;
799                 case 'p':
800                         ctrl_iface_dir = optarg;
801                         break;
802                 default:
803                         usage();
804                         return -1;
805                 }
806         }
807
808         interactive = (argc == optind) && (action_file == NULL);
809
810         if (interactive) {
811                 printf("%s\n\n%s\n\n", hostapd_cli_version,
812                        hostapd_cli_license);
813         }
814
815         for (;;) {
816                 if (ctrl_ifname == NULL) {
817                         struct dirent *dent;
818                         DIR *dir = opendir(ctrl_iface_dir);
819                         if (dir) {
820                                 while ((dent = readdir(dir))) {
821                                         if (os_strcmp(dent->d_name, ".") == 0
822                                             ||
823                                             os_strcmp(dent->d_name, "..") == 0)
824                                                 continue;
825                                         printf("Selected interface '%s'\n",
826                                                dent->d_name);
827                                         ctrl_ifname = os_strdup(dent->d_name);
828                                         break;
829                                 }
830                                 closedir(dir);
831                         }
832                 }
833                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
834                 if (ctrl_conn) {
835                         if (warning_displayed)
836                                 printf("Connection established.\n");
837                         break;
838                 }
839
840                 if (!interactive) {
841                         perror("Failed to connect to hostapd - "
842                                "wpa_ctrl_open");
843                         return -1;
844                 }
845
846                 if (!warning_displayed) {
847                         printf("Could not connect to hostapd - re-trying\n");
848                         warning_displayed = 1;
849                 }
850                 os_sleep(1, 0);
851                 continue;
852         }
853
854         signal(SIGINT, hostapd_cli_terminate);
855         signal(SIGTERM, hostapd_cli_terminate);
856         signal(SIGALRM, hostapd_cli_alarm);
857
858         if (interactive || action_file) {
859                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
860                         hostapd_cli_attached = 1;
861                 } else {
862                         printf("Warning: Failed to attach to hostapd.\n");
863                         if (action_file)
864                                 return -1;
865                 }
866         }
867
868         if (daemonize && os_daemonize(pid_file))
869                 return -1;
870
871         if (interactive)
872                 hostapd_cli_interactive();
873         else if (action_file)
874                 hostapd_cli_action(ctrl_conn);
875         else
876                 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
877
878         os_free(ctrl_ifname);
879         hostapd_cli_cleanup();
880         return 0;
881 }