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_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 %s",
363 argv[0], argv[1], argv[2], argv[3]);
365 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
366 argv[0], argv[1], argv[2]);
368 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
369 return wpa_ctrl_command(ctrl, buf);
373 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
376 return wpa_ctrl_command(ctrl, "WPS_PBC");
380 #ifdef CONFIG_WPS_OOB
381 static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
387 if (argc != 3 && argc != 4) {
388 printf("Invalid WPS_OOB command: need three or four "
390 "- DEV_TYPE: use 'ufd' or 'nfc'\n"
391 "- PATH: path of OOB device like '/mnt'\n"
392 "- METHOD: OOB method 'pin-e' or 'pin-r', "
394 "- DEV_NAME: (only for NFC) device name like "
400 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
401 argv[0], argv[1], argv[2]);
403 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
404 argv[0], argv[1], argv[2], argv[3]);
405 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
406 printf("Too long WPS_OOB command.\n");
409 return wpa_ctrl_command(ctrl, cmd);
411 #endif /* CONFIG_WPS_OOB */
414 static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
419 printf("Invalid 'wps_ap_pin' command - at least one argument "
424 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
425 argv[0], argv[1], argv[2]);
427 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
430 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
431 return wpa_ctrl_command(ctrl, buf);
433 #endif /* CONFIG_WPS */
436 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
437 char *addr, size_t addr_len)
439 char buf[4096], *pos;
443 if (ctrl_conn == NULL) {
444 printf("Not connected to hostapd - command dropped.\n");
447 len = sizeof(buf) - 1;
448 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
451 printf("'%s' command timed out.\n", cmd);
453 } else if (ret < 0) {
454 printf("'%s' command failed.\n", cmd);
459 if (memcmp(buf, "FAIL", 4) == 0)
464 while (*pos != '\0' && *pos != '\n')
467 os_strlcpy(addr, buf, addr_len);
472 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
475 char addr[32], cmd[64];
477 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
480 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
481 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
487 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
489 printf("%s", commands_help);
494 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
497 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
502 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
504 hostapd_cli_quit = 1;
509 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
513 printf("Invalid LEVEL command: needs one argument (debug "
517 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
518 return wpa_ctrl_command(ctrl, cmd);
522 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
527 dir = opendir(ctrl_iface_dir);
529 printf("Control interface directory '%s' could not be "
530 "openned.\n", ctrl_iface_dir);
534 printf("Available interfaces:\n");
535 while ((dent = readdir(dir))) {
536 if (strcmp(dent->d_name, ".") == 0 ||
537 strcmp(dent->d_name, "..") == 0)
539 printf("%s\n", dent->d_name);
545 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
549 hostapd_cli_list_interfaces(ctrl);
553 hostapd_cli_close_connection();
555 ctrl_ifname = strdup(argv[0]);
557 if (hostapd_cli_open_connection(ctrl_ifname)) {
558 printf("Connected to interface '%s.\n", ctrl_ifname);
559 if (wpa_ctrl_attach(ctrl_conn) == 0) {
560 hostapd_cli_attached = 1;
562 printf("Warning: Failed to attach to "
566 printf("Could not connect to interface '%s' - re-trying\n",
573 static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
579 printf("Invalid SET command: needs two arguments (variable "
580 "name and value)\n");
584 res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
585 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
586 printf("Too long SET command.\n");
589 return wpa_ctrl_command(ctrl, cmd);
593 struct hostapd_cli_cmd {
595 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
598 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
599 { "ping", hostapd_cli_cmd_ping },
600 { "mib", hostapd_cli_cmd_mib },
601 { "sta", hostapd_cli_cmd_sta },
602 { "all_sta", hostapd_cli_cmd_all_sta },
603 { "new_sta", hostapd_cli_cmd_new_sta },
604 { "deauthenticate", hostapd_cli_cmd_deauthenticate },
605 { "disassociate", hostapd_cli_cmd_disassociate },
606 #ifdef CONFIG_IEEE80211W
607 { "sa_query", hostapd_cli_cmd_sa_query },
608 #endif /* CONFIG_IEEE80211W */
610 { "wps_pin", hostapd_cli_cmd_wps_pin },
611 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
612 #ifdef CONFIG_WPS_OOB
613 { "wps_oob", hostapd_cli_cmd_wps_oob },
614 #endif /* CONFIG_WPS_OOB */
615 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
616 #endif /* CONFIG_WPS */
617 { "help", hostapd_cli_cmd_help },
618 { "interface", hostapd_cli_cmd_interface },
619 { "level", hostapd_cli_cmd_level },
620 { "license", hostapd_cli_cmd_license },
621 { "quit", hostapd_cli_cmd_quit },
622 { "set", hostapd_cli_cmd_set },
627 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
629 struct hostapd_cli_cmd *cmd, *match = NULL;
633 cmd = hostapd_cli_commands;
635 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
643 printf("Ambiguous command '%s'; possible commands:", argv[0]);
644 cmd = hostapd_cli_commands;
646 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
648 printf(" %s", cmd->cmd);
653 } else if (count == 0) {
654 printf("Unknown command '%s'\n", argv[0]);
656 match->handler(ctrl, argc - 1, &argv[1]);
661 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
665 if (ctrl_conn == NULL)
667 while (wpa_ctrl_pending(ctrl)) {
669 size_t len = sizeof(buf) - 1;
670 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
673 hostapd_cli_action_process(buf, len);
675 if (in_read && first)
681 printf("Could not read pending message.\n");
688 static void hostapd_cli_interactive(void)
690 const int max_args = 10;
691 char cmd[256], *res, *argv[max_args], *pos;
694 printf("\nInteractive mode\n\n");
697 hostapd_cli_recv_pending(ctrl_conn, 0, 0);
699 alarm(ping_interval);
700 res = fgets(cmd, sizeof(cmd), stdin);
705 while (*pos != '\0') {
721 if (argc == max_args)
723 while (*pos != '\0' && *pos != ' ')
729 wpa_request(ctrl_conn, argc, argv);
730 } while (!hostapd_cli_quit);
734 static void hostapd_cli_cleanup(void)
736 hostapd_cli_close_connection();
738 os_daemonize_terminate(pid_file);
744 static void hostapd_cli_terminate(int sig)
746 hostapd_cli_cleanup();
751 static void hostapd_cli_alarm(int sig)
753 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
754 printf("Connection to hostapd lost - trying to reconnect\n");
755 hostapd_cli_close_connection();
758 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
760 printf("Connection to hostapd re-established\n");
761 if (wpa_ctrl_attach(ctrl_conn) == 0) {
762 hostapd_cli_attached = 1;
764 printf("Warning: Failed to attach to "
770 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
771 alarm(ping_interval);
775 static void hostapd_cli_action(struct wpa_ctrl *ctrl)
783 fd = wpa_ctrl_get_fd(ctrl);
785 while (!hostapd_cli_quit) {
788 tv.tv_sec = ping_interval;
790 res = select(fd + 1, &rfds, NULL, NULL, &tv);
791 if (res < 0 && errno != EINTR) {
796 if (FD_ISSET(fd, &rfds))
797 hostapd_cli_recv_pending(ctrl, 0, 1);
799 len = sizeof(buf) - 1;
800 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
801 hostapd_cli_action_process) < 0 ||
802 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
803 printf("hostapd did not reply to PING "
804 "command - exiting\n");
812 int main(int argc, char *argv[])
815 int warning_displayed = 0;
819 if (os_program_init())
823 c = getopt(argc, argv, "a:BhG:i:p:v");
828 action_file = optarg;
834 ping_interval = atoi(optarg);
840 printf("%s\n", hostapd_cli_version);
843 os_free(ctrl_ifname);
844 ctrl_ifname = os_strdup(optarg);
847 ctrl_iface_dir = optarg;
855 interactive = (argc == optind) && (action_file == NULL);
858 printf("%s\n\n%s\n\n", hostapd_cli_version,
859 hostapd_cli_license);
863 if (ctrl_ifname == NULL) {
865 DIR *dir = opendir(ctrl_iface_dir);
867 while ((dent = readdir(dir))) {
868 if (os_strcmp(dent->d_name, ".") == 0
870 os_strcmp(dent->d_name, "..") == 0)
872 printf("Selected interface '%s'\n",
874 ctrl_ifname = os_strdup(dent->d_name);
880 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
882 if (warning_displayed)
883 printf("Connection established.\n");
888 perror("Failed to connect to hostapd - "
893 if (!warning_displayed) {
894 printf("Could not connect to hostapd - re-trying\n");
895 warning_displayed = 1;
901 signal(SIGINT, hostapd_cli_terminate);
902 signal(SIGTERM, hostapd_cli_terminate);
903 signal(SIGALRM, hostapd_cli_alarm);
905 if (interactive || action_file) {
906 if (wpa_ctrl_attach(ctrl_conn) == 0) {
907 hostapd_cli_attached = 1;
909 printf("Warning: Failed to attach to hostapd.\n");
915 if (daemonize && os_daemonize(pid_file))
919 hostapd_cli_interactive();
920 else if (action_file)
921 hostapd_cli_action(ctrl_conn);
923 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
925 os_free(ctrl_ifname);
926 hostapd_cli_cleanup();