2 * hostapd - command line interface for hostapd daemon
3 * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
12 #include "common/wpa_ctrl.h"
13 #include "common/ieee802_11_defs.h"
14 #include "utils/common.h"
15 #include "utils/eloop.h"
16 #include "utils/edit.h"
17 #include "common/version.h"
20 static const char *const hostapd_cli_version =
21 "hostapd_cli v" VERSION_STR "\n"
22 "Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors";
25 static const char *const hostapd_cli_license =
26 "This software may be distributed under the terms of the BSD license.\n"
27 "See README for more details.\n";
29 static const char *const hostapd_cli_full_license =
30 "This software may be distributed under the terms of the BSD license.\n"
32 "Redistribution and use in source and binary forms, with or without\n"
33 "modification, are permitted provided that the following conditions are\n"
36 "1. Redistributions of source code must retain the above copyright\n"
37 " notice, this list of conditions and the following disclaimer.\n"
39 "2. Redistributions in binary form must reproduce the above copyright\n"
40 " notice, this list of conditions and the following disclaimer in the\n"
41 " documentation and/or other materials provided with the distribution.\n"
43 "3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
44 " names of its contributors may be used to endorse or promote products\n"
45 " derived from this software without specific prior written permission.\n"
47 "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
48 "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
49 "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
50 "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
51 "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
52 "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
53 "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
54 "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
55 "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
56 "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
57 "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
60 static const char *const commands_help =
62 " mib get MIB variables (dot1x, dot11, radius)\n"
63 " sta <addr> get MIB variables for one station\n"
64 " all_sta get MIB variables for all stations\n"
65 " new_sta <addr> add a new station\n"
66 " deauthenticate <addr> deauthenticate a station\n"
67 " disassociate <addr> disassociate a station\n"
68 #ifdef CONFIG_IEEE80211W
69 " sa_query <addr> send SA Query to a station\n"
70 #endif /* CONFIG_IEEE80211W */
72 " wps_pin <uuid> <pin> [timeout] [addr] add WPS Enrollee PIN\n"
73 " wps_check_pin <PIN> verify PIN checksum\n"
74 " wps_pbc indicate button pushed to initiate PBC\n"
75 " wps_cancel cancel the pending WPS operation\n"
77 " wps_nfc_tag_read <hexdump> report read NFC tag with WPS data\n"
78 " wps_nfc_config_token <WPS/NDEF> build NFC configuration token\n"
79 " wps_nfc_token <WPS/NDEF/enable/disable> manager NFC password token\n"
80 #endif /* CONFIG_WPS_NFC */
81 " wps_ap_pin <cmd> [params..] enable/disable AP PIN\n"
82 " wps_config <SSID> <auth> <encr> <key> configure AP\n"
83 " wps_get_status show current WPS status\n"
84 #endif /* CONFIG_WPS */
85 " get_config show current configuration\n"
86 " help show this usage help\n"
87 " interface [ifname] show interfaces/select interface\n"
88 " level <debug level> change debug level\n"
89 " license show full hostapd_cli license\n"
90 " quit exit hostapd_cli\n";
92 static struct wpa_ctrl *ctrl_conn;
93 static int hostapd_cli_quit = 0;
94 static int hostapd_cli_attached = 0;
96 #ifndef CONFIG_CTRL_IFACE_DIR
97 #define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd"
98 #endif /* CONFIG_CTRL_IFACE_DIR */
99 static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
100 static const char *client_socket_dir = NULL;
102 static char *ctrl_ifname = NULL;
103 static const char *pid_file = NULL;
104 static const char *action_file = NULL;
105 static int ping_interval = 5;
106 static int interactive = 0;
109 static void usage(void)
111 fprintf(stderr, "%s\n", hostapd_cli_version);
114 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
116 " [-P<pid file>] [-G<ping interval>] [command..]\n"
119 " -h help (show this usage text)\n"
120 " -v shown version information\n"
121 " -p<path> path to find control sockets (default: "
122 "/var/run/hostapd)\n"
123 " -s<dir_path> dir path to open client sockets (default: "
124 CONFIG_CTRL_IFACE_DIR ")\n"
125 " -a<file> run in daemon mode executing the action file "
128 " -B run a daemon in the background\n"
129 " -i<ifname> Interface to listen on (default: first "
130 "interface found in the\n"
137 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
145 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
146 cfile = malloc(flen);
149 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
151 if (client_socket_dir && client_socket_dir[0] &&
152 access(client_socket_dir, F_OK) < 0) {
153 perror(client_socket_dir);
158 ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir);
164 static void hostapd_cli_close_connection(void)
166 if (ctrl_conn == NULL)
169 if (hostapd_cli_attached) {
170 wpa_ctrl_detach(ctrl_conn);
171 hostapd_cli_attached = 0;
173 wpa_ctrl_close(ctrl_conn);
178 static void hostapd_cli_msg_cb(char *msg, size_t len)
184 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
190 if (ctrl_conn == NULL) {
191 printf("Not connected to hostapd - command dropped.\n");
194 len = sizeof(buf) - 1;
195 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
198 printf("'%s' command timed out.\n", cmd);
200 } else if (ret < 0) {
201 printf("'%s' command failed.\n", cmd);
212 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
214 return _wpa_ctrl_command(ctrl, cmd, 1);
218 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
220 return wpa_ctrl_command(ctrl, "PING");
224 static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
226 return wpa_ctrl_command(ctrl, "RELOG");
230 static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
232 if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
233 return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
234 return wpa_ctrl_command(ctrl, "STATUS");
238 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
242 os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]);
243 return wpa_ctrl_command(ctrl, buf);
245 return wpa_ctrl_command(ctrl, "MIB");
249 static int hostapd_cli_exec(const char *program, const char *arg1,
256 len = os_strlen(arg1) + os_strlen(arg2) + 2;
257 arg = os_malloc(len);
260 os_snprintf(arg, len, "%s %s", arg1, arg2);
261 res = os_exec(program, arg, 1);
268 static void hostapd_cli_action_process(char *msg, size_t len)
274 pos = os_strchr(pos, '>');
281 hostapd_cli_exec(action_file, ctrl_ifname, pos);
285 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
289 printf("Invalid 'sta' command - at least one argument, STA "
290 "address, is required.\n");
294 snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]);
296 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
297 return wpa_ctrl_command(ctrl, buf);
301 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
306 printf("Invalid 'new_sta' command - exactly one argument, STA "
307 "address, is required.\n");
310 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
311 return wpa_ctrl_command(ctrl, buf);
315 static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
320 printf("Invalid 'deauthenticate' command - exactly one "
321 "argument, STA address, is required.\n");
325 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
328 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
329 return wpa_ctrl_command(ctrl, buf);
333 static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
338 printf("Invalid 'disassociate' command - exactly one "
339 "argument, STA address, is required.\n");
343 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
346 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
347 return wpa_ctrl_command(ctrl, buf);
351 #ifdef CONFIG_IEEE80211W
352 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
357 printf("Invalid 'sa_query' command - exactly one argument, "
358 "STA address, is required.\n");
361 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
362 return wpa_ctrl_command(ctrl, buf);
364 #endif /* CONFIG_IEEE80211W */
368 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
373 printf("Invalid 'wps_pin' command - at least two arguments, "
374 "UUID and PIN, are required.\n");
378 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
379 argv[0], argv[1], argv[2], argv[3]);
381 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
382 argv[0], argv[1], argv[2]);
384 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
385 return wpa_ctrl_command(ctrl, buf);
389 static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
395 if (argc != 1 && argc != 2) {
396 printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
397 "- PIN to be verified\n");
402 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
405 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
407 if (os_snprintf_error(sizeof(cmd), res)) {
408 printf("Too long WPS_CHECK_PIN command.\n");
411 return wpa_ctrl_command(ctrl, cmd);
415 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
418 return wpa_ctrl_command(ctrl, "WPS_PBC");
422 static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
425 return wpa_ctrl_command(ctrl, "WPS_CANCEL");
429 #ifdef CONFIG_WPS_NFC
430 static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
438 printf("Invalid 'wps_nfc_tag_read' command - one argument "
443 buflen = 18 + os_strlen(argv[0]);
444 buf = os_malloc(buflen);
447 os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
449 ret = wpa_ctrl_command(ctrl, buf);
456 static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
457 int argc, char *argv[])
463 printf("Invalid 'wps_nfc_config_token' command - one argument "
468 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
470 if (os_snprintf_error(sizeof(cmd), res)) {
471 printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
474 return wpa_ctrl_command(ctrl, cmd);
478 static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
479 int argc, char *argv[])
485 printf("Invalid 'wps_nfc_token' command - one argument is "
490 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
491 if (os_snprintf_error(sizeof(cmd), res)) {
492 printf("Too long WPS_NFC_TOKEN command.\n");
495 return wpa_ctrl_command(ctrl, cmd);
499 static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
500 int argc, char *argv[])
506 printf("Invalid 'nfc_get_handover_sel' command - two arguments "
511 res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
513 if (os_snprintf_error(sizeof(cmd), res)) {
514 printf("Too long NFC_GET_HANDOVER_SEL command.\n");
517 return wpa_ctrl_command(ctrl, cmd);
520 #endif /* CONFIG_WPS_NFC */
523 static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
528 printf("Invalid 'wps_ap_pin' command - at least one argument "
533 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
534 argv[0], argv[1], argv[2]);
536 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
539 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
540 return wpa_ctrl_command(ctrl, buf);
544 static int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc,
547 return wpa_ctrl_command(ctrl, "WPS_GET_STATUS");
551 static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
555 char ssid_hex[2 * SSID_MAX_LEN + 1];
556 char key_hex[2 * 64 + 1];
560 printf("Invalid 'wps_config' command - at least two arguments "
566 for (i = 0; i < SSID_MAX_LEN; i++) {
567 if (argv[0][i] == '\0')
569 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
574 for (i = 0; i < 64; i++) {
575 if (argv[3][i] == '\0')
577 os_snprintf(&key_hex[i * 2], 3, "%02x",
583 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
584 ssid_hex, argv[1], argv[2], key_hex);
586 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
587 ssid_hex, argv[1], argv[2]);
589 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
591 return wpa_ctrl_command(ctrl, buf);
593 #endif /* CONFIG_WPS */
596 static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
603 printf("Invalid 'disassoc_imminent' command - two arguments "
604 "(STA addr and Disassociation Timer) are needed\n");
608 res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
610 if (os_snprintf_error(sizeof(buf), res))
612 return wpa_ctrl_command(ctrl, buf);
616 static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
623 printf("Invalid 'ess_disassoc' command - three arguments (STA "
624 "addr, disassoc timer, and URL) are needed\n");
628 res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
629 argv[0], argv[1], argv[2]);
630 if (os_snprintf_error(sizeof(buf), res))
632 return wpa_ctrl_command(ctrl, buf);
636 static int hostapd_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc,
639 char buf[2000], *tmp;
643 printf("Invalid 'bss_tm_req' command - at least one argument (STA addr) is needed\n");
647 res = os_snprintf(buf, sizeof(buf), "BSS_TM_REQ %s", argv[0]);
648 if (os_snprintf_error(sizeof(buf), res))
652 for (i = 1; i < argc; i++) {
654 res = os_snprintf(tmp, sizeof(buf) - total, " %s", argv[i]);
655 if (os_snprintf_error(sizeof(buf) - total, res))
659 return wpa_ctrl_command(ctrl, buf);
663 static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
666 return wpa_ctrl_command(ctrl, "GET_CONFIG");
670 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
671 char *addr, size_t addr_len)
673 char buf[4096], *pos;
677 if (ctrl_conn == NULL) {
678 printf("Not connected to hostapd - command dropped.\n");
681 len = sizeof(buf) - 1;
682 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
685 printf("'%s' command timed out.\n", cmd);
687 } else if (ret < 0) {
688 printf("'%s' command failed.\n", cmd);
693 if (memcmp(buf, "FAIL", 4) == 0)
698 while (*pos != '\0' && *pos != '\n')
701 os_strlcpy(addr, buf, addr_len);
706 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
709 char addr[32], cmd[64];
711 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
714 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
715 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
721 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
723 printf("%s", commands_help);
728 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
731 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
736 static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl,
737 int argc, char *argv[])
743 printf("Invalid 'set_qos_map_set' command - "
744 "one argument (comma delimited QoS map set) "
749 res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
750 if (os_snprintf_error(sizeof(buf), res))
752 return wpa_ctrl_command(ctrl, buf);
756 static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
757 int argc, char *argv[])
763 printf("Invalid 'send_qos_map_conf' command - "
764 "one argument (STA addr) is needed\n");
768 res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
769 if (os_snprintf_error(sizeof(buf), res))
771 return wpa_ctrl_command(ctrl, buf);
775 static int hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc,
782 printf("Invalid 'hs20_wnm_notif' command - two arguments (STA "
783 "addr and URL) are needed\n");
787 res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s",
789 if (os_snprintf_error(sizeof(buf), res))
791 return wpa_ctrl_command(ctrl, buf);
795 static int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc,
802 printf("Invalid 'hs20_deauth_req' command - at least three arguments (STA addr, Code, Re-auth Delay) are needed\n");
807 res = os_snprintf(buf, sizeof(buf),
808 "HS20_DEAUTH_REQ %s %s %s %s",
809 argv[0], argv[1], argv[2], argv[3]);
811 res = os_snprintf(buf, sizeof(buf),
812 "HS20_DEAUTH_REQ %s %s %s",
813 argv[0], argv[1], argv[2]);
814 if (os_snprintf_error(sizeof(buf), res))
816 return wpa_ctrl_command(ctrl, buf);
820 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
822 hostapd_cli_quit = 1;
829 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
833 printf("Invalid LEVEL command: needs one argument (debug "
837 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
838 return wpa_ctrl_command(ctrl, cmd);
842 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
847 dir = opendir(ctrl_iface_dir);
849 printf("Control interface directory '%s' could not be "
850 "openned.\n", ctrl_iface_dir);
854 printf("Available interfaces:\n");
855 while ((dent = readdir(dir))) {
856 if (strcmp(dent->d_name, ".") == 0 ||
857 strcmp(dent->d_name, "..") == 0)
859 printf("%s\n", dent->d_name);
865 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
869 hostapd_cli_list_interfaces(ctrl);
873 hostapd_cli_close_connection();
874 os_free(ctrl_ifname);
875 ctrl_ifname = os_strdup(argv[0]);
876 if (ctrl_ifname == NULL)
879 if (hostapd_cli_open_connection(ctrl_ifname)) {
880 printf("Connected to interface '%s.\n", ctrl_ifname);
881 if (wpa_ctrl_attach(ctrl_conn) == 0) {
882 hostapd_cli_attached = 1;
884 printf("Warning: Failed to attach to "
888 printf("Could not connect to interface '%s' - re-trying\n",
895 static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
901 printf("Invalid SET command: needs two arguments (variable "
902 "name and value)\n");
906 res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
907 if (os_snprintf_error(sizeof(cmd), res)) {
908 printf("Too long SET command.\n");
911 return wpa_ctrl_command(ctrl, cmd);
915 static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
921 printf("Invalid GET command: needs one argument (variable "
926 res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
927 if (os_snprintf_error(sizeof(cmd), res)) {
928 printf("Too long GET command.\n");
931 return wpa_ctrl_command(ctrl, cmd);
936 static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[])
944 printf("FST command: parameters are required.\n");
948 total = os_snprintf(cmd, sizeof(cmd), "FST-MANAGER");
950 for (i = 0; i < argc; i++) {
951 res = os_snprintf(cmd + total, sizeof(cmd) - total, " %s",
953 if (os_snprintf_error(sizeof(cmd) - total, res)) {
954 printf("Too long fst command.\n");
959 return wpa_ctrl_command(ctrl, cmd);
961 #endif /* CONFIG_FST */
964 static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
965 int argc, char *argv[])
974 printf("Invalid chan_switch command: needs at least two "
975 "arguments (count and freq)\n"
976 "usage: <cs_count> <freq> [sec_channel_offset=] "
977 "[center_freq1=] [center_freq2=] [bandwidth=] "
978 "[blocktx] [ht|vht]\n");
982 res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
984 if (os_snprintf_error(sizeof(cmd), res)) {
985 printf("Too long CHAN_SWITCH command.\n");
990 for (i = 2; i < argc; i++) {
992 res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
993 if (os_snprintf_error(sizeof(cmd) - total, res)) {
994 printf("Too long CHAN_SWITCH command.\n");
999 return wpa_ctrl_command(ctrl, cmd);
1003 static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc,
1006 return wpa_ctrl_command(ctrl, "ENABLE");
1010 static int hostapd_cli_cmd_reload(struct wpa_ctrl *ctrl, int argc,
1013 return wpa_ctrl_command(ctrl, "RELOAD");
1017 static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc,
1020 return wpa_ctrl_command(ctrl, "DISABLE");
1024 static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
1029 if (argc < 2 || argc > 3) {
1030 printf("Invalid vendor command\n"
1031 "usage: <vendor id> <command id> [<hex formatted command argument>]\n");
1035 res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
1036 argc == 3 ? argv[2] : "");
1037 if (os_snprintf_error(sizeof(cmd), res)) {
1038 printf("Too long VENDOR command.\n");
1041 return wpa_ctrl_command(ctrl, cmd);
1045 static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc,
1048 return wpa_ctrl_command(ctrl, "ERP_FLUSH");
1052 static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc,
1058 res = os_snprintf(cmd, sizeof(cmd), "LOG_LEVEL%s%s%s%s",
1059 argc >= 1 ? " " : "",
1060 argc >= 1 ? argv[0] : "",
1061 argc == 2 ? " " : "",
1062 argc == 2 ? argv[1] : "");
1063 if (os_snprintf_error(sizeof(cmd), res)) {
1064 printf("Too long option\n");
1067 return wpa_ctrl_command(ctrl, cmd);
1071 struct hostapd_cli_cmd {
1073 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
1076 static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
1077 { "ping", hostapd_cli_cmd_ping },
1078 { "mib", hostapd_cli_cmd_mib },
1079 { "relog", hostapd_cli_cmd_relog },
1080 { "status", hostapd_cli_cmd_status },
1081 { "sta", hostapd_cli_cmd_sta },
1082 { "all_sta", hostapd_cli_cmd_all_sta },
1083 { "new_sta", hostapd_cli_cmd_new_sta },
1084 { "deauthenticate", hostapd_cli_cmd_deauthenticate },
1085 { "disassociate", hostapd_cli_cmd_disassociate },
1086 #ifdef CONFIG_IEEE80211W
1087 { "sa_query", hostapd_cli_cmd_sa_query },
1088 #endif /* CONFIG_IEEE80211W */
1090 { "wps_pin", hostapd_cli_cmd_wps_pin },
1091 { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
1092 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
1093 { "wps_cancel", hostapd_cli_cmd_wps_cancel },
1094 #ifdef CONFIG_WPS_NFC
1095 { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
1096 { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
1097 { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
1098 { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
1099 #endif /* CONFIG_WPS_NFC */
1100 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
1101 { "wps_config", hostapd_cli_cmd_wps_config },
1102 { "wps_get_status", hostapd_cli_cmd_wps_get_status },
1103 #endif /* CONFIG_WPS */
1104 { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
1105 { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
1106 { "bss_tm_req", hostapd_cli_cmd_bss_tm_req },
1107 { "get_config", hostapd_cli_cmd_get_config },
1108 { "help", hostapd_cli_cmd_help },
1109 { "interface", hostapd_cli_cmd_interface },
1111 { "fst", hostapd_cli_cmd_fst },
1112 #endif /* CONFIG_FST */
1113 { "level", hostapd_cli_cmd_level },
1114 { "license", hostapd_cli_cmd_license },
1115 { "quit", hostapd_cli_cmd_quit },
1116 { "set", hostapd_cli_cmd_set },
1117 { "get", hostapd_cli_cmd_get },
1118 { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
1119 { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
1120 { "chan_switch", hostapd_cli_cmd_chan_switch },
1121 { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif },
1122 { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req },
1123 { "vendor", hostapd_cli_cmd_vendor },
1124 { "enable", hostapd_cli_cmd_enable },
1125 { "reload", hostapd_cli_cmd_reload },
1126 { "disable", hostapd_cli_cmd_disable },
1127 { "erp_flush", hostapd_cli_cmd_erp_flush },
1128 { "log_level", hostapd_cli_cmd_log_level },
1133 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
1135 const struct hostapd_cli_cmd *cmd, *match = NULL;
1139 cmd = hostapd_cli_commands;
1141 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
1143 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1144 /* we have an exact match */
1154 printf("Ambiguous command '%s'; possible commands:", argv[0]);
1155 cmd = hostapd_cli_commands;
1157 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
1159 printf(" %s", cmd->cmd);
1164 } else if (count == 0) {
1165 printf("Unknown command '%s'\n", argv[0]);
1167 match->handler(ctrl, argc - 1, &argv[1]);
1172 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
1176 if (ctrl_conn == NULL)
1178 while (wpa_ctrl_pending(ctrl)) {
1180 size_t len = sizeof(buf) - 1;
1181 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
1184 hostapd_cli_action_process(buf, len);
1186 if (in_read && first)
1189 printf("%s\n", buf);
1192 printf("Could not read pending message.\n");
1201 static int tokenize_cmd(char *cmd, char *argv[])
1214 if (argc == max_args)
1217 char *pos2 = os_strrchr(pos, '"');
1221 while (*pos != '\0' && *pos != ' ')
1231 static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
1233 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
1234 printf("Connection to hostapd lost - trying to reconnect\n");
1235 hostapd_cli_close_connection();
1238 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1240 printf("Connection to hostapd re-established\n");
1241 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1242 hostapd_cli_attached = 1;
1244 printf("Warning: Failed to attach to "
1250 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
1251 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1255 static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
1261 static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
1263 char *argv[max_args];
1265 argc = tokenize_cmd(cmd, argv);
1267 wpa_request(ctrl_conn, argc, argv);
1271 static void hostapd_cli_edit_eof_cb(void *ctx)
1277 static void hostapd_cli_interactive(void)
1279 printf("\nInteractive mode\n\n");
1281 eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
1282 edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
1283 NULL, NULL, NULL, NULL);
1284 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1288 edit_deinit(NULL, NULL);
1289 eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
1293 static void hostapd_cli_cleanup(void)
1295 hostapd_cli_close_connection();
1297 os_daemonize_terminate(pid_file);
1299 os_program_deinit();
1303 static void hostapd_cli_action(struct wpa_ctrl *ctrl)
1311 fd = wpa_ctrl_get_fd(ctrl);
1313 while (!hostapd_cli_quit) {
1316 tv.tv_sec = ping_interval;
1318 res = select(fd + 1, &rfds, NULL, NULL, &tv);
1319 if (res < 0 && errno != EINTR) {
1324 if (FD_ISSET(fd, &rfds))
1325 hostapd_cli_recv_pending(ctrl, 0, 1);
1327 len = sizeof(buf) - 1;
1328 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1329 hostapd_cli_action_process) < 0 ||
1330 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
1331 printf("hostapd did not reply to PING "
1332 "command - exiting\n");
1340 int main(int argc, char *argv[])
1342 int warning_displayed = 0;
1346 if (os_program_init())
1350 c = getopt(argc, argv, "a:BhG:i:p:P:s:v");
1355 action_file = optarg;
1361 ping_interval = atoi(optarg);
1367 printf("%s\n", hostapd_cli_version);
1370 os_free(ctrl_ifname);
1371 ctrl_ifname = os_strdup(optarg);
1374 ctrl_iface_dir = optarg;
1380 client_socket_dir = optarg;
1388 interactive = (argc == optind) && (action_file == NULL);
1391 printf("%s\n\n%s\n\n", hostapd_cli_version,
1392 hostapd_cli_license);
1399 if (ctrl_ifname == NULL) {
1400 struct dirent *dent;
1401 DIR *dir = opendir(ctrl_iface_dir);
1403 while ((dent = readdir(dir))) {
1404 if (os_strcmp(dent->d_name, ".") == 0
1406 os_strcmp(dent->d_name, "..") == 0)
1408 printf("Selected interface '%s'\n",
1410 ctrl_ifname = os_strdup(dent->d_name);
1416 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1418 if (warning_displayed)
1419 printf("Connection established.\n");
1424 perror("Failed to connect to hostapd - "
1429 if (!warning_displayed) {
1430 printf("Could not connect to hostapd - re-trying\n");
1431 warning_displayed = 1;
1437 if (interactive || action_file) {
1438 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1439 hostapd_cli_attached = 1;
1441 printf("Warning: Failed to attach to hostapd.\n");
1447 if (daemonize && os_daemonize(pid_file))
1451 hostapd_cli_interactive();
1452 else if (action_file)
1453 hostapd_cli_action(ctrl_conn);
1455 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1457 os_free(ctrl_ifname);
1459 hostapd_cli_cleanup();