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