e80de487dde884e7d871b0ba5890697ecc16b386
[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 static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
574 {
575         char cmd[256];
576         int res;
577
578         if (argc != 2) {
579                 printf("Invalid SET command: needs two arguments (variable "
580                        "name and value)\n");
581                 return -1;
582         }
583
584         res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
585         if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
586                 printf("Too long SET command.\n");
587                 return -1;
588         }
589         return wpa_ctrl_command(ctrl, cmd);
590 }
591
592
593 struct hostapd_cli_cmd {
594         const char *cmd;
595         int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
596 };
597
598 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
599         { "ping", hostapd_cli_cmd_ping },
600         { "mib", hostapd_cli_cmd_mib },
601         { "sta", hostapd_cli_cmd_sta },
602         { "all_sta", hostapd_cli_cmd_all_sta },
603         { "new_sta", hostapd_cli_cmd_new_sta },
604         { "deauthenticate", hostapd_cli_cmd_deauthenticate },
605         { "disassociate", hostapd_cli_cmd_disassociate },
606 #ifdef CONFIG_IEEE80211W
607         { "sa_query", hostapd_cli_cmd_sa_query },
608 #endif /* CONFIG_IEEE80211W */
609 #ifdef CONFIG_WPS
610         { "wps_pin", hostapd_cli_cmd_wps_pin },
611         { "wps_pbc", hostapd_cli_cmd_wps_pbc },
612 #ifdef CONFIG_WPS_OOB
613         { "wps_oob", hostapd_cli_cmd_wps_oob },
614 #endif /* CONFIG_WPS_OOB */
615         { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
616 #endif /* CONFIG_WPS */
617         { "help", hostapd_cli_cmd_help },
618         { "interface", hostapd_cli_cmd_interface },
619         { "level", hostapd_cli_cmd_level },
620         { "license", hostapd_cli_cmd_license },
621         { "quit", hostapd_cli_cmd_quit },
622         { "set", hostapd_cli_cmd_set },
623         { NULL, NULL }
624 };
625
626
627 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
628 {
629         struct hostapd_cli_cmd *cmd, *match = NULL;
630         int count;
631
632         count = 0;
633         cmd = hostapd_cli_commands;
634         while (cmd->cmd) {
635                 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
636                         match = cmd;
637                         count++;
638                 }
639                 cmd++;
640         }
641
642         if (count > 1) {
643                 printf("Ambiguous command '%s'; possible commands:", argv[0]);
644                 cmd = hostapd_cli_commands;
645                 while (cmd->cmd) {
646                         if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
647                             0) {
648                                 printf(" %s", cmd->cmd);
649                         }
650                         cmd++;
651                 }
652                 printf("\n");
653         } else if (count == 0) {
654                 printf("Unknown command '%s'\n", argv[0]);
655         } else {
656                 match->handler(ctrl, argc - 1, &argv[1]);
657         }
658 }
659
660
661 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
662                                      int action_monitor)
663 {
664         int first = 1;
665         if (ctrl_conn == NULL)
666                 return;
667         while (wpa_ctrl_pending(ctrl)) {
668                 char buf[256];
669                 size_t len = sizeof(buf) - 1;
670                 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
671                         buf[len] = '\0';
672                         if (action_monitor)
673                                 hostapd_cli_action_process(buf, len);
674                         else {
675                                 if (in_read && first)
676                                         printf("\n");
677                                 first = 0;
678                                 printf("%s\n", buf);
679                         }
680                 } else {
681                         printf("Could not read pending message.\n");
682                         break;
683                 }
684         }
685 }
686
687
688 static void hostapd_cli_interactive(void)
689 {
690         const int max_args = 10;
691         char cmd[256], *res, *argv[max_args], *pos;
692         int argc;
693
694         printf("\nInteractive mode\n\n");
695
696         do {
697                 hostapd_cli_recv_pending(ctrl_conn, 0, 0);
698                 printf("> ");
699                 alarm(ping_interval);
700                 res = fgets(cmd, sizeof(cmd), stdin);
701                 alarm(0);
702                 if (res == NULL)
703                         break;
704                 pos = cmd;
705                 while (*pos != '\0') {
706                         if (*pos == '\n') {
707                                 *pos = '\0';
708                                 break;
709                         }
710                         pos++;
711                 }
712                 argc = 0;
713                 pos = cmd;
714                 for (;;) {
715                         while (*pos == ' ')
716                                 pos++;
717                         if (*pos == '\0')
718                                 break;
719                         argv[argc] = pos;
720                         argc++;
721                         if (argc == max_args)
722                                 break;
723                         while (*pos != '\0' && *pos != ' ')
724                                 pos++;
725                         if (*pos == ' ')
726                                 *pos++ = '\0';
727                 }
728                 if (argc)
729                         wpa_request(ctrl_conn, argc, argv);
730         } while (!hostapd_cli_quit);
731 }
732
733
734 static void hostapd_cli_cleanup(void)
735 {
736         hostapd_cli_close_connection();
737         if (pid_file)
738                 os_daemonize_terminate(pid_file);
739
740         os_program_deinit();
741 }
742
743
744 static void hostapd_cli_terminate(int sig)
745 {
746         hostapd_cli_cleanup();
747         exit(0);
748 }
749
750
751 static void hostapd_cli_alarm(int sig)
752 {
753         if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
754                 printf("Connection to hostapd lost - trying to reconnect\n");
755                 hostapd_cli_close_connection();
756         }
757         if (!ctrl_conn) {
758                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
759                 if (ctrl_conn) {
760                         printf("Connection to hostapd re-established\n");
761                         if (wpa_ctrl_attach(ctrl_conn) == 0) {
762                                 hostapd_cli_attached = 1;
763                         } else {
764                                 printf("Warning: Failed to attach to "
765                                        "hostapd.\n");
766                         }
767                 }
768         }
769         if (ctrl_conn)
770                 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
771         alarm(ping_interval);
772 }
773
774
775 static void hostapd_cli_action(struct wpa_ctrl *ctrl)
776 {
777         fd_set rfds;
778         int fd, res;
779         struct timeval tv;
780         char buf[256];
781         size_t len;
782
783         fd = wpa_ctrl_get_fd(ctrl);
784
785         while (!hostapd_cli_quit) {
786                 FD_ZERO(&rfds);
787                 FD_SET(fd, &rfds);
788                 tv.tv_sec = ping_interval;
789                 tv.tv_usec = 0;
790                 res = select(fd + 1, &rfds, NULL, NULL, &tv);
791                 if (res < 0 && errno != EINTR) {
792                         perror("select");
793                         break;
794                 }
795
796                 if (FD_ISSET(fd, &rfds))
797                         hostapd_cli_recv_pending(ctrl, 0, 1);
798                 else {
799                         len = sizeof(buf) - 1;
800                         if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
801                                              hostapd_cli_action_process) < 0 ||
802                             len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
803                                 printf("hostapd did not reply to PING "
804                                        "command - exiting\n");
805                                 break;
806                         }
807                 }
808         }
809 }
810
811
812 int main(int argc, char *argv[])
813 {
814         int interactive;
815         int warning_displayed = 0;
816         int c;
817         int daemonize = 0;
818
819         if (os_program_init())
820                 return -1;
821
822         for (;;) {
823                 c = getopt(argc, argv, "a:BhG:i:p:v");
824                 if (c < 0)
825                         break;
826                 switch (c) {
827                 case 'a':
828                         action_file = optarg;
829                         break;
830                 case 'B':
831                         daemonize = 1;
832                         break;
833                 case 'G':
834                         ping_interval = atoi(optarg);
835                         break;
836                 case 'h':
837                         usage();
838                         return 0;
839                 case 'v':
840                         printf("%s\n", hostapd_cli_version);
841                         return 0;
842                 case 'i':
843                         os_free(ctrl_ifname);
844                         ctrl_ifname = os_strdup(optarg);
845                         break;
846                 case 'p':
847                         ctrl_iface_dir = optarg;
848                         break;
849                 default:
850                         usage();
851                         return -1;
852                 }
853         }
854
855         interactive = (argc == optind) && (action_file == NULL);
856
857         if (interactive) {
858                 printf("%s\n\n%s\n\n", hostapd_cli_version,
859                        hostapd_cli_license);
860         }
861
862         for (;;) {
863                 if (ctrl_ifname == NULL) {
864                         struct dirent *dent;
865                         DIR *dir = opendir(ctrl_iface_dir);
866                         if (dir) {
867                                 while ((dent = readdir(dir))) {
868                                         if (os_strcmp(dent->d_name, ".") == 0
869                                             ||
870                                             os_strcmp(dent->d_name, "..") == 0)
871                                                 continue;
872                                         printf("Selected interface '%s'\n",
873                                                dent->d_name);
874                                         ctrl_ifname = os_strdup(dent->d_name);
875                                         break;
876                                 }
877                                 closedir(dir);
878                         }
879                 }
880                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
881                 if (ctrl_conn) {
882                         if (warning_displayed)
883                                 printf("Connection established.\n");
884                         break;
885                 }
886
887                 if (!interactive) {
888                         perror("Failed to connect to hostapd - "
889                                "wpa_ctrl_open");
890                         return -1;
891                 }
892
893                 if (!warning_displayed) {
894                         printf("Could not connect to hostapd - re-trying\n");
895                         warning_displayed = 1;
896                 }
897                 os_sleep(1, 0);
898                 continue;
899         }
900
901         signal(SIGINT, hostapd_cli_terminate);
902         signal(SIGTERM, hostapd_cli_terminate);
903         signal(SIGALRM, hostapd_cli_alarm);
904
905         if (interactive || action_file) {
906                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
907                         hostapd_cli_attached = 1;
908                 } else {
909                         printf("Warning: Failed to attach to hostapd.\n");
910                         if (action_file)
911                                 return -1;
912                 }
913         }
914
915         if (daemonize && os_daemonize(pid_file))
916                 return -1;
917
918         if (interactive)
919                 hostapd_cli_interactive();
920         else if (action_file)
921                 hostapd_cli_action(ctrl_conn);
922         else
923                 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
924
925         os_free(ctrl_ifname);
926         hostapd_cli_cleanup();
927         return 0;
928 }