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] [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"
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 " help show this usage help\n"
101 " interface [ifname] show interfaces/select interface\n"
102 " level <debug level> change debug level\n"
103 " license show full hostapd_cli license\n"
104 " quit exit hostapd_cli\n";
106 static struct wpa_ctrl *ctrl_conn;
107 static int hostapd_cli_quit = 0;
108 static int hostapd_cli_attached = 0;
109 static const char *ctrl_iface_dir = "/var/run/hostapd";
110 static char *ctrl_ifname = NULL;
111 static const char *pid_file = NULL;
112 static const char *action_file = NULL;
113 static int ping_interval = 5;
116 static void usage(void)
118 fprintf(stderr, "%s\n", hostapd_cli_version);
121 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
123 " [-G<ping interval>] [command..]\n"
126 " -h help (show this usage text)\n"
127 " -v shown version information\n"
128 " -p<path> path to find control sockets (default: "
129 "/var/run/hostapd)\n"
130 " -a<file> run in daemon mode executing the action file "
133 " -B run a daemon in the background\n"
134 " -i<ifname> Interface to listen on (default: first "
135 "interface found in the\n"
142 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
150 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
151 cfile = malloc(flen);
154 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
156 ctrl_conn = wpa_ctrl_open(cfile);
162 static void hostapd_cli_close_connection(void)
164 if (ctrl_conn == NULL)
167 if (hostapd_cli_attached) {
168 wpa_ctrl_detach(ctrl_conn);
169 hostapd_cli_attached = 0;
171 wpa_ctrl_close(ctrl_conn);
176 static void hostapd_cli_msg_cb(char *msg, size_t len)
182 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
188 if (ctrl_conn == NULL) {
189 printf("Not connected to hostapd - command dropped.\n");
192 len = sizeof(buf) - 1;
193 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
196 printf("'%s' command timed out.\n", cmd);
198 } else if (ret < 0) {
199 printf("'%s' command failed.\n", cmd);
210 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
212 return _wpa_ctrl_command(ctrl, cmd, 1);
216 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
218 return wpa_ctrl_command(ctrl, "PING");
222 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
224 return wpa_ctrl_command(ctrl, "MIB");
228 static int hostapd_cli_exec(const char *program, const char *arg1,
236 len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
237 cmd = os_malloc(len);
240 res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
241 if (res < 0 || (size_t) res >= len) {
249 #endif /* _WIN32_WCE */
256 static void hostapd_cli_action_process(char *msg, size_t len)
262 pos = os_strchr(pos, '>');
269 hostapd_cli_exec(action_file, ctrl_ifname, pos);
273 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
277 printf("Invalid 'sta' command - exactly one argument, STA "
278 "address, is required.\n");
281 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
282 return wpa_ctrl_command(ctrl, buf);
286 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
291 printf("Invalid 'new_sta' command - exactly one argument, STA "
292 "address, is required.\n");
295 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
296 return wpa_ctrl_command(ctrl, buf);
300 static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
305 printf("Invalid 'deauthenticate' command - exactly one "
306 "argument, STA address, is required.\n");
310 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
313 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
314 return wpa_ctrl_command(ctrl, buf);
318 static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
323 printf("Invalid 'disassociate' command - exactly one "
324 "argument, STA address, is required.\n");
328 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
331 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
332 return wpa_ctrl_command(ctrl, buf);
336 #ifdef CONFIG_IEEE80211W
337 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
342 printf("Invalid 'sa_query' command - exactly one argument, "
343 "STA address, is required.\n");
346 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
347 return wpa_ctrl_command(ctrl, buf);
349 #endif /* CONFIG_IEEE80211W */
353 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
358 printf("Invalid 'wps_pin' command - at least two arguments, "
359 "UUID and PIN, are required.\n");
363 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
364 argv[0], argv[1], argv[2], argv[3]);
366 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
367 argv[0], argv[1], argv[2]);
369 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
370 return wpa_ctrl_command(ctrl, buf);
374 static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
380 if (argc != 1 && argc != 2) {
381 printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
382 "- PIN to be verified\n");
387 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
390 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
392 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
393 printf("Too long WPS_CHECK_PIN command.\n");
396 return wpa_ctrl_command(ctrl, cmd);
400 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
403 return wpa_ctrl_command(ctrl, "WPS_PBC");
407 #ifdef CONFIG_WPS_OOB
408 static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
414 if (argc != 3 && argc != 4) {
415 printf("Invalid WPS_OOB command: need three or four "
417 "- DEV_TYPE: use 'ufd' or 'nfc'\n"
418 "- PATH: path of OOB device like '/mnt'\n"
419 "- METHOD: OOB method 'pin-e' or 'pin-r', "
421 "- DEV_NAME: (only for NFC) device name like "
427 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
428 argv[0], argv[1], argv[2]);
430 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
431 argv[0], argv[1], argv[2], argv[3]);
432 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
433 printf("Too long WPS_OOB command.\n");
436 return wpa_ctrl_command(ctrl, cmd);
438 #endif /* CONFIG_WPS_OOB */
441 static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
446 printf("Invalid 'wps_ap_pin' command - at least one argument "
451 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
452 argv[0], argv[1], argv[2]);
454 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
457 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
458 return wpa_ctrl_command(ctrl, buf);
460 #endif /* CONFIG_WPS */
463 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
464 char *addr, size_t addr_len)
466 char buf[4096], *pos;
470 if (ctrl_conn == NULL) {
471 printf("Not connected to hostapd - command dropped.\n");
474 len = sizeof(buf) - 1;
475 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
478 printf("'%s' command timed out.\n", cmd);
480 } else if (ret < 0) {
481 printf("'%s' command failed.\n", cmd);
486 if (memcmp(buf, "FAIL", 4) == 0)
491 while (*pos != '\0' && *pos != '\n')
494 os_strlcpy(addr, buf, addr_len);
499 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
502 char addr[32], cmd[64];
504 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
507 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
508 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
514 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
516 printf("%s", commands_help);
521 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
524 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
529 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
531 hostapd_cli_quit = 1;
536 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
540 printf("Invalid LEVEL command: needs one argument (debug "
544 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
545 return wpa_ctrl_command(ctrl, cmd);
549 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
554 dir = opendir(ctrl_iface_dir);
556 printf("Control interface directory '%s' could not be "
557 "openned.\n", ctrl_iface_dir);
561 printf("Available interfaces:\n");
562 while ((dent = readdir(dir))) {
563 if (strcmp(dent->d_name, ".") == 0 ||
564 strcmp(dent->d_name, "..") == 0)
566 printf("%s\n", dent->d_name);
572 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
576 hostapd_cli_list_interfaces(ctrl);
580 hostapd_cli_close_connection();
582 ctrl_ifname = strdup(argv[0]);
584 if (hostapd_cli_open_connection(ctrl_ifname)) {
585 printf("Connected to interface '%s.\n", ctrl_ifname);
586 if (wpa_ctrl_attach(ctrl_conn) == 0) {
587 hostapd_cli_attached = 1;
589 printf("Warning: Failed to attach to "
593 printf("Could not connect to interface '%s' - re-trying\n",
600 static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
606 printf("Invalid SET command: needs two arguments (variable "
607 "name and value)\n");
611 res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
612 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
613 printf("Too long SET command.\n");
616 return wpa_ctrl_command(ctrl, cmd);
620 struct hostapd_cli_cmd {
622 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
625 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
626 { "ping", hostapd_cli_cmd_ping },
627 { "mib", hostapd_cli_cmd_mib },
628 { "sta", hostapd_cli_cmd_sta },
629 { "all_sta", hostapd_cli_cmd_all_sta },
630 { "new_sta", hostapd_cli_cmd_new_sta },
631 { "deauthenticate", hostapd_cli_cmd_deauthenticate },
632 { "disassociate", hostapd_cli_cmd_disassociate },
633 #ifdef CONFIG_IEEE80211W
634 { "sa_query", hostapd_cli_cmd_sa_query },
635 #endif /* CONFIG_IEEE80211W */
637 { "wps_pin", hostapd_cli_cmd_wps_pin },
638 { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
639 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
640 #ifdef CONFIG_WPS_OOB
641 { "wps_oob", hostapd_cli_cmd_wps_oob },
642 #endif /* CONFIG_WPS_OOB */
643 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
644 #endif /* CONFIG_WPS */
645 { "help", hostapd_cli_cmd_help },
646 { "interface", hostapd_cli_cmd_interface },
647 { "level", hostapd_cli_cmd_level },
648 { "license", hostapd_cli_cmd_license },
649 { "quit", hostapd_cli_cmd_quit },
650 { "set", hostapd_cli_cmd_set },
655 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
657 struct hostapd_cli_cmd *cmd, *match = NULL;
661 cmd = hostapd_cli_commands;
663 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
671 printf("Ambiguous command '%s'; possible commands:", argv[0]);
672 cmd = hostapd_cli_commands;
674 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
676 printf(" %s", cmd->cmd);
681 } else if (count == 0) {
682 printf("Unknown command '%s'\n", argv[0]);
684 match->handler(ctrl, argc - 1, &argv[1]);
689 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
693 if (ctrl_conn == NULL)
695 while (wpa_ctrl_pending(ctrl)) {
697 size_t len = sizeof(buf) - 1;
698 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
701 hostapd_cli_action_process(buf, len);
703 if (in_read && first)
709 printf("Could not read pending message.\n");
716 static void hostapd_cli_interactive(void)
718 const int max_args = 10;
719 char cmd[256], *res, *argv[max_args], *pos;
722 printf("\nInteractive mode\n\n");
725 hostapd_cli_recv_pending(ctrl_conn, 0, 0);
727 alarm(ping_interval);
728 res = fgets(cmd, sizeof(cmd), stdin);
733 while (*pos != '\0') {
749 if (argc == max_args)
751 while (*pos != '\0' && *pos != ' ')
757 wpa_request(ctrl_conn, argc, argv);
758 } while (!hostapd_cli_quit);
762 static void hostapd_cli_cleanup(void)
764 hostapd_cli_close_connection();
766 os_daemonize_terminate(pid_file);
772 static void hostapd_cli_terminate(int sig)
774 hostapd_cli_cleanup();
779 static void hostapd_cli_alarm(int sig)
781 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
782 printf("Connection to hostapd lost - trying to reconnect\n");
783 hostapd_cli_close_connection();
786 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
788 printf("Connection to hostapd re-established\n");
789 if (wpa_ctrl_attach(ctrl_conn) == 0) {
790 hostapd_cli_attached = 1;
792 printf("Warning: Failed to attach to "
798 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
799 alarm(ping_interval);
803 static void hostapd_cli_action(struct wpa_ctrl *ctrl)
811 fd = wpa_ctrl_get_fd(ctrl);
813 while (!hostapd_cli_quit) {
816 tv.tv_sec = ping_interval;
818 res = select(fd + 1, &rfds, NULL, NULL, &tv);
819 if (res < 0 && errno != EINTR) {
824 if (FD_ISSET(fd, &rfds))
825 hostapd_cli_recv_pending(ctrl, 0, 1);
827 len = sizeof(buf) - 1;
828 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
829 hostapd_cli_action_process) < 0 ||
830 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
831 printf("hostapd did not reply to PING "
832 "command - exiting\n");
840 int main(int argc, char *argv[])
843 int warning_displayed = 0;
847 if (os_program_init())
851 c = getopt(argc, argv, "a:BhG:i:p:v");
856 action_file = optarg;
862 ping_interval = atoi(optarg);
868 printf("%s\n", hostapd_cli_version);
871 os_free(ctrl_ifname);
872 ctrl_ifname = os_strdup(optarg);
875 ctrl_iface_dir = optarg;
883 interactive = (argc == optind) && (action_file == NULL);
886 printf("%s\n\n%s\n\n", hostapd_cli_version,
887 hostapd_cli_license);
891 if (ctrl_ifname == NULL) {
893 DIR *dir = opendir(ctrl_iface_dir);
895 while ((dent = readdir(dir))) {
896 if (os_strcmp(dent->d_name, ".") == 0
898 os_strcmp(dent->d_name, "..") == 0)
900 printf("Selected interface '%s'\n",
902 ctrl_ifname = os_strdup(dent->d_name);
908 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
910 if (warning_displayed)
911 printf("Connection established.\n");
916 perror("Failed to connect to hostapd - "
921 if (!warning_displayed) {
922 printf("Could not connect to hostapd - re-trying\n");
923 warning_displayed = 1;
929 signal(SIGINT, hostapd_cli_terminate);
930 signal(SIGTERM, hostapd_cli_terminate);
931 signal(SIGALRM, hostapd_cli_alarm);
933 if (interactive || action_file) {
934 if (wpa_ctrl_attach(ctrl_conn) == 0) {
935 hostapd_cli_attached = 1;
937 printf("Warning: Failed to attach to hostapd.\n");
943 if (daemonize && os_daemonize(pid_file))
947 hostapd_cli_interactive();
948 else if (action_file)
949 hostapd_cli_action(ctrl_conn);
951 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
953 os_free(ctrl_ifname);
954 hostapd_cli_cleanup();