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 #ifdef CONFIG_IEEE80211W
87 " sa_query <addr> send SA Query to a station\n"
88 #endif /* CONFIG_IEEE80211W */
90 " wps_pin <uuid> <pin> [timeout] add WPS Enrollee PIN (Device Password)\n"
91 " wps_pbc indicate button pushed to initiate PBC\n"
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)
114 fprintf(stderr, "%s\n", hostapd_cli_version);
117 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
119 " [-G<ping interval>] [command..]\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 "
129 " -B run a daemon in the background\n"
130 " -i<ifname> Interface to listen on (default: first "
131 "interface found in the\n"
138 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
146 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
147 cfile = malloc(flen);
150 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
152 ctrl_conn = wpa_ctrl_open(cfile);
158 static void hostapd_cli_close_connection(void)
160 if (ctrl_conn == NULL)
163 if (hostapd_cli_attached) {
164 wpa_ctrl_detach(ctrl_conn);
165 hostapd_cli_attached = 0;
167 wpa_ctrl_close(ctrl_conn);
172 static void hostapd_cli_msg_cb(char *msg, size_t len)
178 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
184 if (ctrl_conn == NULL) {
185 printf("Not connected to hostapd - command dropped.\n");
188 len = sizeof(buf) - 1;
189 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
192 printf("'%s' command timed out.\n", cmd);
194 } else if (ret < 0) {
195 printf("'%s' command failed.\n", cmd);
206 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
208 return _wpa_ctrl_command(ctrl, cmd, 1);
212 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
214 return wpa_ctrl_command(ctrl, "PING");
218 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
220 return wpa_ctrl_command(ctrl, "MIB");
224 static int hostapd_cli_exec(const char *program, const char *arg1,
232 len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
233 cmd = os_malloc(len);
236 res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
237 if (res < 0 || (size_t) res >= len) {
245 #endif /* _WIN32_WCE */
252 static void hostapd_cli_action_process(char *msg, size_t len)
258 pos = os_strchr(pos, '>');
265 hostapd_cli_exec(action_file, ctrl_ifname, pos);
269 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
273 printf("Invalid 'sta' command - exactly one argument, STA "
274 "address, is required.\n");
277 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
278 return wpa_ctrl_command(ctrl, buf);
282 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
287 printf("Invalid 'new_sta' command - exactly one argument, STA "
288 "address, is required.\n");
291 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
292 return wpa_ctrl_command(ctrl, buf);
296 static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
301 printf("Invalid 'deauthenticate' command - exactly one "
302 "argument, STA address, is required.\n");
306 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
309 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
310 return wpa_ctrl_command(ctrl, buf);
314 static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
319 printf("Invalid 'disassociate' command - exactly one "
320 "argument, STA address, is required.\n");
324 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
327 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
328 return wpa_ctrl_command(ctrl, buf);
332 #ifdef CONFIG_IEEE80211W
333 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
338 printf("Invalid 'sa_query' command - exactly one argument, "
339 "STA address, is required.\n");
342 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
343 return wpa_ctrl_command(ctrl, buf);
345 #endif /* CONFIG_IEEE80211W */
349 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
354 printf("Invalid 'wps_pin' command - at least two arguments, "
355 "UUID and PIN, are required.\n");
359 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
360 argv[0], argv[1], argv[2]);
362 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
363 return wpa_ctrl_command(ctrl, buf);
367 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
370 return wpa_ctrl_command(ctrl, "WPS_PBC");
374 #ifdef CONFIG_WPS_OOB
375 static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
381 if (argc != 3 && argc != 4) {
382 printf("Invalid WPS_OOB command: need three or four "
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', "
388 "- DEV_NAME: (only for NFC) device name like "
394 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
395 argv[0], argv[1], argv[2]);
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");
403 return wpa_ctrl_command(ctrl, cmd);
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)
412 char buf[4096], *pos;
416 if (ctrl_conn == NULL) {
417 printf("Not connected to hostapd - command dropped.\n");
420 len = sizeof(buf) - 1;
421 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
424 printf("'%s' command timed out.\n", cmd);
426 } else if (ret < 0) {
427 printf("'%s' command failed.\n", cmd);
432 if (memcmp(buf, "FAIL", 4) == 0)
437 while (*pos != '\0' && *pos != '\n')
440 os_strlcpy(addr, buf, addr_len);
445 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
448 char addr[32], cmd[64];
450 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
453 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
454 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
460 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
462 printf("%s", commands_help);
467 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
470 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
475 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
477 hostapd_cli_quit = 1;
482 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
486 printf("Invalid LEVEL command: needs one argument (debug "
490 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
491 return wpa_ctrl_command(ctrl, cmd);
495 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
500 dir = opendir(ctrl_iface_dir);
502 printf("Control interface directory '%s' could not be "
503 "openned.\n", ctrl_iface_dir);
507 printf("Available interfaces:\n");
508 while ((dent = readdir(dir))) {
509 if (strcmp(dent->d_name, ".") == 0 ||
510 strcmp(dent->d_name, "..") == 0)
512 printf("%s\n", dent->d_name);
518 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
522 hostapd_cli_list_interfaces(ctrl);
526 hostapd_cli_close_connection();
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;
535 printf("Warning: Failed to attach to "
539 printf("Could not connect to interface '%s' - re-trying\n",
546 struct hostapd_cli_cmd {
548 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
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 */
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 },
578 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
580 struct hostapd_cli_cmd *cmd, *match = NULL;
584 cmd = hostapd_cli_commands;
586 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
594 printf("Ambiguous command '%s'; possible commands:", argv[0]);
595 cmd = hostapd_cli_commands;
597 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
599 printf(" %s", cmd->cmd);
604 } else if (count == 0) {
605 printf("Unknown command '%s'\n", argv[0]);
607 match->handler(ctrl, argc - 1, &argv[1]);
612 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
616 if (ctrl_conn == NULL)
618 while (wpa_ctrl_pending(ctrl)) {
620 size_t len = sizeof(buf) - 1;
621 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
624 hostapd_cli_action_process(buf, len);
626 if (in_read && first)
632 printf("Could not read pending message.\n");
639 static void hostapd_cli_interactive(void)
641 const int max_args = 10;
642 char cmd[256], *res, *argv[max_args], *pos;
645 printf("\nInteractive mode\n\n");
648 hostapd_cli_recv_pending(ctrl_conn, 0, 0);
650 alarm(ping_interval);
651 res = fgets(cmd, sizeof(cmd), stdin);
656 while (*pos != '\0') {
672 if (argc == max_args)
674 while (*pos != '\0' && *pos != ' ')
680 wpa_request(ctrl_conn, argc, argv);
681 } while (!hostapd_cli_quit);
685 static void hostapd_cli_cleanup(void)
687 hostapd_cli_close_connection();
689 os_daemonize_terminate(pid_file);
695 static void hostapd_cli_terminate(int sig)
697 hostapd_cli_cleanup();
702 static void hostapd_cli_alarm(int sig)
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();
709 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
711 printf("Connection to hostapd re-established\n");
712 if (wpa_ctrl_attach(ctrl_conn) == 0) {
713 hostapd_cli_attached = 1;
715 printf("Warning: Failed to attach to "
721 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
722 alarm(ping_interval);
726 static void hostapd_cli_action(struct wpa_ctrl *ctrl)
734 fd = wpa_ctrl_get_fd(ctrl);
736 while (!hostapd_cli_quit) {
739 tv.tv_sec = ping_interval;
741 res = select(fd + 1, &rfds, NULL, NULL, &tv);
742 if (res < 0 && errno != EINTR) {
747 if (FD_ISSET(fd, &rfds))
748 hostapd_cli_recv_pending(ctrl, 0, 1);
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");
763 int main(int argc, char *argv[])
766 int warning_displayed = 0;
770 if (os_program_init())
774 c = getopt(argc, argv, "a:BhG:i:p:v");
779 action_file = optarg;
785 ping_interval = atoi(optarg);
791 printf("%s\n", hostapd_cli_version);
794 os_free(ctrl_ifname);
795 ctrl_ifname = os_strdup(optarg);
798 ctrl_iface_dir = optarg;
806 interactive = (argc == optind) && (action_file == NULL);
809 printf("%s\n\n%s\n\n", hostapd_cli_version,
810 hostapd_cli_license);
814 if (ctrl_ifname == NULL) {
816 DIR *dir = opendir(ctrl_iface_dir);
818 while ((dent = readdir(dir))) {
819 if (os_strcmp(dent->d_name, ".") == 0
821 os_strcmp(dent->d_name, "..") == 0)
823 printf("Selected interface '%s'\n",
825 ctrl_ifname = os_strdup(dent->d_name);
831 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
833 if (warning_displayed)
834 printf("Connection established.\n");
839 perror("Failed to connect to hostapd - "
844 if (!warning_displayed) {
845 printf("Could not connect to hostapd - re-trying\n");
846 warning_displayed = 1;
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;
860 printf("Warning: Failed to attach to hostapd.\n");
866 if (daemonize && os_daemonize(pid_file))
870 hostapd_cli_interactive();
871 else if (action_file)
872 hostapd_cli_action(ctrl_conn);
874 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
876 os_free(ctrl_ifname);
877 hostapd_cli_cleanup();