2 * hostapd - command line interface for hostapd daemon
3 * Copyright (c) 2004-2016, 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"
18 #include "common/cli.h"
20 #ifndef CONFIG_NO_CTRL_IFACE
22 static const char *const hostapd_cli_version =
23 "hostapd_cli v" VERSION_STR "\n"
24 "Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors";
27 static const char *const hostapd_cli_license =
28 "This software may be distributed under the terms of the BSD license.\n"
29 "See README for more details.\n";
31 static const char *const hostapd_cli_full_license =
32 "This software may be distributed under the terms of the BSD license.\n"
34 "Redistribution and use in source and binary forms, with or without\n"
35 "modification, are permitted provided that the following conditions are\n"
38 "1. Redistributions of source code must retain the above copyright\n"
39 " notice, this list of conditions and the following disclaimer.\n"
41 "2. Redistributions in binary form must reproduce the above copyright\n"
42 " notice, this list of conditions and the following disclaimer in the\n"
43 " documentation and/or other materials provided with the distribution.\n"
45 "3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
46 " names of its contributors may be used to endorse or promote products\n"
47 " derived from this software without specific prior written permission.\n"
49 "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
50 "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
51 "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
52 "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
53 "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
54 "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
55 "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
56 "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
57 "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
58 "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
59 "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
62 static struct wpa_ctrl *ctrl_conn;
63 static int hostapd_cli_quit = 0;
64 static int hostapd_cli_attached = 0;
66 #ifndef CONFIG_CTRL_IFACE_DIR
67 #define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd"
68 #endif /* CONFIG_CTRL_IFACE_DIR */
69 static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
70 static const char *client_socket_dir = NULL;
72 static char *ctrl_ifname = NULL;
73 static const char *pid_file = NULL;
74 static const char *action_file = NULL;
75 static int ping_interval = 5;
76 static int interactive = 0;
78 static void print_help(FILE *stream, const char *cmd);
79 static char ** list_cmd_list(void);
82 static void usage(void)
84 fprintf(stderr, "%s\n", hostapd_cli_version);
87 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
89 " [-P<pid file>] [-G<ping interval>] [command..]\n"
92 " -h help (show this usage text)\n"
93 " -v shown version information\n"
94 " -p<path> path to find control sockets (default: "
96 " -s<dir_path> dir path to open client sockets (default: "
97 CONFIG_CTRL_IFACE_DIR ")\n"
98 " -a<file> run in daemon mode executing the action file "
101 " -B run a daemon in the background\n"
102 " -i<ifname> Interface to listen on (default: first "
103 "interface found in the\n"
104 " socket path)\n\n");
105 print_help(stderr, NULL);
109 static int get_cmd_arg_num(const char *str, int pos)
113 for (i = 0; i <= pos; i++) {
116 while (i <= pos && str[i] != ' ')
127 static int str_starts(const char *src, const char *match)
129 return os_strncmp(src, match, os_strlen(match)) == 0;
133 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
135 #ifndef CONFIG_CTRL_IFACE_UDP
138 #endif /* !CONFIG_CTRL_IFACE_UDP */
143 #ifdef CONFIG_CTRL_IFACE_UDP
144 ctrl_conn = wpa_ctrl_open(ifname);
146 #else /* CONFIG_CTRL_IFACE_UDP */
147 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
148 cfile = malloc(flen);
151 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
153 if (client_socket_dir && client_socket_dir[0] &&
154 access(client_socket_dir, F_OK) < 0) {
155 perror(client_socket_dir);
160 ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir);
163 #endif /* CONFIG_CTRL_IFACE_UDP */
167 static void hostapd_cli_close_connection(void)
169 if (ctrl_conn == NULL)
172 if (hostapd_cli_attached) {
173 wpa_ctrl_detach(ctrl_conn);
174 hostapd_cli_attached = 0;
176 wpa_ctrl_close(ctrl_conn);
181 static void hostapd_cli_msg_cb(char *msg, size_t len)
187 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
193 if (ctrl_conn == NULL) {
194 printf("Not connected to hostapd - command dropped.\n");
197 len = sizeof(buf) - 1;
198 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
201 printf("'%s' command timed out.\n", cmd);
203 } else if (ret < 0) {
204 printf("'%s' command failed.\n", cmd);
215 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
217 return _wpa_ctrl_command(ctrl, cmd, 1);
221 static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
230 res = os_snprintf(pos, end - pos, "%s", cmd);
231 if (os_snprintf_error(end - pos, res))
235 for (i = 0; i < argc; i++) {
236 res = os_snprintf(pos, end - pos, " %s", argv[i]);
237 if (os_snprintf_error(end - pos, res))
242 buf[buflen - 1] = '\0';
246 printf("Too long command\n");
251 static int hostapd_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd,
252 int min_args, int argc, char *argv[])
256 if (argc < min_args) {
257 printf("Invalid %s command - at least %d argument%s required.\n",
258 cmd, min_args, min_args > 1 ? "s are" : " is");
261 if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0)
263 return wpa_ctrl_command(ctrl, buf);
267 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
269 return wpa_ctrl_command(ctrl, "PING");
273 static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
275 return wpa_ctrl_command(ctrl, "RELOG");
279 static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
281 if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
282 return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
283 return wpa_ctrl_command(ctrl, "STATUS");
287 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
291 os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]);
292 return wpa_ctrl_command(ctrl, buf);
294 return wpa_ctrl_command(ctrl, "MIB");
298 static int hostapd_cli_exec(const char *program, const char *arg1,
305 len = os_strlen(arg1) + os_strlen(arg2) + 2;
306 arg = os_malloc(len);
309 os_snprintf(arg, len, "%s %s", arg1, arg2);
310 res = os_exec(program, arg, 1);
317 static void hostapd_cli_action_process(char *msg, size_t len)
323 pos = os_strchr(pos, '>');
330 hostapd_cli_exec(action_file, ctrl_ifname, pos);
334 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
338 printf("Invalid 'sta' command - at least one argument, STA "
339 "address, is required.\n");
343 snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]);
345 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
346 return wpa_ctrl_command(ctrl, buf);
350 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
355 printf("Invalid 'new_sta' command - exactly one argument, STA "
356 "address, is required.\n");
359 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
360 return wpa_ctrl_command(ctrl, buf);
364 static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
369 printf("Invalid 'deauthenticate' command - exactly one "
370 "argument, STA address, is required.\n");
374 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
377 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
378 return wpa_ctrl_command(ctrl, buf);
382 static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
387 printf("Invalid 'disassociate' command - exactly one "
388 "argument, STA address, is required.\n");
392 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
395 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
396 return wpa_ctrl_command(ctrl, buf);
400 #ifdef CONFIG_IEEE80211W
401 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
406 printf("Invalid 'sa_query' command - exactly one argument, "
407 "STA address, is required.\n");
410 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
411 return wpa_ctrl_command(ctrl, buf);
413 #endif /* CONFIG_IEEE80211W */
417 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
422 printf("Invalid 'wps_pin' command - at least two arguments, "
423 "UUID and PIN, are required.\n");
427 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
428 argv[0], argv[1], argv[2], argv[3]);
430 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
431 argv[0], argv[1], argv[2]);
433 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
434 return wpa_ctrl_command(ctrl, buf);
438 static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
444 if (argc != 1 && argc != 2) {
445 printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
446 "- PIN to be verified\n");
451 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
454 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
456 if (os_snprintf_error(sizeof(cmd), res)) {
457 printf("Too long WPS_CHECK_PIN command.\n");
460 return wpa_ctrl_command(ctrl, cmd);
464 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
467 return wpa_ctrl_command(ctrl, "WPS_PBC");
471 static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
474 return wpa_ctrl_command(ctrl, "WPS_CANCEL");
478 #ifdef CONFIG_WPS_NFC
479 static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
487 printf("Invalid 'wps_nfc_tag_read' command - one argument "
492 buflen = 18 + os_strlen(argv[0]);
493 buf = os_malloc(buflen);
496 os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
498 ret = wpa_ctrl_command(ctrl, buf);
505 static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
506 int argc, char *argv[])
512 printf("Invalid 'wps_nfc_config_token' command - one argument "
517 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
519 if (os_snprintf_error(sizeof(cmd), res)) {
520 printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
523 return wpa_ctrl_command(ctrl, cmd);
527 static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
528 int argc, char *argv[])
534 printf("Invalid 'wps_nfc_token' command - one argument is "
539 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
540 if (os_snprintf_error(sizeof(cmd), res)) {
541 printf("Too long WPS_NFC_TOKEN command.\n");
544 return wpa_ctrl_command(ctrl, cmd);
548 static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
549 int argc, char *argv[])
555 printf("Invalid 'nfc_get_handover_sel' command - two arguments "
560 res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
562 if (os_snprintf_error(sizeof(cmd), res)) {
563 printf("Too long NFC_GET_HANDOVER_SEL command.\n");
566 return wpa_ctrl_command(ctrl, cmd);
569 #endif /* CONFIG_WPS_NFC */
572 static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
577 printf("Invalid 'wps_ap_pin' command - at least one argument "
582 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
583 argv[0], argv[1], argv[2]);
585 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
588 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
589 return wpa_ctrl_command(ctrl, buf);
593 static int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc,
596 return wpa_ctrl_command(ctrl, "WPS_GET_STATUS");
600 static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
604 char ssid_hex[2 * SSID_MAX_LEN + 1];
605 char key_hex[2 * 64 + 1];
609 printf("Invalid 'wps_config' command - at least two arguments "
615 for (i = 0; i < SSID_MAX_LEN; i++) {
616 if (argv[0][i] == '\0')
618 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
623 for (i = 0; i < 64; i++) {
624 if (argv[3][i] == '\0')
626 os_snprintf(&key_hex[i * 2], 3, "%02x",
632 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
633 ssid_hex, argv[1], argv[2], key_hex);
635 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
636 ssid_hex, argv[1], argv[2]);
638 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
640 return wpa_ctrl_command(ctrl, buf);
642 #endif /* CONFIG_WPS */
645 static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
652 printf("Invalid 'disassoc_imminent' command - two arguments "
653 "(STA addr and Disassociation Timer) are needed\n");
657 res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
659 if (os_snprintf_error(sizeof(buf), res))
661 return wpa_ctrl_command(ctrl, buf);
665 static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
672 printf("Invalid 'ess_disassoc' command - three arguments (STA "
673 "addr, disassoc timer, and URL) are needed\n");
677 res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
678 argv[0], argv[1], argv[2]);
679 if (os_snprintf_error(sizeof(buf), res))
681 return wpa_ctrl_command(ctrl, buf);
685 static int hostapd_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc,
688 char buf[2000], *tmp;
692 printf("Invalid 'bss_tm_req' command - at least one argument (STA addr) is needed\n");
696 res = os_snprintf(buf, sizeof(buf), "BSS_TM_REQ %s", argv[0]);
697 if (os_snprintf_error(sizeof(buf), res))
701 for (i = 1; i < argc; i++) {
703 res = os_snprintf(tmp, sizeof(buf) - total, " %s", argv[i]);
704 if (os_snprintf_error(sizeof(buf) - total, res))
708 return wpa_ctrl_command(ctrl, buf);
712 static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
715 return wpa_ctrl_command(ctrl, "GET_CONFIG");
719 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
720 char *addr, size_t addr_len)
722 char buf[4096], *pos;
726 if (ctrl_conn == NULL) {
727 printf("Not connected to hostapd - command dropped.\n");
730 len = sizeof(buf) - 1;
731 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
734 printf("'%s' command timed out.\n", cmd);
736 } else if (ret < 0) {
737 printf("'%s' command failed.\n", cmd);
742 if (memcmp(buf, "FAIL", 4) == 0)
747 while (*pos != '\0' && *pos != '\n')
750 os_strlcpy(addr, buf, addr_len);
755 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
758 char addr[32], cmd[64];
760 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
763 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
764 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
770 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
772 print_help(stdout, argc > 0 ? argv[0] : NULL);
777 static char ** hostapd_cli_complete_help(const char *str, int pos)
779 int arg = get_cmd_arg_num(str, pos);
784 res = list_cmd_list();
792 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
795 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
800 static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl,
801 int argc, char *argv[])
807 printf("Invalid 'set_qos_map_set' command - "
808 "one argument (comma delimited QoS map set) "
813 res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
814 if (os_snprintf_error(sizeof(buf), res))
816 return wpa_ctrl_command(ctrl, buf);
820 static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
821 int argc, char *argv[])
827 printf("Invalid 'send_qos_map_conf' command - "
828 "one argument (STA addr) is needed\n");
832 res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
833 if (os_snprintf_error(sizeof(buf), res))
835 return wpa_ctrl_command(ctrl, buf);
839 static int hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc,
846 printf("Invalid 'hs20_wnm_notif' command - two arguments (STA "
847 "addr and URL) are needed\n");
851 res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s",
853 if (os_snprintf_error(sizeof(buf), res))
855 return wpa_ctrl_command(ctrl, buf);
859 static int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc,
866 printf("Invalid 'hs20_deauth_req' command - at least three arguments (STA addr, Code, Re-auth Delay) are needed\n");
871 res = os_snprintf(buf, sizeof(buf),
872 "HS20_DEAUTH_REQ %s %s %s %s",
873 argv[0], argv[1], argv[2], argv[3]);
875 res = os_snprintf(buf, sizeof(buf),
876 "HS20_DEAUTH_REQ %s %s %s",
877 argv[0], argv[1], argv[2]);
878 if (os_snprintf_error(sizeof(buf), res))
880 return wpa_ctrl_command(ctrl, buf);
884 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
886 hostapd_cli_quit = 1;
893 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
897 printf("Invalid LEVEL command: needs one argument (debug "
901 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
902 return wpa_ctrl_command(ctrl, cmd);
906 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
911 dir = opendir(ctrl_iface_dir);
913 printf("Control interface directory '%s' could not be "
914 "openned.\n", ctrl_iface_dir);
918 printf("Available interfaces:\n");
919 while ((dent = readdir(dir))) {
920 if (strcmp(dent->d_name, ".") == 0 ||
921 strcmp(dent->d_name, "..") == 0)
923 printf("%s\n", dent->d_name);
929 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
933 hostapd_cli_list_interfaces(ctrl);
937 hostapd_cli_close_connection();
938 os_free(ctrl_ifname);
939 ctrl_ifname = os_strdup(argv[0]);
940 if (ctrl_ifname == NULL)
943 if (hostapd_cli_open_connection(ctrl_ifname)) {
944 printf("Connected to interface '%s.\n", ctrl_ifname);
945 if (wpa_ctrl_attach(ctrl_conn) == 0) {
946 hostapd_cli_attached = 1;
948 printf("Warning: Failed to attach to "
952 printf("Could not connect to interface '%s' - re-trying\n",
959 static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
965 printf("Invalid SET command: needs two arguments (variable "
966 "name and value)\n");
970 res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
971 if (os_snprintf_error(sizeof(cmd), res)) {
972 printf("Too long SET command.\n");
975 return wpa_ctrl_command(ctrl, cmd);
979 static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
985 printf("Invalid GET command: needs one argument (variable "
990 res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
991 if (os_snprintf_error(sizeof(cmd), res)) {
992 printf("Too long GET command.\n");
995 return wpa_ctrl_command(ctrl, cmd);
1000 static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[])
1008 printf("FST command: parameters are required.\n");
1012 total = os_snprintf(cmd, sizeof(cmd), "FST-MANAGER");
1014 for (i = 0; i < argc; i++) {
1015 res = os_snprintf(cmd + total, sizeof(cmd) - total, " %s",
1017 if (os_snprintf_error(sizeof(cmd) - total, res)) {
1018 printf("Too long fst command.\n");
1023 return wpa_ctrl_command(ctrl, cmd);
1025 #endif /* CONFIG_FST */
1028 static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
1029 int argc, char *argv[])
1038 printf("Invalid chan_switch command: needs at least two "
1039 "arguments (count and freq)\n"
1040 "usage: <cs_count> <freq> [sec_channel_offset=] "
1041 "[center_freq1=] [center_freq2=] [bandwidth=] "
1042 "[blocktx] [ht|vht]\n");
1046 res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
1048 if (os_snprintf_error(sizeof(cmd), res)) {
1049 printf("Too long CHAN_SWITCH command.\n");
1054 for (i = 2; i < argc; i++) {
1056 res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
1057 if (os_snprintf_error(sizeof(cmd) - total, res)) {
1058 printf("Too long CHAN_SWITCH command.\n");
1063 return wpa_ctrl_command(ctrl, cmd);
1067 static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc,
1070 return wpa_ctrl_command(ctrl, "ENABLE");
1074 static int hostapd_cli_cmd_reload(struct wpa_ctrl *ctrl, int argc,
1077 return wpa_ctrl_command(ctrl, "RELOAD");
1081 static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc,
1084 return wpa_ctrl_command(ctrl, "DISABLE");
1088 static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
1093 if (argc < 2 || argc > 3) {
1094 printf("Invalid vendor command\n"
1095 "usage: <vendor id> <command id> [<hex formatted command argument>]\n");
1099 res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
1100 argc == 3 ? argv[2] : "");
1101 if (os_snprintf_error(sizeof(cmd), res)) {
1102 printf("Too long VENDOR command.\n");
1105 return wpa_ctrl_command(ctrl, cmd);
1109 static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc,
1112 return wpa_ctrl_command(ctrl, "ERP_FLUSH");
1116 static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc,
1122 res = os_snprintf(cmd, sizeof(cmd), "LOG_LEVEL%s%s%s%s",
1123 argc >= 1 ? " " : "",
1124 argc >= 1 ? argv[0] : "",
1125 argc == 2 ? " " : "",
1126 argc == 2 ? argv[1] : "");
1127 if (os_snprintf_error(sizeof(cmd), res)) {
1128 printf("Too long option\n");
1131 return wpa_ctrl_command(ctrl, cmd);
1135 static int hostapd_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
1139 return hostapd_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]);
1143 static int hostapd_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
1145 return wpa_ctrl_command(ctrl, "PMKSA");
1149 static int hostapd_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc,
1152 return wpa_ctrl_command(ctrl, "PMKSA_FLUSH");
1156 static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc,
1162 if (argc < 3 || argc > 5) {
1163 printf("Invalid set_neighbor command: needs 3-5 arguments\n");
1167 res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s",
1168 argv[0], argv[1], argv[2], argc >= 4 ? argv[3] : "",
1169 argc == 5 ? argv[4] : "");
1170 if (os_snprintf_error(sizeof(cmd), res)) {
1171 printf("Too long SET_NEIGHBOR command.\n");
1174 return wpa_ctrl_command(ctrl, cmd);
1178 static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc,
1185 printf("Invalid remove_neighbor command: needs 2 arguments\n");
1189 res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NEIGHBOR %s %s",
1191 if (os_snprintf_error(sizeof(cmd), res)) {
1192 printf("Too long REMOVE_NEIGHBOR command.\n");
1195 return wpa_ctrl_command(ctrl, cmd);
1199 static int hostapd_cli_cmd_req_lci(struct wpa_ctrl *ctrl, int argc,
1206 printf("Invalid req_lci command - requires destination address\n");
1210 res = os_snprintf(cmd, sizeof(cmd), "REQ_LCI %s", argv[0]);
1211 if (os_snprintf_error(sizeof(cmd), res)) {
1212 printf("Too long REQ_LCI command.\n");
1215 return wpa_ctrl_command(ctrl, cmd);
1219 static int hostapd_cli_cmd_req_range(struct wpa_ctrl *ctrl, int argc,
1223 printf("Invalid req_range command: needs at least 4 arguments - dest address, randomization interval, min AP count, and 1 to 16 AP addresses\n");
1227 return hostapd_cli_cmd(ctrl, "REQ_RANGE", 4, argc, argv);
1231 static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
1234 return wpa_ctrl_command(ctrl, "DRIVER_FLAGS");
1238 struct hostapd_cli_cmd {
1240 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
1241 char ** (*completion)(const char *str, int pos);
1245 static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
1246 { "ping", hostapd_cli_cmd_ping, NULL,
1247 "= pings hostapd" },
1248 { "mib", hostapd_cli_cmd_mib, NULL,
1249 "= get MIB variables (dot1x, dot11, radius)" },
1250 { "relog", hostapd_cli_cmd_relog, NULL, NULL },
1251 { "status", hostapd_cli_cmd_status, NULL, NULL },
1252 { "sta", hostapd_cli_cmd_sta, NULL,
1253 "<addr> = get MIB variables for one station" },
1254 { "all_sta", hostapd_cli_cmd_all_sta, NULL,
1255 "= get MIB variables for all stations" },
1256 { "new_sta", hostapd_cli_cmd_new_sta, NULL,
1257 "<addr> = add a new station" },
1258 { "deauthenticate", hostapd_cli_cmd_deauthenticate, NULL,
1259 "<addr> = deauthenticate a station" },
1260 { "disassociate", hostapd_cli_cmd_disassociate, NULL,
1261 "<addr> = disassociate a station" },
1262 #ifdef CONFIG_IEEE80211W
1263 { "sa_query", hostapd_cli_cmd_sa_query, NULL,
1264 "<addr> = send SA Query to a station" },
1265 #endif /* CONFIG_IEEE80211W */
1267 { "wps_pin", hostapd_cli_cmd_wps_pin, NULL,
1268 "<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" },
1269 { "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL,
1270 "<PIN> = verify PIN checksum" },
1271 { "wps_pbc", hostapd_cli_cmd_wps_pbc, NULL,
1272 "= indicate button pushed to initiate PBC" },
1273 { "wps_cancel", hostapd_cli_cmd_wps_cancel, NULL,
1274 "= cancel the pending WPS operation" },
1275 #ifdef CONFIG_WPS_NFC
1276 { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read, NULL,
1277 "<hexdump> = report read NFC tag with WPS data" },
1278 { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token, NULL,
1279 "<WPS/NDEF> = build NFC configuration token" },
1280 { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token, NULL,
1281 "<WPS/NDEF/enable/disable> = manager NFC password token" },
1282 { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel, NULL,
1284 #endif /* CONFIG_WPS_NFC */
1285 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin, NULL,
1286 "<cmd> [params..] = enable/disable AP PIN" },
1287 { "wps_config", hostapd_cli_cmd_wps_config, NULL,
1288 "<SSID> <auth> <encr> <key> = configure AP" },
1289 { "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL,
1290 "= show current WPS status" },
1291 #endif /* CONFIG_WPS */
1292 { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL, NULL },
1293 { "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL, NULL },
1294 { "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL, NULL },
1295 { "get_config", hostapd_cli_cmd_get_config, NULL,
1296 "= show current configuration" },
1297 { "help", hostapd_cli_cmd_help, hostapd_cli_complete_help,
1298 "= show this usage help" },
1299 { "interface", hostapd_cli_cmd_interface, NULL,
1300 "[ifname] = show interfaces/select interface" },
1302 { "fst", hostapd_cli_cmd_fst, NULL, NULL },
1303 #endif /* CONFIG_FST */
1304 { "raw", hostapd_cli_cmd_raw, NULL, NULL },
1305 { "level", hostapd_cli_cmd_level, NULL,
1306 "<debug level> = change debug level" },
1307 { "license", hostapd_cli_cmd_license, NULL,
1308 "= show full hostapd_cli license" },
1309 { "quit", hostapd_cli_cmd_quit, NULL,
1310 "= exit hostapd_cli" },
1311 { "set", hostapd_cli_cmd_set, NULL, NULL },
1312 { "get", hostapd_cli_cmd_get, NULL, NULL },
1313 { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL, NULL },
1314 { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf, NULL, NULL },
1315 { "chan_switch", hostapd_cli_cmd_chan_switch, NULL, NULL },
1316 { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL, NULL },
1317 { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL, NULL },
1318 { "vendor", hostapd_cli_cmd_vendor, NULL, NULL },
1319 { "enable", hostapd_cli_cmd_enable, NULL, NULL },
1320 { "reload", hostapd_cli_cmd_reload, NULL, NULL },
1321 { "disable", hostapd_cli_cmd_disable, NULL, NULL },
1322 { "erp_flush", hostapd_cli_cmd_erp_flush, NULL, NULL },
1323 { "log_level", hostapd_cli_cmd_log_level, NULL, NULL },
1324 { "pmksa", hostapd_cli_cmd_pmksa, NULL, NULL },
1325 { "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL, NULL },
1326 { "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL, NULL },
1327 { "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL, NULL },
1328 { "req_lci", hostapd_cli_cmd_req_lci, NULL, NULL },
1329 { "req_range", hostapd_cli_cmd_req_range, NULL, NULL },
1330 { "driver_flags", hostapd_cli_cmd_driver_flags, NULL, NULL },
1331 { NULL, NULL, NULL, NULL }
1336 * Prints command usage, lines are padded with the specified string.
1338 static void print_cmd_help(FILE *stream, const struct hostapd_cli_cmd *cmd,
1344 if (cmd->usage == NULL)
1346 fprintf(stream, "%s%s ", pad, cmd->cmd);
1347 for (n = 0; (c = cmd->usage[n]); n++) {
1348 fprintf(stream, "%c", c);
1350 fprintf(stream, "%s", pad);
1352 fprintf(stream, "\n");
1356 static void print_help(FILE *stream, const char *cmd)
1360 fprintf(stream, "commands:\n");
1361 for (n = 0; hostapd_cli_commands[n].cmd; n++) {
1362 if (cmd == NULL || str_starts(hostapd_cli_commands[n].cmd, cmd))
1363 print_cmd_help(stream, &hostapd_cli_commands[n], " ");
1368 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
1370 const struct hostapd_cli_cmd *cmd, *match = NULL;
1374 cmd = hostapd_cli_commands;
1376 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
1378 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1379 /* we have an exact match */
1389 printf("Ambiguous command '%s'; possible commands:", argv[0]);
1390 cmd = hostapd_cli_commands;
1392 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
1394 printf(" %s", cmd->cmd);
1399 } else if (count == 0) {
1400 printf("Unknown command '%s'\n", argv[0]);
1402 match->handler(ctrl, argc - 1, &argv[1]);
1407 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
1411 if (ctrl_conn == NULL)
1413 while (wpa_ctrl_pending(ctrl)) {
1415 size_t len = sizeof(buf) - 1;
1416 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
1419 hostapd_cli_action_process(buf, len);
1421 if (in_read && first)
1424 printf("%s\n", buf);
1427 printf("Could not read pending message.\n");
1436 static int tokenize_cmd(char *cmd, char *argv[])
1449 if (argc == max_args)
1452 char *pos2 = os_strrchr(pos, '"');
1456 while (*pos != '\0' && *pos != ' ')
1466 static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
1468 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
1469 printf("Connection to hostapd lost - trying to reconnect\n");
1470 hostapd_cli_close_connection();
1473 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1475 printf("Connection to hostapd re-established\n");
1476 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1477 hostapd_cli_attached = 1;
1479 printf("Warning: Failed to attach to "
1485 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
1486 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1490 static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
1496 static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
1498 char *argv[max_args];
1500 argc = tokenize_cmd(cmd, argv);
1502 wpa_request(ctrl_conn, argc, argv);
1506 static void hostapd_cli_edit_eof_cb(void *ctx)
1512 static char ** list_cmd_list(void)
1517 count = ARRAY_SIZE(hostapd_cli_commands);
1518 res = os_calloc(count + 1, sizeof(char *));
1522 for (i = 0; hostapd_cli_commands[i].cmd; i++) {
1523 res[i] = os_strdup(hostapd_cli_commands[i].cmd);
1532 static char ** hostapd_cli_cmd_completion(const char *cmd, const char *str,
1537 for (i = 0; hostapd_cli_commands[i].cmd; i++) {
1538 if (os_strcasecmp(hostapd_cli_commands[i].cmd, cmd) != 0)
1540 if (hostapd_cli_commands[i].completion)
1541 return hostapd_cli_commands[i].completion(str, pos);
1542 if (!hostapd_cli_commands[i].usage)
1545 printf("\r%s\n", hostapd_cli_commands[i].usage);
1554 static char ** hostapd_cli_edit_completion_cb(void *ctx, const char *str,
1561 end = os_strchr(str, ' ');
1562 if (end == NULL || str + pos < end)
1563 return list_cmd_list();
1565 cmd = os_malloc(pos + 1);
1568 os_memcpy(cmd, str, pos);
1569 cmd[end - str] = '\0';
1570 res = hostapd_cli_cmd_completion(cmd, str, pos);
1576 static void hostapd_cli_interactive(void)
1578 printf("\nInteractive mode\n\n");
1580 eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
1581 edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
1582 hostapd_cli_edit_completion_cb, NULL, NULL, NULL);
1583 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1587 edit_deinit(NULL, NULL);
1588 eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
1592 static void hostapd_cli_cleanup(void)
1594 hostapd_cli_close_connection();
1596 os_daemonize_terminate(pid_file);
1598 os_program_deinit();
1602 static void hostapd_cli_action(struct wpa_ctrl *ctrl)
1610 fd = wpa_ctrl_get_fd(ctrl);
1612 while (!hostapd_cli_quit) {
1615 tv.tv_sec = ping_interval;
1617 res = select(fd + 1, &rfds, NULL, NULL, &tv);
1618 if (res < 0 && errno != EINTR) {
1623 if (FD_ISSET(fd, &rfds))
1624 hostapd_cli_recv_pending(ctrl, 0, 1);
1626 len = sizeof(buf) - 1;
1627 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1628 hostapd_cli_action_process) < 0 ||
1629 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
1630 printf("hostapd did not reply to PING "
1631 "command - exiting\n");
1639 int main(int argc, char *argv[])
1641 int warning_displayed = 0;
1645 if (os_program_init())
1649 c = getopt(argc, argv, "a:BhG:i:p:P:s:v");
1654 action_file = optarg;
1660 ping_interval = atoi(optarg);
1666 printf("%s\n", hostapd_cli_version);
1669 os_free(ctrl_ifname);
1670 ctrl_ifname = os_strdup(optarg);
1673 ctrl_iface_dir = optarg;
1679 client_socket_dir = optarg;
1687 interactive = (argc == optind) && (action_file == NULL);
1690 printf("%s\n\n%s\n\n", hostapd_cli_version,
1691 hostapd_cli_license);
1698 if (ctrl_ifname == NULL) {
1699 struct dirent *dent;
1700 DIR *dir = opendir(ctrl_iface_dir);
1702 while ((dent = readdir(dir))) {
1703 if (os_strcmp(dent->d_name, ".") == 0
1705 os_strcmp(dent->d_name, "..") == 0)
1707 printf("Selected interface '%s'\n",
1709 ctrl_ifname = os_strdup(dent->d_name);
1715 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1717 if (warning_displayed)
1718 printf("Connection established.\n");
1723 perror("Failed to connect to hostapd - "
1728 if (!warning_displayed) {
1729 printf("Could not connect to hostapd - re-trying\n");
1730 warning_displayed = 1;
1736 if (interactive || action_file) {
1737 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1738 hostapd_cli_attached = 1;
1740 printf("Warning: Failed to attach to hostapd.\n");
1746 if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
1750 hostapd_cli_interactive();
1751 else if (action_file)
1752 hostapd_cli_action(ctrl_conn);
1754 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1756 os_free(ctrl_ifname);
1758 hostapd_cli_cleanup();
1762 #else /* CONFIG_NO_CTRL_IFACE */
1764 int main(int argc, char *argv[])
1769 #endif /* CONFIG_NO_CTRL_IFACE */