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