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 #endif /* CONFIG_WPS */
98 " help show this usage help\n"
99 " interface [ifname] show interfaces/select interface\n"
100 " level <debug level> change debug level\n"
101 " license show full hostapd_cli license\n"
102 " quit exit hostapd_cli\n";
104 static struct wpa_ctrl *ctrl_conn;
105 static int hostapd_cli_quit = 0;
106 static int hostapd_cli_attached = 0;
107 static const char *ctrl_iface_dir = "/var/run/hostapd";
108 static char *ctrl_ifname = NULL;
109 static const char *pid_file = NULL;
110 static const char *action_file = NULL;
111 static int ping_interval = 5;
114 static void usage(void)
116 fprintf(stderr, "%s\n", hostapd_cli_version);
119 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
121 " [-G<ping interval>] [command..]\n"
124 " -h help (show this usage text)\n"
125 " -v shown version information\n"
126 " -p<path> path to find control sockets (default: "
127 "/var/run/hostapd)\n"
128 " -a<file> run in daemon mode executing the action file "
131 " -B run a daemon in the background\n"
132 " -i<ifname> Interface to listen on (default: first "
133 "interface found in the\n"
140 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
148 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
149 cfile = malloc(flen);
152 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
154 ctrl_conn = wpa_ctrl_open(cfile);
160 static void hostapd_cli_close_connection(void)
162 if (ctrl_conn == NULL)
165 if (hostapd_cli_attached) {
166 wpa_ctrl_detach(ctrl_conn);
167 hostapd_cli_attached = 0;
169 wpa_ctrl_close(ctrl_conn);
174 static void hostapd_cli_msg_cb(char *msg, size_t len)
180 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
186 if (ctrl_conn == NULL) {
187 printf("Not connected to hostapd - command dropped.\n");
190 len = sizeof(buf) - 1;
191 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
194 printf("'%s' command timed out.\n", cmd);
196 } else if (ret < 0) {
197 printf("'%s' command failed.\n", cmd);
208 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
210 return _wpa_ctrl_command(ctrl, cmd, 1);
214 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
216 return wpa_ctrl_command(ctrl, "PING");
220 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
222 return wpa_ctrl_command(ctrl, "MIB");
226 static int hostapd_cli_exec(const char *program, const char *arg1,
234 len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
235 cmd = os_malloc(len);
238 res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
239 if (res < 0 || (size_t) res >= len) {
247 #endif /* _WIN32_WCE */
254 static void hostapd_cli_action_process(char *msg, size_t len)
260 pos = os_strchr(pos, '>');
267 hostapd_cli_exec(action_file, ctrl_ifname, pos);
271 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
275 printf("Invalid 'sta' command - exactly one argument, STA "
276 "address, is required.\n");
279 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
280 return wpa_ctrl_command(ctrl, buf);
284 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
289 printf("Invalid 'new_sta' command - exactly one argument, STA "
290 "address, is required.\n");
293 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
294 return wpa_ctrl_command(ctrl, buf);
298 static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
303 printf("Invalid 'deauthenticate' command - exactly one "
304 "argument, STA address, is required.\n");
308 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
311 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
312 return wpa_ctrl_command(ctrl, buf);
316 static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
321 printf("Invalid 'disassociate' command - exactly one "
322 "argument, STA address, is required.\n");
326 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
329 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
330 return wpa_ctrl_command(ctrl, buf);
334 #ifdef CONFIG_IEEE80211W
335 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
340 printf("Invalid 'sa_query' command - exactly one argument, "
341 "STA address, is required.\n");
344 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
345 return wpa_ctrl_command(ctrl, buf);
347 #endif /* CONFIG_IEEE80211W */
351 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
356 printf("Invalid 'wps_pin' command - at least two arguments, "
357 "UUID and PIN, are required.\n");
361 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
362 argv[0], argv[1], argv[2]);
364 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
365 return wpa_ctrl_command(ctrl, buf);
369 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
372 return wpa_ctrl_command(ctrl, "WPS_PBC");
376 #ifdef CONFIG_WPS_OOB
377 static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
383 if (argc != 3 && argc != 4) {
384 printf("Invalid WPS_OOB command: need three or four "
386 "- DEV_TYPE: use 'ufd' or 'nfc'\n"
387 "- PATH: path of OOB device like '/mnt'\n"
388 "- METHOD: OOB method 'pin-e' or 'pin-r', "
390 "- DEV_NAME: (only for NFC) device name like "
396 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
397 argv[0], argv[1], argv[2]);
399 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
400 argv[0], argv[1], argv[2], argv[3]);
401 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
402 printf("Too long WPS_OOB command.\n");
405 return wpa_ctrl_command(ctrl, cmd);
407 #endif /* CONFIG_WPS_OOB */
408 #endif /* CONFIG_WPS */
411 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
412 char *addr, size_t addr_len)
414 char buf[4096], *pos;
418 if (ctrl_conn == NULL) {
419 printf("Not connected to hostapd - command dropped.\n");
422 len = sizeof(buf) - 1;
423 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
426 printf("'%s' command timed out.\n", cmd);
428 } else if (ret < 0) {
429 printf("'%s' command failed.\n", cmd);
434 if (memcmp(buf, "FAIL", 4) == 0)
439 while (*pos != '\0' && *pos != '\n')
442 os_strlcpy(addr, buf, addr_len);
447 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
450 char addr[32], cmd[64];
452 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
455 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
456 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
462 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
464 printf("%s", commands_help);
469 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
472 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
477 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
479 hostapd_cli_quit = 1;
484 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
488 printf("Invalid LEVEL command: needs one argument (debug "
492 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
493 return wpa_ctrl_command(ctrl, cmd);
497 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
502 dir = opendir(ctrl_iface_dir);
504 printf("Control interface directory '%s' could not be "
505 "openned.\n", ctrl_iface_dir);
509 printf("Available interfaces:\n");
510 while ((dent = readdir(dir))) {
511 if (strcmp(dent->d_name, ".") == 0 ||
512 strcmp(dent->d_name, "..") == 0)
514 printf("%s\n", dent->d_name);
520 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
524 hostapd_cli_list_interfaces(ctrl);
528 hostapd_cli_close_connection();
530 ctrl_ifname = strdup(argv[0]);
532 if (hostapd_cli_open_connection(ctrl_ifname)) {
533 printf("Connected to interface '%s.\n", ctrl_ifname);
534 if (wpa_ctrl_attach(ctrl_conn) == 0) {
535 hostapd_cli_attached = 1;
537 printf("Warning: Failed to attach to "
541 printf("Could not connect to interface '%s' - re-trying\n",
548 struct hostapd_cli_cmd {
550 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
553 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
554 { "ping", hostapd_cli_cmd_ping },
555 { "mib", hostapd_cli_cmd_mib },
556 { "sta", hostapd_cli_cmd_sta },
557 { "all_sta", hostapd_cli_cmd_all_sta },
558 { "new_sta", hostapd_cli_cmd_new_sta },
559 { "deauthenticate", hostapd_cli_cmd_deauthenticate },
560 { "disassociate", hostapd_cli_cmd_disassociate },
561 #ifdef CONFIG_IEEE80211W
562 { "sa_query", hostapd_cli_cmd_sa_query },
563 #endif /* CONFIG_IEEE80211W */
565 { "wps_pin", hostapd_cli_cmd_wps_pin },
566 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
567 #ifdef CONFIG_WPS_OOB
568 { "wps_oob", hostapd_cli_cmd_wps_oob },
569 #endif /* CONFIG_WPS_OOB */
570 #endif /* CONFIG_WPS */
571 { "help", hostapd_cli_cmd_help },
572 { "interface", hostapd_cli_cmd_interface },
573 { "level", hostapd_cli_cmd_level },
574 { "license", hostapd_cli_cmd_license },
575 { "quit", hostapd_cli_cmd_quit },
580 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
582 struct hostapd_cli_cmd *cmd, *match = NULL;
586 cmd = hostapd_cli_commands;
588 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
596 printf("Ambiguous command '%s'; possible commands:", argv[0]);
597 cmd = hostapd_cli_commands;
599 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
601 printf(" %s", cmd->cmd);
606 } else if (count == 0) {
607 printf("Unknown command '%s'\n", argv[0]);
609 match->handler(ctrl, argc - 1, &argv[1]);
614 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
618 if (ctrl_conn == NULL)
620 while (wpa_ctrl_pending(ctrl)) {
622 size_t len = sizeof(buf) - 1;
623 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
626 hostapd_cli_action_process(buf, len);
628 if (in_read && first)
634 printf("Could not read pending message.\n");
641 static void hostapd_cli_interactive(void)
643 const int max_args = 10;
644 char cmd[256], *res, *argv[max_args], *pos;
647 printf("\nInteractive mode\n\n");
650 hostapd_cli_recv_pending(ctrl_conn, 0, 0);
652 alarm(ping_interval);
653 res = fgets(cmd, sizeof(cmd), stdin);
658 while (*pos != '\0') {
674 if (argc == max_args)
676 while (*pos != '\0' && *pos != ' ')
682 wpa_request(ctrl_conn, argc, argv);
683 } while (!hostapd_cli_quit);
687 static void hostapd_cli_cleanup(void)
689 hostapd_cli_close_connection();
691 os_daemonize_terminate(pid_file);
697 static void hostapd_cli_terminate(int sig)
699 hostapd_cli_cleanup();
704 static void hostapd_cli_alarm(int sig)
706 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
707 printf("Connection to hostapd lost - trying to reconnect\n");
708 hostapd_cli_close_connection();
711 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
713 printf("Connection to hostapd re-established\n");
714 if (wpa_ctrl_attach(ctrl_conn) == 0) {
715 hostapd_cli_attached = 1;
717 printf("Warning: Failed to attach to "
723 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
724 alarm(ping_interval);
728 static void hostapd_cli_action(struct wpa_ctrl *ctrl)
736 fd = wpa_ctrl_get_fd(ctrl);
738 while (!hostapd_cli_quit) {
741 tv.tv_sec = ping_interval;
743 res = select(fd + 1, &rfds, NULL, NULL, &tv);
744 if (res < 0 && errno != EINTR) {
749 if (FD_ISSET(fd, &rfds))
750 hostapd_cli_recv_pending(ctrl, 0, 1);
752 len = sizeof(buf) - 1;
753 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
754 hostapd_cli_action_process) < 0 ||
755 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
756 printf("hostapd did not reply to PING "
757 "command - exiting\n");
765 int main(int argc, char *argv[])
768 int warning_displayed = 0;
772 if (os_program_init())
776 c = getopt(argc, argv, "a:BhG:i:p:v");
781 action_file = optarg;
787 ping_interval = atoi(optarg);
793 printf("%s\n", hostapd_cli_version);
796 os_free(ctrl_ifname);
797 ctrl_ifname = os_strdup(optarg);
800 ctrl_iface_dir = optarg;
808 interactive = (argc == optind) && (action_file == NULL);
811 printf("%s\n\n%s\n\n", hostapd_cli_version,
812 hostapd_cli_license);
816 if (ctrl_ifname == NULL) {
818 DIR *dir = opendir(ctrl_iface_dir);
820 while ((dent = readdir(dir))) {
821 if (os_strcmp(dent->d_name, ".") == 0
823 os_strcmp(dent->d_name, "..") == 0)
825 printf("Selected interface '%s'\n",
827 ctrl_ifname = os_strdup(dent->d_name);
833 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
835 if (warning_displayed)
836 printf("Connection established.\n");
841 perror("Failed to connect to hostapd - "
846 if (!warning_displayed) {
847 printf("Could not connect to hostapd - re-trying\n");
848 warning_displayed = 1;
854 signal(SIGINT, hostapd_cli_terminate);
855 signal(SIGTERM, hostapd_cli_terminate);
856 signal(SIGALRM, hostapd_cli_alarm);
858 if (interactive || action_file) {
859 if (wpa_ctrl_attach(ctrl_conn) == 0) {
860 hostapd_cli_attached = 1;
862 printf("Warning: Failed to attach to hostapd.\n");
868 if (daemonize && os_daemonize(pid_file))
872 hostapd_cli_interactive();
873 else if (action_file)
874 hostapd_cli_action(ctrl_conn);
876 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
878 os_free(ctrl_ifname);
879 hostapd_cli_cleanup();