2 * hostapd - command line interface for hostapd daemon
3 * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
18 #include "common/wpa_ctrl.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"
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"
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"
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"
49 "Alternatively, this software may be distributed under the terms of the\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"
56 "1. Redistributions of source code must retain the above copyright\n"
57 " notice, this list of conditions and the following disclaimer.\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"
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"
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"
80 static const char *commands_help =
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 */
92 " wps_pin <uuid> <pin> [timeout] add WPS Enrollee PIN (Device Password)\n"
93 " wps_pbc indicate button pushed to initiate PBC\n"
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";
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;
115 static void usage(void)
117 fprintf(stderr, "%s\n", hostapd_cli_version);
120 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
122 " [-G<ping interval>] [command..]\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 "
132 " -B run a daemon in the background\n"
133 " -i<ifname> Interface to listen on (default: first "
134 "interface found in the\n"
141 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
149 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
150 cfile = malloc(flen);
153 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
155 ctrl_conn = wpa_ctrl_open(cfile);
161 static void hostapd_cli_close_connection(void)
163 if (ctrl_conn == NULL)
166 if (hostapd_cli_attached) {
167 wpa_ctrl_detach(ctrl_conn);
168 hostapd_cli_attached = 0;
170 wpa_ctrl_close(ctrl_conn);
175 static void hostapd_cli_msg_cb(char *msg, size_t len)
181 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
187 if (ctrl_conn == NULL) {
188 printf("Not connected to hostapd - command dropped.\n");
191 len = sizeof(buf) - 1;
192 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
195 printf("'%s' command timed out.\n", cmd);
197 } else if (ret < 0) {
198 printf("'%s' command failed.\n", cmd);
209 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
211 return _wpa_ctrl_command(ctrl, cmd, 1);
215 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
217 return wpa_ctrl_command(ctrl, "PING");
221 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
223 return wpa_ctrl_command(ctrl, "MIB");
227 static int hostapd_cli_exec(const char *program, const char *arg1,
235 len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
236 cmd = os_malloc(len);
239 res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
240 if (res < 0 || (size_t) res >= len) {
248 #endif /* _WIN32_WCE */
255 static void hostapd_cli_action_process(char *msg, size_t len)
261 pos = os_strchr(pos, '>');
268 hostapd_cli_exec(action_file, ctrl_ifname, pos);
272 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
276 printf("Invalid 'sta' command - exactly one argument, STA "
277 "address, is required.\n");
280 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
281 return wpa_ctrl_command(ctrl, buf);
285 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
290 printf("Invalid 'new_sta' command - exactly one argument, STA "
291 "address, is required.\n");
294 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
295 return wpa_ctrl_command(ctrl, buf);
299 static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
304 printf("Invalid 'deauthenticate' command - exactly one "
305 "argument, STA address, is required.\n");
309 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
312 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
313 return wpa_ctrl_command(ctrl, buf);
317 static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
322 printf("Invalid 'disassociate' command - exactly one "
323 "argument, STA address, is required.\n");
327 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
330 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
331 return wpa_ctrl_command(ctrl, buf);
335 #ifdef CONFIG_IEEE80211W
336 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
341 printf("Invalid 'sa_query' command - exactly one argument, "
342 "STA address, is required.\n");
345 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
346 return wpa_ctrl_command(ctrl, buf);
348 #endif /* CONFIG_IEEE80211W */
352 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
357 printf("Invalid 'wps_pin' command - at least two arguments, "
358 "UUID and PIN, are required.\n");
362 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
363 argv[0], argv[1], argv[2]);
365 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
366 return wpa_ctrl_command(ctrl, buf);
370 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
373 return wpa_ctrl_command(ctrl, "WPS_PBC");
377 #ifdef CONFIG_WPS_OOB
378 static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
384 if (argc != 3 && argc != 4) {
385 printf("Invalid WPS_OOB command: need three or four "
387 "- DEV_TYPE: use 'ufd' or 'nfc'\n"
388 "- PATH: path of OOB device like '/mnt'\n"
389 "- METHOD: OOB method 'pin-e' or 'pin-r', "
391 "- DEV_NAME: (only for NFC) device name like "
397 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
398 argv[0], argv[1], argv[2]);
400 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
401 argv[0], argv[1], argv[2], argv[3]);
402 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
403 printf("Too long WPS_OOB command.\n");
406 return wpa_ctrl_command(ctrl, cmd);
408 #endif /* CONFIG_WPS_OOB */
411 static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
416 printf("Invalid 'wps_ap_pin' command - at least one argument "
421 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
422 argv[0], argv[1], argv[2]);
424 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
427 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
428 return wpa_ctrl_command(ctrl, buf);
430 #endif /* CONFIG_WPS */
433 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
434 char *addr, size_t addr_len)
436 char buf[4096], *pos;
440 if (ctrl_conn == NULL) {
441 printf("Not connected to hostapd - command dropped.\n");
444 len = sizeof(buf) - 1;
445 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
448 printf("'%s' command timed out.\n", cmd);
450 } else if (ret < 0) {
451 printf("'%s' command failed.\n", cmd);
456 if (memcmp(buf, "FAIL", 4) == 0)
461 while (*pos != '\0' && *pos != '\n')
464 os_strlcpy(addr, buf, addr_len);
469 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
472 char addr[32], cmd[64];
474 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
477 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
478 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
484 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
486 printf("%s", commands_help);
491 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
494 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
499 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
501 hostapd_cli_quit = 1;
506 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
510 printf("Invalid LEVEL command: needs one argument (debug "
514 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
515 return wpa_ctrl_command(ctrl, cmd);
519 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
524 dir = opendir(ctrl_iface_dir);
526 printf("Control interface directory '%s' could not be "
527 "openned.\n", ctrl_iface_dir);
531 printf("Available interfaces:\n");
532 while ((dent = readdir(dir))) {
533 if (strcmp(dent->d_name, ".") == 0 ||
534 strcmp(dent->d_name, "..") == 0)
536 printf("%s\n", dent->d_name);
542 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
546 hostapd_cli_list_interfaces(ctrl);
550 hostapd_cli_close_connection();
552 ctrl_ifname = strdup(argv[0]);
554 if (hostapd_cli_open_connection(ctrl_ifname)) {
555 printf("Connected to interface '%s.\n", ctrl_ifname);
556 if (wpa_ctrl_attach(ctrl_conn) == 0) {
557 hostapd_cli_attached = 1;
559 printf("Warning: Failed to attach to "
563 printf("Could not connect to interface '%s' - re-trying\n",
570 struct hostapd_cli_cmd {
572 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
575 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
576 { "ping", hostapd_cli_cmd_ping },
577 { "mib", hostapd_cli_cmd_mib },
578 { "sta", hostapd_cli_cmd_sta },
579 { "all_sta", hostapd_cli_cmd_all_sta },
580 { "new_sta", hostapd_cli_cmd_new_sta },
581 { "deauthenticate", hostapd_cli_cmd_deauthenticate },
582 { "disassociate", hostapd_cli_cmd_disassociate },
583 #ifdef CONFIG_IEEE80211W
584 { "sa_query", hostapd_cli_cmd_sa_query },
585 #endif /* CONFIG_IEEE80211W */
587 { "wps_pin", hostapd_cli_cmd_wps_pin },
588 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
589 #ifdef CONFIG_WPS_OOB
590 { "wps_oob", hostapd_cli_cmd_wps_oob },
591 #endif /* CONFIG_WPS_OOB */
592 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
593 #endif /* CONFIG_WPS */
594 { "help", hostapd_cli_cmd_help },
595 { "interface", hostapd_cli_cmd_interface },
596 { "level", hostapd_cli_cmd_level },
597 { "license", hostapd_cli_cmd_license },
598 { "quit", hostapd_cli_cmd_quit },
603 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
605 struct hostapd_cli_cmd *cmd, *match = NULL;
609 cmd = hostapd_cli_commands;
611 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
619 printf("Ambiguous command '%s'; possible commands:", argv[0]);
620 cmd = hostapd_cli_commands;
622 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
624 printf(" %s", cmd->cmd);
629 } else if (count == 0) {
630 printf("Unknown command '%s'\n", argv[0]);
632 match->handler(ctrl, argc - 1, &argv[1]);
637 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
641 if (ctrl_conn == NULL)
643 while (wpa_ctrl_pending(ctrl)) {
645 size_t len = sizeof(buf) - 1;
646 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
649 hostapd_cli_action_process(buf, len);
651 if (in_read && first)
657 printf("Could not read pending message.\n");
664 static void hostapd_cli_interactive(void)
666 const int max_args = 10;
667 char cmd[256], *res, *argv[max_args], *pos;
670 printf("\nInteractive mode\n\n");
673 hostapd_cli_recv_pending(ctrl_conn, 0, 0);
675 alarm(ping_interval);
676 res = fgets(cmd, sizeof(cmd), stdin);
681 while (*pos != '\0') {
697 if (argc == max_args)
699 while (*pos != '\0' && *pos != ' ')
705 wpa_request(ctrl_conn, argc, argv);
706 } while (!hostapd_cli_quit);
710 static void hostapd_cli_cleanup(void)
712 hostapd_cli_close_connection();
714 os_daemonize_terminate(pid_file);
720 static void hostapd_cli_terminate(int sig)
722 hostapd_cli_cleanup();
727 static void hostapd_cli_alarm(int sig)
729 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
730 printf("Connection to hostapd lost - trying to reconnect\n");
731 hostapd_cli_close_connection();
734 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
736 printf("Connection to hostapd re-established\n");
737 if (wpa_ctrl_attach(ctrl_conn) == 0) {
738 hostapd_cli_attached = 1;
740 printf("Warning: Failed to attach to "
746 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
747 alarm(ping_interval);
751 static void hostapd_cli_action(struct wpa_ctrl *ctrl)
759 fd = wpa_ctrl_get_fd(ctrl);
761 while (!hostapd_cli_quit) {
764 tv.tv_sec = ping_interval;
766 res = select(fd + 1, &rfds, NULL, NULL, &tv);
767 if (res < 0 && errno != EINTR) {
772 if (FD_ISSET(fd, &rfds))
773 hostapd_cli_recv_pending(ctrl, 0, 1);
775 len = sizeof(buf) - 1;
776 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
777 hostapd_cli_action_process) < 0 ||
778 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
779 printf("hostapd did not reply to PING "
780 "command - exiting\n");
788 int main(int argc, char *argv[])
791 int warning_displayed = 0;
795 if (os_program_init())
799 c = getopt(argc, argv, "a:BhG:i:p:v");
804 action_file = optarg;
810 ping_interval = atoi(optarg);
816 printf("%s\n", hostapd_cli_version);
819 os_free(ctrl_ifname);
820 ctrl_ifname = os_strdup(optarg);
823 ctrl_iface_dir = optarg;
831 interactive = (argc == optind) && (action_file == NULL);
834 printf("%s\n\n%s\n\n", hostapd_cli_version,
835 hostapd_cli_license);
839 if (ctrl_ifname == NULL) {
841 DIR *dir = opendir(ctrl_iface_dir);
843 while ((dent = readdir(dir))) {
844 if (os_strcmp(dent->d_name, ".") == 0
846 os_strcmp(dent->d_name, "..") == 0)
848 printf("Selected interface '%s'\n",
850 ctrl_ifname = os_strdup(dent->d_name);
856 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
858 if (warning_displayed)
859 printf("Connection established.\n");
864 perror("Failed to connect to hostapd - "
869 if (!warning_displayed) {
870 printf("Could not connect to hostapd - re-trying\n");
871 warning_displayed = 1;
877 signal(SIGINT, hostapd_cli_terminate);
878 signal(SIGTERM, hostapd_cli_terminate);
879 signal(SIGALRM, hostapd_cli_alarm);
881 if (interactive || action_file) {
882 if (wpa_ctrl_attach(ctrl_conn) == 0) {
883 hostapd_cli_attached = 1;
885 printf("Warning: Failed to attach to hostapd.\n");
891 if (daemonize && os_daemonize(pid_file))
895 hostapd_cli_interactive();
896 else if (action_file)
897 hostapd_cli_action(ctrl_conn);
899 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
901 os_free(ctrl_ifname);
902 hostapd_cli_cleanup();