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 " get_config show current configuration\n"
101 " help show this usage help\n"
102 " interface [ifname] show interfaces/select interface\n"
103 " level <debug level> change debug level\n"
104 " license show full hostapd_cli license\n"
105 " quit exit hostapd_cli\n";
107 static struct wpa_ctrl *ctrl_conn;
108 static int hostapd_cli_quit = 0;
109 static int hostapd_cli_attached = 0;
110 static const char *ctrl_iface_dir = "/var/run/hostapd";
111 static char *ctrl_ifname = NULL;
112 static const char *pid_file = NULL;
113 static const char *action_file = NULL;
114 static int ping_interval = 5;
117 static void usage(void)
119 fprintf(stderr, "%s\n", hostapd_cli_version);
122 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
124 " [-G<ping interval>] [command..]\n"
127 " -h help (show this usage text)\n"
128 " -v shown version information\n"
129 " -p<path> path to find control sockets (default: "
130 "/var/run/hostapd)\n"
131 " -a<file> run in daemon mode executing the action file "
134 " -B run a daemon in the background\n"
135 " -i<ifname> Interface to listen on (default: first "
136 "interface found in the\n"
143 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
151 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
152 cfile = malloc(flen);
155 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
157 ctrl_conn = wpa_ctrl_open(cfile);
163 static void hostapd_cli_close_connection(void)
165 if (ctrl_conn == NULL)
168 if (hostapd_cli_attached) {
169 wpa_ctrl_detach(ctrl_conn);
170 hostapd_cli_attached = 0;
172 wpa_ctrl_close(ctrl_conn);
177 static void hostapd_cli_msg_cb(char *msg, size_t len)
183 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
189 if (ctrl_conn == NULL) {
190 printf("Not connected to hostapd - command dropped.\n");
193 len = sizeof(buf) - 1;
194 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
197 printf("'%s' command timed out.\n", cmd);
199 } else if (ret < 0) {
200 printf("'%s' command failed.\n", cmd);
211 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
213 return _wpa_ctrl_command(ctrl, cmd, 1);
217 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
219 return wpa_ctrl_command(ctrl, "PING");
223 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
225 return wpa_ctrl_command(ctrl, "MIB");
229 static int hostapd_cli_exec(const char *program, const char *arg1,
237 len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
238 cmd = os_malloc(len);
241 res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
242 if (res < 0 || (size_t) res >= len) {
250 #endif /* _WIN32_WCE */
257 static void hostapd_cli_action_process(char *msg, size_t len)
263 pos = os_strchr(pos, '>');
270 hostapd_cli_exec(action_file, ctrl_ifname, pos);
274 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
278 printf("Invalid 'sta' command - exactly one argument, STA "
279 "address, is required.\n");
282 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
283 return wpa_ctrl_command(ctrl, buf);
287 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
292 printf("Invalid 'new_sta' command - exactly one argument, STA "
293 "address, is required.\n");
296 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
297 return wpa_ctrl_command(ctrl, buf);
301 static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
306 printf("Invalid 'deauthenticate' command - exactly one "
307 "argument, STA address, is required.\n");
311 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
314 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
315 return wpa_ctrl_command(ctrl, buf);
319 static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
324 printf("Invalid 'disassociate' command - exactly one "
325 "argument, STA address, is required.\n");
329 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
332 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
333 return wpa_ctrl_command(ctrl, buf);
337 #ifdef CONFIG_IEEE80211W
338 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
343 printf("Invalid 'sa_query' command - exactly one argument, "
344 "STA address, is required.\n");
347 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
348 return wpa_ctrl_command(ctrl, buf);
350 #endif /* CONFIG_IEEE80211W */
354 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
359 printf("Invalid 'wps_pin' command - at least two arguments, "
360 "UUID and PIN, are required.\n");
364 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
365 argv[0], argv[1], argv[2], argv[3]);
367 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
368 argv[0], argv[1], argv[2]);
370 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
371 return wpa_ctrl_command(ctrl, buf);
375 static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
381 if (argc != 1 && argc != 2) {
382 printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
383 "- PIN to be verified\n");
388 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
391 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
393 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
394 printf("Too long WPS_CHECK_PIN command.\n");
397 return wpa_ctrl_command(ctrl, cmd);
401 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
404 return wpa_ctrl_command(ctrl, "WPS_PBC");
408 #ifdef CONFIG_WPS_OOB
409 static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
415 if (argc != 3 && argc != 4) {
416 printf("Invalid WPS_OOB command: need three or four "
418 "- DEV_TYPE: use 'ufd' or 'nfc'\n"
419 "- PATH: path of OOB device like '/mnt'\n"
420 "- METHOD: OOB method 'pin-e' or 'pin-r', "
422 "- DEV_NAME: (only for NFC) device name like "
428 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
429 argv[0], argv[1], argv[2]);
431 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
432 argv[0], argv[1], argv[2], argv[3]);
433 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
434 printf("Too long WPS_OOB command.\n");
437 return wpa_ctrl_command(ctrl, cmd);
439 #endif /* CONFIG_WPS_OOB */
442 static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
447 printf("Invalid 'wps_ap_pin' command - at least one argument "
452 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
453 argv[0], argv[1], argv[2]);
455 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
458 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
459 return wpa_ctrl_command(ctrl, buf);
461 #endif /* CONFIG_WPS */
464 static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
467 return wpa_ctrl_command(ctrl, "GET_CONFIG");
471 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
472 char *addr, size_t addr_len)
474 char buf[4096], *pos;
478 if (ctrl_conn == NULL) {
479 printf("Not connected to hostapd - command dropped.\n");
482 len = sizeof(buf) - 1;
483 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
486 printf("'%s' command timed out.\n", cmd);
488 } else if (ret < 0) {
489 printf("'%s' command failed.\n", cmd);
494 if (memcmp(buf, "FAIL", 4) == 0)
499 while (*pos != '\0' && *pos != '\n')
502 os_strlcpy(addr, buf, addr_len);
507 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
510 char addr[32], cmd[64];
512 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
515 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
516 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
522 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
524 printf("%s", commands_help);
529 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
532 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
537 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
539 hostapd_cli_quit = 1;
544 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
548 printf("Invalid LEVEL command: needs one argument (debug "
552 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
553 return wpa_ctrl_command(ctrl, cmd);
557 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
562 dir = opendir(ctrl_iface_dir);
564 printf("Control interface directory '%s' could not be "
565 "openned.\n", ctrl_iface_dir);
569 printf("Available interfaces:\n");
570 while ((dent = readdir(dir))) {
571 if (strcmp(dent->d_name, ".") == 0 ||
572 strcmp(dent->d_name, "..") == 0)
574 printf("%s\n", dent->d_name);
580 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
584 hostapd_cli_list_interfaces(ctrl);
588 hostapd_cli_close_connection();
590 ctrl_ifname = strdup(argv[0]);
592 if (hostapd_cli_open_connection(ctrl_ifname)) {
593 printf("Connected to interface '%s.\n", ctrl_ifname);
594 if (wpa_ctrl_attach(ctrl_conn) == 0) {
595 hostapd_cli_attached = 1;
597 printf("Warning: Failed to attach to "
601 printf("Could not connect to interface '%s' - re-trying\n",
608 static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
614 printf("Invalid SET command: needs two arguments (variable "
615 "name and value)\n");
619 res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
620 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
621 printf("Too long SET command.\n");
624 return wpa_ctrl_command(ctrl, cmd);
628 struct hostapd_cli_cmd {
630 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
633 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
634 { "ping", hostapd_cli_cmd_ping },
635 { "mib", hostapd_cli_cmd_mib },
636 { "sta", hostapd_cli_cmd_sta },
637 { "all_sta", hostapd_cli_cmd_all_sta },
638 { "new_sta", hostapd_cli_cmd_new_sta },
639 { "deauthenticate", hostapd_cli_cmd_deauthenticate },
640 { "disassociate", hostapd_cli_cmd_disassociate },
641 #ifdef CONFIG_IEEE80211W
642 { "sa_query", hostapd_cli_cmd_sa_query },
643 #endif /* CONFIG_IEEE80211W */
645 { "wps_pin", hostapd_cli_cmd_wps_pin },
646 { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
647 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
648 #ifdef CONFIG_WPS_OOB
649 { "wps_oob", hostapd_cli_cmd_wps_oob },
650 #endif /* CONFIG_WPS_OOB */
651 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
652 #endif /* CONFIG_WPS */
653 { "get_config", hostapd_cli_cmd_get_config },
654 { "help", hostapd_cli_cmd_help },
655 { "interface", hostapd_cli_cmd_interface },
656 { "level", hostapd_cli_cmd_level },
657 { "license", hostapd_cli_cmd_license },
658 { "quit", hostapd_cli_cmd_quit },
659 { "set", hostapd_cli_cmd_set },
664 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
666 struct hostapd_cli_cmd *cmd, *match = NULL;
670 cmd = hostapd_cli_commands;
672 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
680 printf("Ambiguous command '%s'; possible commands:", argv[0]);
681 cmd = hostapd_cli_commands;
683 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
685 printf(" %s", cmd->cmd);
690 } else if (count == 0) {
691 printf("Unknown command '%s'\n", argv[0]);
693 match->handler(ctrl, argc - 1, &argv[1]);
698 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
702 if (ctrl_conn == NULL)
704 while (wpa_ctrl_pending(ctrl)) {
706 size_t len = sizeof(buf) - 1;
707 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
710 hostapd_cli_action_process(buf, len);
712 if (in_read && first)
718 printf("Could not read pending message.\n");
725 static void hostapd_cli_interactive(void)
727 const int max_args = 10;
728 char cmd[256], *res, *argv[max_args], *pos;
731 printf("\nInteractive mode\n\n");
734 hostapd_cli_recv_pending(ctrl_conn, 0, 0);
736 alarm(ping_interval);
737 res = fgets(cmd, sizeof(cmd), stdin);
742 while (*pos != '\0') {
758 if (argc == max_args)
760 while (*pos != '\0' && *pos != ' ')
766 wpa_request(ctrl_conn, argc, argv);
767 } while (!hostapd_cli_quit);
771 static void hostapd_cli_cleanup(void)
773 hostapd_cli_close_connection();
775 os_daemonize_terminate(pid_file);
781 static void hostapd_cli_terminate(int sig)
783 hostapd_cli_cleanup();
788 static void hostapd_cli_alarm(int sig)
790 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
791 printf("Connection to hostapd lost - trying to reconnect\n");
792 hostapd_cli_close_connection();
795 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
797 printf("Connection to hostapd re-established\n");
798 if (wpa_ctrl_attach(ctrl_conn) == 0) {
799 hostapd_cli_attached = 1;
801 printf("Warning: Failed to attach to "
807 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
808 alarm(ping_interval);
812 static void hostapd_cli_action(struct wpa_ctrl *ctrl)
820 fd = wpa_ctrl_get_fd(ctrl);
822 while (!hostapd_cli_quit) {
825 tv.tv_sec = ping_interval;
827 res = select(fd + 1, &rfds, NULL, NULL, &tv);
828 if (res < 0 && errno != EINTR) {
833 if (FD_ISSET(fd, &rfds))
834 hostapd_cli_recv_pending(ctrl, 0, 1);
836 len = sizeof(buf) - 1;
837 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
838 hostapd_cli_action_process) < 0 ||
839 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
840 printf("hostapd did not reply to PING "
841 "command - exiting\n");
849 int main(int argc, char *argv[])
852 int warning_displayed = 0;
856 if (os_program_init())
860 c = getopt(argc, argv, "a:BhG:i:p:v");
865 action_file = optarg;
871 ping_interval = atoi(optarg);
877 printf("%s\n", hostapd_cli_version);
880 os_free(ctrl_ifname);
881 ctrl_ifname = os_strdup(optarg);
884 ctrl_iface_dir = optarg;
892 interactive = (argc == optind) && (action_file == NULL);
895 printf("%s\n\n%s\n\n", hostapd_cli_version,
896 hostapd_cli_license);
900 if (ctrl_ifname == NULL) {
902 DIR *dir = opendir(ctrl_iface_dir);
904 while ((dent = readdir(dir))) {
905 if (os_strcmp(dent->d_name, ".") == 0
907 os_strcmp(dent->d_name, "..") == 0)
909 printf("Selected interface '%s'\n",
911 ctrl_ifname = os_strdup(dent->d_name);
917 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
919 if (warning_displayed)
920 printf("Connection established.\n");
925 perror("Failed to connect to hostapd - "
930 if (!warning_displayed) {
931 printf("Could not connect to hostapd - re-trying\n");
932 warning_displayed = 1;
938 signal(SIGINT, hostapd_cli_terminate);
939 signal(SIGTERM, hostapd_cli_terminate);
940 signal(SIGALRM, hostapd_cli_alarm);
942 if (interactive || action_file) {
943 if (wpa_ctrl_attach(ctrl_conn) == 0) {
944 hostapd_cli_attached = 1;
946 printf("Warning: Failed to attach to hostapd.\n");
952 if (daemonize && os_daemonize(pid_file))
956 hostapd_cli_interactive();
957 else if (action_file)
958 hostapd_cli_action(ctrl_conn);
960 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
962 os_free(ctrl_ifname);
963 hostapd_cli_cleanup();