18dbcf02cSchristos /* 28dbcf02cSchristos * hostapd - command line interface for hostapd daemon 3*45d3cc13Schristos * Copyright (c) 2004-2022, Jouni Malinen <j@w1.fi> 48dbcf02cSchristos * 5316ee512Schristos * This software may be distributed under the terms of the BSD license. 6316ee512Schristos * See README for more details. 78dbcf02cSchristos */ 88dbcf02cSchristos 98dbcf02cSchristos #include "includes.h" 108dbcf02cSchristos #include <dirent.h> 118dbcf02cSchristos 128dbcf02cSchristos #include "common/wpa_ctrl.h" 13ecc36642Schristos #include "common/ieee802_11_defs.h" 14b8fa3219Schristos #include "utils/common.h" 15b8fa3219Schristos #include "utils/eloop.h" 16b8fa3219Schristos #include "utils/edit.h" 178dbcf02cSchristos #include "common/version.h" 18ecc36642Schristos #include "common/cli.h" 198dbcf02cSchristos 20ecc36642Schristos #ifndef CONFIG_NO_CTRL_IFACE 218dbcf02cSchristos 22ecc36642Schristos static const char *const hostapd_cli_version = 238dbcf02cSchristos "hostapd_cli v" VERSION_STR "\n" 24*45d3cc13Schristos "Copyright (c) 2004-2024, Jouni Malinen <j@w1.fi> and contributors"; 258dbcf02cSchristos 268dbcf02cSchristos static struct wpa_ctrl *ctrl_conn; 278dbcf02cSchristos static int hostapd_cli_quit = 0; 288dbcf02cSchristos static int hostapd_cli_attached = 0; 293c5783d3Schristos 303c5783d3Schristos #ifndef CONFIG_CTRL_IFACE_DIR 313c5783d3Schristos #define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd" 323c5783d3Schristos #endif /* CONFIG_CTRL_IFACE_DIR */ 333c5783d3Schristos static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR; 34ecc36642Schristos static const char *client_socket_dir = NULL; 353c5783d3Schristos 368dbcf02cSchristos static char *ctrl_ifname = NULL; 378dbcf02cSchristos static const char *pid_file = NULL; 388dbcf02cSchristos static const char *action_file = NULL; 398dbcf02cSchristos static int ping_interval = 5; 40b8fa3219Schristos static int interactive = 0; 41ecc36642Schristos static int event_handler_registered = 0; 42ecc36642Schristos 43ecc36642Schristos static DEFINE_DL_LIST(stations); /* struct cli_txt_entry */ 44ecc36642Schristos 45ecc36642Schristos static void print_help(FILE *stream, const char *cmd); 46ecc36642Schristos static char ** list_cmd_list(void); 47ecc36642Schristos static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx); 48be6b3c4dSchristos static void update_stations(struct wpa_ctrl *ctrl); 49be6b3c4dSchristos static void cli_event(const char *str); 508dbcf02cSchristos 518dbcf02cSchristos 528dbcf02cSchristos static void usage(void) 538dbcf02cSchristos { 548dbcf02cSchristos fprintf(stderr, "%s\n", hostapd_cli_version); 558dbcf02cSchristos fprintf(stderr, 568dbcf02cSchristos "\n" 57*45d3cc13Schristos "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvBr] " 588dbcf02cSchristos "[-a<path>] \\\n" 59ecc36642Schristos " [-P<pid file>] [-G<ping interval>] [command..]\n" 608dbcf02cSchristos "\n" 618dbcf02cSchristos "Options:\n" 628dbcf02cSchristos " -h help (show this usage text)\n" 638dbcf02cSchristos " -v shown version information\n" 648dbcf02cSchristos " -p<path> path to find control sockets (default: " 658dbcf02cSchristos "/var/run/hostapd)\n" 66ecc36642Schristos " -s<dir_path> dir path to open client sockets (default: " 67ecc36642Schristos CONFIG_CTRL_IFACE_DIR ")\n" 688dbcf02cSchristos " -a<file> run in daemon mode executing the action file " 698dbcf02cSchristos "based on events\n" 708dbcf02cSchristos " from hostapd\n" 71*45d3cc13Schristos " -r try to reconnect when client socket is " 72*45d3cc13Schristos "disconnected.\n" 73*45d3cc13Schristos " This is useful only when used with -a.\n" 748dbcf02cSchristos " -B run a daemon in the background\n" 758dbcf02cSchristos " -i<ifname> Interface to listen on (default: first " 768dbcf02cSchristos "interface found in the\n" 77ecc36642Schristos " socket path)\n\n"); 78ecc36642Schristos print_help(stderr, NULL); 79ecc36642Schristos } 80ecc36642Schristos 81ecc36642Schristos 82ecc36642Schristos static void register_event_handler(struct wpa_ctrl *ctrl) 83ecc36642Schristos { 84ecc36642Schristos if (!ctrl_conn) 85ecc36642Schristos return; 86ecc36642Schristos if (interactive) { 87ecc36642Schristos event_handler_registered = 88ecc36642Schristos !eloop_register_read_sock(wpa_ctrl_get_fd(ctrl), 89ecc36642Schristos hostapd_cli_receive, 90ecc36642Schristos NULL, NULL); 91ecc36642Schristos } 92ecc36642Schristos } 93ecc36642Schristos 94ecc36642Schristos 95ecc36642Schristos static void unregister_event_handler(struct wpa_ctrl *ctrl) 96ecc36642Schristos { 97ecc36642Schristos if (!ctrl_conn) 98ecc36642Schristos return; 99ecc36642Schristos if (interactive && event_handler_registered) { 100ecc36642Schristos eloop_unregister_read_sock(wpa_ctrl_get_fd(ctrl)); 101ecc36642Schristos event_handler_registered = 0; 102ecc36642Schristos } 1038dbcf02cSchristos } 1048dbcf02cSchristos 1058dbcf02cSchristos 1068dbcf02cSchristos static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname) 1078dbcf02cSchristos { 108ecc36642Schristos #ifndef CONFIG_CTRL_IFACE_UDP 1098dbcf02cSchristos char *cfile; 1108dbcf02cSchristos int flen; 111ecc36642Schristos #endif /* !CONFIG_CTRL_IFACE_UDP */ 1128dbcf02cSchristos 1138dbcf02cSchristos if (ifname == NULL) 1148dbcf02cSchristos return NULL; 1158dbcf02cSchristos 116ecc36642Schristos #ifdef CONFIG_CTRL_IFACE_UDP 117ecc36642Schristos ctrl_conn = wpa_ctrl_open(ifname); 118ecc36642Schristos return ctrl_conn; 119ecc36642Schristos #else /* CONFIG_CTRL_IFACE_UDP */ 1208dbcf02cSchristos flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2; 1218dbcf02cSchristos cfile = malloc(flen); 1228dbcf02cSchristos if (cfile == NULL) 1238dbcf02cSchristos return NULL; 1248dbcf02cSchristos snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname); 1258dbcf02cSchristos 126ecc36642Schristos if (client_socket_dir && client_socket_dir[0] && 127ecc36642Schristos access(client_socket_dir, F_OK) < 0) { 128ecc36642Schristos perror(client_socket_dir); 129ecc36642Schristos free(cfile); 130ecc36642Schristos return NULL; 131ecc36642Schristos } 132ecc36642Schristos 133ecc36642Schristos ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir); 1348dbcf02cSchristos free(cfile); 1358dbcf02cSchristos return ctrl_conn; 136ecc36642Schristos #endif /* CONFIG_CTRL_IFACE_UDP */ 1378dbcf02cSchristos } 1388dbcf02cSchristos 1398dbcf02cSchristos 1408dbcf02cSchristos static void hostapd_cli_close_connection(void) 1418dbcf02cSchristos { 1428dbcf02cSchristos if (ctrl_conn == NULL) 1438dbcf02cSchristos return; 1448dbcf02cSchristos 145ecc36642Schristos unregister_event_handler(ctrl_conn); 1468dbcf02cSchristos if (hostapd_cli_attached) { 1478dbcf02cSchristos wpa_ctrl_detach(ctrl_conn); 1488dbcf02cSchristos hostapd_cli_attached = 0; 1498dbcf02cSchristos } 1508dbcf02cSchristos wpa_ctrl_close(ctrl_conn); 1518dbcf02cSchristos ctrl_conn = NULL; 1528dbcf02cSchristos } 1538dbcf02cSchristos 1548dbcf02cSchristos 155be6b3c4dSchristos static int hostapd_cli_reconnect(const char *ifname) 156be6b3c4dSchristos { 157be6b3c4dSchristos char *next_ctrl_ifname; 158be6b3c4dSchristos 159be6b3c4dSchristos hostapd_cli_close_connection(); 160be6b3c4dSchristos 161be6b3c4dSchristos if (!ifname) 162be6b3c4dSchristos return -1; 163be6b3c4dSchristos 164be6b3c4dSchristos next_ctrl_ifname = os_strdup(ifname); 165be6b3c4dSchristos os_free(ctrl_ifname); 166be6b3c4dSchristos ctrl_ifname = next_ctrl_ifname; 167be6b3c4dSchristos if (!ctrl_ifname) 168be6b3c4dSchristos return -1; 169be6b3c4dSchristos 170be6b3c4dSchristos ctrl_conn = hostapd_cli_open_connection(ctrl_ifname); 171be6b3c4dSchristos if (!ctrl_conn) 172be6b3c4dSchristos return -1; 173be6b3c4dSchristos if (!interactive && !action_file) 174be6b3c4dSchristos return 0; 175be6b3c4dSchristos if (wpa_ctrl_attach(ctrl_conn) == 0) { 176be6b3c4dSchristos hostapd_cli_attached = 1; 177be6b3c4dSchristos register_event_handler(ctrl_conn); 178be6b3c4dSchristos update_stations(ctrl_conn); 179be6b3c4dSchristos } else { 180be6b3c4dSchristos printf("Warning: Failed to attach to hostapd.\n"); 181be6b3c4dSchristos } 182be6b3c4dSchristos return 0; 183be6b3c4dSchristos } 184be6b3c4dSchristos 185be6b3c4dSchristos 1868dbcf02cSchristos static void hostapd_cli_msg_cb(char *msg, size_t len) 1878dbcf02cSchristos { 188be6b3c4dSchristos cli_event(msg); 1898dbcf02cSchristos printf("%s\n", msg); 1908dbcf02cSchristos } 1918dbcf02cSchristos 1928dbcf02cSchristos 193be6b3c4dSchristos static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd, int print) 1948dbcf02cSchristos { 1958dbcf02cSchristos char buf[4096]; 1968dbcf02cSchristos size_t len; 1978dbcf02cSchristos int ret; 1988dbcf02cSchristos 1998dbcf02cSchristos if (ctrl_conn == NULL) { 2008dbcf02cSchristos printf("Not connected to hostapd - command dropped.\n"); 2018dbcf02cSchristos return -1; 2028dbcf02cSchristos } 2038dbcf02cSchristos len = sizeof(buf) - 1; 2048dbcf02cSchristos ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, 2058dbcf02cSchristos hostapd_cli_msg_cb); 2068dbcf02cSchristos if (ret == -2) { 2078dbcf02cSchristos printf("'%s' command timed out.\n", cmd); 2088dbcf02cSchristos return -2; 2098dbcf02cSchristos } else if (ret < 0) { 2108dbcf02cSchristos printf("'%s' command failed.\n", cmd); 2118dbcf02cSchristos return -1; 2128dbcf02cSchristos } 2138dbcf02cSchristos if (print) { 2148dbcf02cSchristos buf[len] = '\0'; 2158dbcf02cSchristos printf("%s", buf); 2168dbcf02cSchristos } 2178dbcf02cSchristos return 0; 2188dbcf02cSchristos } 2198dbcf02cSchristos 2208dbcf02cSchristos 221be6b3c4dSchristos static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd) 2228dbcf02cSchristos { 2238dbcf02cSchristos return _wpa_ctrl_command(ctrl, cmd, 1); 2248dbcf02cSchristos } 2258dbcf02cSchristos 2268dbcf02cSchristos 227ecc36642Schristos static int hostapd_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd, 228ecc36642Schristos int min_args, int argc, char *argv[]) 229ecc36642Schristos { 230ecc36642Schristos char buf[4096]; 231ecc36642Schristos 232ecc36642Schristos if (argc < min_args) { 233ecc36642Schristos printf("Invalid %s command - at least %d argument%s required.\n", 234ecc36642Schristos cmd, min_args, min_args > 1 ? "s are" : " is"); 235ecc36642Schristos return -1; 236ecc36642Schristos } 237ecc36642Schristos if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0) 238ecc36642Schristos return -1; 239ecc36642Schristos return wpa_ctrl_command(ctrl, buf); 240ecc36642Schristos } 241ecc36642Schristos 242ecc36642Schristos 2438dbcf02cSchristos static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[]) 2448dbcf02cSchristos { 2458dbcf02cSchristos return wpa_ctrl_command(ctrl, "PING"); 2468dbcf02cSchristos } 2478dbcf02cSchristos 2488dbcf02cSchristos 249b8fa3219Schristos static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[]) 250b8fa3219Schristos { 251b8fa3219Schristos return wpa_ctrl_command(ctrl, "RELOG"); 252b8fa3219Schristos } 253b8fa3219Schristos 254b8fa3219Schristos 255*45d3cc13Schristos static int hostapd_cli_cmd_close_log(struct wpa_ctrl *ctrl, int argc, 256*45d3cc13Schristos char *argv[]) 257*45d3cc13Schristos { 258*45d3cc13Schristos return wpa_ctrl_command(ctrl, "CLOSE_LOG"); 259*45d3cc13Schristos } 260*45d3cc13Schristos 261*45d3cc13Schristos 2623c5783d3Schristos static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[]) 2633c5783d3Schristos { 2643c5783d3Schristos if (argc > 0 && os_strcmp(argv[0], "driver") == 0) 2653c5783d3Schristos return wpa_ctrl_command(ctrl, "STATUS-DRIVER"); 2663c5783d3Schristos return wpa_ctrl_command(ctrl, "STATUS"); 2673c5783d3Schristos } 2683c5783d3Schristos 2693c5783d3Schristos 2708dbcf02cSchristos static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[]) 2718dbcf02cSchristos { 2723c5783d3Schristos if (argc > 0) { 2733c5783d3Schristos char buf[100]; 2743c5783d3Schristos os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]); 2753c5783d3Schristos return wpa_ctrl_command(ctrl, buf); 2763c5783d3Schristos } 2778dbcf02cSchristos return wpa_ctrl_command(ctrl, "MIB"); 2788dbcf02cSchristos } 2798dbcf02cSchristos 2808dbcf02cSchristos 2818dbcf02cSchristos static int hostapd_cli_exec(const char *program, const char *arg1, 2828dbcf02cSchristos const char *arg2) 2838dbcf02cSchristos { 2843c5783d3Schristos char *arg; 2858dbcf02cSchristos size_t len; 2868dbcf02cSchristos int res; 2878dbcf02cSchristos 2883c5783d3Schristos len = os_strlen(arg1) + os_strlen(arg2) + 2; 2893c5783d3Schristos arg = os_malloc(len); 2903c5783d3Schristos if (arg == NULL) 2918dbcf02cSchristos return -1; 2923c5783d3Schristos os_snprintf(arg, len, "%s %s", arg1, arg2); 2933c5783d3Schristos res = os_exec(program, arg, 1); 2943c5783d3Schristos os_free(arg); 2958dbcf02cSchristos 2963c5783d3Schristos return res; 2978dbcf02cSchristos } 2988dbcf02cSchristos 2998dbcf02cSchristos 3008dbcf02cSchristos static void hostapd_cli_action_process(char *msg, size_t len) 3018dbcf02cSchristos { 3028dbcf02cSchristos const char *pos; 3038dbcf02cSchristos 3048dbcf02cSchristos pos = msg; 3058dbcf02cSchristos if (*pos == '<') { 3068dbcf02cSchristos pos = os_strchr(pos, '>'); 3078dbcf02cSchristos if (pos) 3088dbcf02cSchristos pos++; 3098dbcf02cSchristos else 3108dbcf02cSchristos pos = msg; 3118dbcf02cSchristos } 3128dbcf02cSchristos 3138dbcf02cSchristos hostapd_cli_exec(action_file, ctrl_ifname, pos); 3148dbcf02cSchristos } 3158dbcf02cSchristos 3168dbcf02cSchristos 317*45d3cc13Schristos static void hostapd_cli_action_cb(char *msg, size_t len) 318*45d3cc13Schristos { 319*45d3cc13Schristos hostapd_cli_action_process(msg, len); 320*45d3cc13Schristos } 321*45d3cc13Schristos 322*45d3cc13Schristos 3238dbcf02cSchristos static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) 3248dbcf02cSchristos { 3258dbcf02cSchristos char buf[64]; 3263c5783d3Schristos if (argc < 1) { 3273c5783d3Schristos printf("Invalid 'sta' command - at least one argument, STA " 3288dbcf02cSchristos "address, is required.\n"); 3298dbcf02cSchristos return -1; 3308dbcf02cSchristos } 3313c5783d3Schristos if (argc > 1) 3323c5783d3Schristos snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]); 3333c5783d3Schristos else 3348dbcf02cSchristos snprintf(buf, sizeof(buf), "STA %s", argv[0]); 3358dbcf02cSchristos return wpa_ctrl_command(ctrl, buf); 3368dbcf02cSchristos } 3378dbcf02cSchristos 3388dbcf02cSchristos 339be6b3c4dSchristos static char ** hostapd_complete_stations(const char *str, int pos) 340be6b3c4dSchristos { 341be6b3c4dSchristos int arg = get_cmd_arg_num(str, pos); 342be6b3c4dSchristos char **res = NULL; 343be6b3c4dSchristos 344be6b3c4dSchristos switch (arg) { 345be6b3c4dSchristos case 1: 346be6b3c4dSchristos res = cli_txt_list_array(&stations); 347be6b3c4dSchristos break; 348be6b3c4dSchristos } 349be6b3c4dSchristos 350be6b3c4dSchristos return res; 351be6b3c4dSchristos } 352be6b3c4dSchristos 353be6b3c4dSchristos 3548dbcf02cSchristos static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc, 3558dbcf02cSchristos char *argv[]) 3568dbcf02cSchristos { 3578dbcf02cSchristos char buf[64]; 3588dbcf02cSchristos if (argc != 1) { 3598dbcf02cSchristos printf("Invalid 'new_sta' command - exactly one argument, STA " 3608dbcf02cSchristos "address, is required.\n"); 3618dbcf02cSchristos return -1; 3628dbcf02cSchristos } 3638dbcf02cSchristos snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]); 3648dbcf02cSchristos return wpa_ctrl_command(ctrl, buf); 3658dbcf02cSchristos } 3668dbcf02cSchristos 3678dbcf02cSchristos 3688dbcf02cSchristos static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc, 3698dbcf02cSchristos char *argv[]) 3708dbcf02cSchristos { 3718dbcf02cSchristos char buf[64]; 3728dbcf02cSchristos if (argc < 1) { 3738dbcf02cSchristos printf("Invalid 'deauthenticate' command - exactly one " 3748dbcf02cSchristos "argument, STA address, is required.\n"); 3758dbcf02cSchristos return -1; 3768dbcf02cSchristos } 3778dbcf02cSchristos if (argc > 1) 3788dbcf02cSchristos os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s", 3798dbcf02cSchristos argv[0], argv[1]); 3808dbcf02cSchristos else 3818dbcf02cSchristos os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]); 3828dbcf02cSchristos return wpa_ctrl_command(ctrl, buf); 3838dbcf02cSchristos } 3848dbcf02cSchristos 3858dbcf02cSchristos 3868dbcf02cSchristos static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc, 3878dbcf02cSchristos char *argv[]) 3888dbcf02cSchristos { 3898dbcf02cSchristos char buf[64]; 3908dbcf02cSchristos if (argc < 1) { 3918dbcf02cSchristos printf("Invalid 'disassociate' command - exactly one " 3928dbcf02cSchristos "argument, STA address, is required.\n"); 3938dbcf02cSchristos return -1; 3948dbcf02cSchristos } 3958dbcf02cSchristos if (argc > 1) 3968dbcf02cSchristos os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s", 3978dbcf02cSchristos argv[0], argv[1]); 3988dbcf02cSchristos else 3998dbcf02cSchristos os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]); 4008dbcf02cSchristos return wpa_ctrl_command(ctrl, buf); 4018dbcf02cSchristos } 4028dbcf02cSchristos 4038dbcf02cSchristos 404ecc36642Schristos #ifdef CONFIG_TAXONOMY 405ecc36642Schristos static int hostapd_cli_cmd_signature(struct wpa_ctrl *ctrl, int argc, 406ecc36642Schristos char *argv[]) 407ecc36642Schristos { 408ecc36642Schristos char buf[64]; 409ecc36642Schristos 410ecc36642Schristos if (argc != 1) { 411ecc36642Schristos printf("Invalid 'signature' command - exactly one argument, STA address, is required.\n"); 412ecc36642Schristos return -1; 413ecc36642Schristos } 414ecc36642Schristos os_snprintf(buf, sizeof(buf), "SIGNATURE %s", argv[0]); 415ecc36642Schristos return wpa_ctrl_command(ctrl, buf); 416ecc36642Schristos } 417ecc36642Schristos #endif /* CONFIG_TAXONOMY */ 418ecc36642Schristos 419ecc36642Schristos 4208dbcf02cSchristos static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc, 4218dbcf02cSchristos char *argv[]) 4228dbcf02cSchristos { 4238dbcf02cSchristos char buf[64]; 4248dbcf02cSchristos if (argc != 1) { 4258dbcf02cSchristos printf("Invalid 'sa_query' command - exactly one argument, " 4268dbcf02cSchristos "STA address, is required.\n"); 4278dbcf02cSchristos return -1; 4288dbcf02cSchristos } 4298dbcf02cSchristos snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]); 4308dbcf02cSchristos return wpa_ctrl_command(ctrl, buf); 4318dbcf02cSchristos } 4328dbcf02cSchristos 4338dbcf02cSchristos 4348dbcf02cSchristos #ifdef CONFIG_WPS 4358dbcf02cSchristos static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, 4368dbcf02cSchristos char *argv[]) 4378dbcf02cSchristos { 438b8fa3219Schristos char buf[256]; 4398dbcf02cSchristos if (argc < 2) { 4408dbcf02cSchristos printf("Invalid 'wps_pin' command - at least two arguments, " 4418dbcf02cSchristos "UUID and PIN, are required.\n"); 4428dbcf02cSchristos return -1; 4438dbcf02cSchristos } 444b8fa3219Schristos if (argc > 3) 445b8fa3219Schristos snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s", 446b8fa3219Schristos argv[0], argv[1], argv[2], argv[3]); 447b8fa3219Schristos else if (argc > 2) 4488dbcf02cSchristos snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s", 4498dbcf02cSchristos argv[0], argv[1], argv[2]); 4508dbcf02cSchristos else 4518dbcf02cSchristos snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]); 4528dbcf02cSchristos return wpa_ctrl_command(ctrl, buf); 4538dbcf02cSchristos } 4548dbcf02cSchristos 4558dbcf02cSchristos 456b8fa3219Schristos static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc, 457b8fa3219Schristos char *argv[]) 458b8fa3219Schristos { 459b8fa3219Schristos char cmd[256]; 460b8fa3219Schristos int res; 461b8fa3219Schristos 462b8fa3219Schristos if (argc != 1 && argc != 2) { 463b8fa3219Schristos printf("Invalid WPS_CHECK_PIN command: needs one argument:\n" 464b8fa3219Schristos "- PIN to be verified\n"); 465b8fa3219Schristos return -1; 466b8fa3219Schristos } 467b8fa3219Schristos 468b8fa3219Schristos if (argc == 2) 469b8fa3219Schristos res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s", 470b8fa3219Schristos argv[0], argv[1]); 471b8fa3219Schristos else 472b8fa3219Schristos res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s", 473b8fa3219Schristos argv[0]); 474299bbf24Schristos if (os_snprintf_error(sizeof(cmd), res)) { 475b8fa3219Schristos printf("Too long WPS_CHECK_PIN command.\n"); 476b8fa3219Schristos return -1; 477b8fa3219Schristos } 478b8fa3219Schristos return wpa_ctrl_command(ctrl, cmd); 479b8fa3219Schristos } 480b8fa3219Schristos 481b8fa3219Schristos 4828dbcf02cSchristos static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, 4838dbcf02cSchristos char *argv[]) 4848dbcf02cSchristos { 4858dbcf02cSchristos return wpa_ctrl_command(ctrl, "WPS_PBC"); 4868dbcf02cSchristos } 4878dbcf02cSchristos 4888dbcf02cSchristos 489316ee512Schristos static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc, 4908dbcf02cSchristos char *argv[]) 4918dbcf02cSchristos { 492316ee512Schristos return wpa_ctrl_command(ctrl, "WPS_CANCEL"); 493316ee512Schristos } 4948dbcf02cSchristos 495316ee512Schristos 496316ee512Schristos #ifdef CONFIG_WPS_NFC 497316ee512Schristos static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc, 498316ee512Schristos char *argv[]) 499316ee512Schristos { 500316ee512Schristos int ret; 501316ee512Schristos char *buf; 502316ee512Schristos size_t buflen; 503316ee512Schristos 504316ee512Schristos if (argc != 1) { 505316ee512Schristos printf("Invalid 'wps_nfc_tag_read' command - one argument " 506316ee512Schristos "is required.\n"); 5078dbcf02cSchristos return -1; 5088dbcf02cSchristos } 5098dbcf02cSchristos 510316ee512Schristos buflen = 18 + os_strlen(argv[0]); 511316ee512Schristos buf = os_malloc(buflen); 512316ee512Schristos if (buf == NULL) 513316ee512Schristos return -1; 514316ee512Schristos os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]); 515316ee512Schristos 516316ee512Schristos ret = wpa_ctrl_command(ctrl, buf); 517316ee512Schristos os_free(buf); 518316ee512Schristos 519316ee512Schristos return ret; 520316ee512Schristos } 521316ee512Schristos 522316ee512Schristos 523316ee512Schristos static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl, 524316ee512Schristos int argc, char *argv[]) 525316ee512Schristos { 526316ee512Schristos char cmd[64]; 527316ee512Schristos int res; 528316ee512Schristos 529316ee512Schristos if (argc != 1) { 530316ee512Schristos printf("Invalid 'wps_nfc_config_token' command - one argument " 531316ee512Schristos "is required.\n"); 532316ee512Schristos return -1; 533316ee512Schristos } 534316ee512Schristos 535316ee512Schristos res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s", 536316ee512Schristos argv[0]); 537299bbf24Schristos if (os_snprintf_error(sizeof(cmd), res)) { 538316ee512Schristos printf("Too long WPS_NFC_CONFIG_TOKEN command.\n"); 5398dbcf02cSchristos return -1; 5408dbcf02cSchristos } 5418dbcf02cSchristos return wpa_ctrl_command(ctrl, cmd); 5428dbcf02cSchristos } 543316ee512Schristos 544316ee512Schristos 545316ee512Schristos static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, 546316ee512Schristos int argc, char *argv[]) 547316ee512Schristos { 548316ee512Schristos char cmd[64]; 549316ee512Schristos int res; 550316ee512Schristos 551316ee512Schristos if (argc != 1) { 552316ee512Schristos printf("Invalid 'wps_nfc_token' command - one argument is " 553316ee512Schristos "required.\n"); 554316ee512Schristos return -1; 555316ee512Schristos } 556316ee512Schristos 557316ee512Schristos res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]); 558299bbf24Schristos if (os_snprintf_error(sizeof(cmd), res)) { 559316ee512Schristos printf("Too long WPS_NFC_TOKEN command.\n"); 560316ee512Schristos return -1; 561316ee512Schristos } 562316ee512Schristos return wpa_ctrl_command(ctrl, cmd); 563316ee512Schristos } 5643c5783d3Schristos 5653c5783d3Schristos 5663c5783d3Schristos static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl, 5673c5783d3Schristos int argc, char *argv[]) 5683c5783d3Schristos { 5693c5783d3Schristos char cmd[64]; 5703c5783d3Schristos int res; 5713c5783d3Schristos 5723c5783d3Schristos if (argc != 2) { 5733c5783d3Schristos printf("Invalid 'nfc_get_handover_sel' command - two arguments " 5743c5783d3Schristos "are required.\n"); 5753c5783d3Schristos return -1; 5763c5783d3Schristos } 5773c5783d3Schristos 5783c5783d3Schristos res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s", 5793c5783d3Schristos argv[0], argv[1]); 580299bbf24Schristos if (os_snprintf_error(sizeof(cmd), res)) { 5813c5783d3Schristos printf("Too long NFC_GET_HANDOVER_SEL command.\n"); 5823c5783d3Schristos return -1; 5833c5783d3Schristos } 5843c5783d3Schristos return wpa_ctrl_command(ctrl, cmd); 5853c5783d3Schristos } 5863c5783d3Schristos 587316ee512Schristos #endif /* CONFIG_WPS_NFC */ 588fa52ba2cSchristos 589fa52ba2cSchristos 590fa52ba2cSchristos static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc, 591fa52ba2cSchristos char *argv[]) 592fa52ba2cSchristos { 593fa52ba2cSchristos char buf[64]; 594fa52ba2cSchristos if (argc < 1) { 595fa52ba2cSchristos printf("Invalid 'wps_ap_pin' command - at least one argument " 596fa52ba2cSchristos "is required.\n"); 597fa52ba2cSchristos return -1; 598fa52ba2cSchristos } 599fa52ba2cSchristos if (argc > 2) 600fa52ba2cSchristos snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s", 601fa52ba2cSchristos argv[0], argv[1], argv[2]); 602fa52ba2cSchristos else if (argc > 1) 603fa52ba2cSchristos snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s", 604fa52ba2cSchristos argv[0], argv[1]); 605fa52ba2cSchristos else 606fa52ba2cSchristos snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]); 607fa52ba2cSchristos return wpa_ctrl_command(ctrl, buf); 608fa52ba2cSchristos } 609b8fa3219Schristos 610b8fa3219Schristos 6113c5783d3Schristos static int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc, 6123c5783d3Schristos char *argv[]) 6133c5783d3Schristos { 6143c5783d3Schristos return wpa_ctrl_command(ctrl, "WPS_GET_STATUS"); 6153c5783d3Schristos } 6163c5783d3Schristos 6173c5783d3Schristos 618b8fa3219Schristos static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc, 619b8fa3219Schristos char *argv[]) 620b8fa3219Schristos { 621b8fa3219Schristos char buf[256]; 622ecc36642Schristos char ssid_hex[2 * SSID_MAX_LEN + 1]; 623b8fa3219Schristos char key_hex[2 * 64 + 1]; 624b8fa3219Schristos int i; 625b8fa3219Schristos 626b8fa3219Schristos if (argc < 1) { 627b8fa3219Schristos printf("Invalid 'wps_config' command - at least two arguments " 628b8fa3219Schristos "are required.\n"); 629b8fa3219Schristos return -1; 630b8fa3219Schristos } 631b8fa3219Schristos 632b8fa3219Schristos ssid_hex[0] = '\0'; 633ecc36642Schristos for (i = 0; i < SSID_MAX_LEN; i++) { 634b8fa3219Schristos if (argv[0][i] == '\0') 635b8fa3219Schristos break; 636b8fa3219Schristos os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]); 637b8fa3219Schristos } 638b8fa3219Schristos 639b8fa3219Schristos key_hex[0] = '\0'; 640b8fa3219Schristos if (argc > 3) { 641b8fa3219Schristos for (i = 0; i < 64; i++) { 642b8fa3219Schristos if (argv[3][i] == '\0') 643b8fa3219Schristos break; 644b8fa3219Schristos os_snprintf(&key_hex[i * 2], 3, "%02x", 645b8fa3219Schristos argv[3][i]); 646b8fa3219Schristos } 647b8fa3219Schristos } 648b8fa3219Schristos 649b8fa3219Schristos if (argc > 3) 650b8fa3219Schristos snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s", 651b8fa3219Schristos ssid_hex, argv[1], argv[2], key_hex); 652b8fa3219Schristos else if (argc > 2) 653b8fa3219Schristos snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s", 654b8fa3219Schristos ssid_hex, argv[1], argv[2]); 655b8fa3219Schristos else 656b8fa3219Schristos snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s", 657b8fa3219Schristos ssid_hex, argv[1]); 658b8fa3219Schristos return wpa_ctrl_command(ctrl, buf); 659b8fa3219Schristos } 6608dbcf02cSchristos #endif /* CONFIG_WPS */ 6618dbcf02cSchristos 6628dbcf02cSchristos 663316ee512Schristos static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc, 664316ee512Schristos char *argv[]) 665316ee512Schristos { 666316ee512Schristos char buf[300]; 667316ee512Schristos int res; 668316ee512Schristos 669316ee512Schristos if (argc < 2) { 670316ee512Schristos printf("Invalid 'disassoc_imminent' command - two arguments " 671316ee512Schristos "(STA addr and Disassociation Timer) are needed\n"); 672316ee512Schristos return -1; 673316ee512Schristos } 674316ee512Schristos 675316ee512Schristos res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s", 676316ee512Schristos argv[0], argv[1]); 677299bbf24Schristos if (os_snprintf_error(sizeof(buf), res)) 678316ee512Schristos return -1; 679316ee512Schristos return wpa_ctrl_command(ctrl, buf); 680316ee512Schristos } 681316ee512Schristos 682316ee512Schristos 683b8fa3219Schristos static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc, 684b8fa3219Schristos char *argv[]) 685b8fa3219Schristos { 686b8fa3219Schristos char buf[300]; 687b8fa3219Schristos int res; 688b8fa3219Schristos 6893c5783d3Schristos if (argc < 3) { 6903c5783d3Schristos printf("Invalid 'ess_disassoc' command - three arguments (STA " 6913c5783d3Schristos "addr, disassoc timer, and URL) are needed\n"); 692b8fa3219Schristos return -1; 693b8fa3219Schristos } 694b8fa3219Schristos 6953c5783d3Schristos res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s", 6963c5783d3Schristos argv[0], argv[1], argv[2]); 697299bbf24Schristos if (os_snprintf_error(sizeof(buf), res)) 698b8fa3219Schristos return -1; 699b8fa3219Schristos return wpa_ctrl_command(ctrl, buf); 700b8fa3219Schristos } 701b8fa3219Schristos 702b8fa3219Schristos 703299bbf24Schristos static int hostapd_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc, 704299bbf24Schristos char *argv[]) 705299bbf24Schristos { 706299bbf24Schristos char buf[2000], *tmp; 707299bbf24Schristos int res, i, total; 708299bbf24Schristos 709299bbf24Schristos if (argc < 1) { 710299bbf24Schristos printf("Invalid 'bss_tm_req' command - at least one argument (STA addr) is needed\n"); 711299bbf24Schristos return -1; 712299bbf24Schristos } 713299bbf24Schristos 714299bbf24Schristos res = os_snprintf(buf, sizeof(buf), "BSS_TM_REQ %s", argv[0]); 715299bbf24Schristos if (os_snprintf_error(sizeof(buf), res)) 716299bbf24Schristos return -1; 717299bbf24Schristos 718299bbf24Schristos total = res; 719299bbf24Schristos for (i = 1; i < argc; i++) { 720299bbf24Schristos tmp = &buf[total]; 721299bbf24Schristos res = os_snprintf(tmp, sizeof(buf) - total, " %s", argv[i]); 722299bbf24Schristos if (os_snprintf_error(sizeof(buf) - total, res)) 723299bbf24Schristos return -1; 724299bbf24Schristos total += res; 725299bbf24Schristos } 726299bbf24Schristos return wpa_ctrl_command(ctrl, buf); 727299bbf24Schristos } 728299bbf24Schristos 729299bbf24Schristos 730b8fa3219Schristos static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc, 731b8fa3219Schristos char *argv[]) 732b8fa3219Schristos { 733b8fa3219Schristos return wpa_ctrl_command(ctrl, "GET_CONFIG"); 734b8fa3219Schristos } 735b8fa3219Schristos 736b8fa3219Schristos 737be6b3c4dSchristos static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, const char *cmd, 738be6b3c4dSchristos char *addr, size_t addr_len, int print) 7398dbcf02cSchristos { 7408dbcf02cSchristos char buf[4096], *pos; 7418dbcf02cSchristos size_t len; 7428dbcf02cSchristos int ret; 7438dbcf02cSchristos 7448dbcf02cSchristos if (ctrl_conn == NULL) { 7458dbcf02cSchristos printf("Not connected to hostapd - command dropped.\n"); 7468dbcf02cSchristos return -1; 7478dbcf02cSchristos } 7488dbcf02cSchristos len = sizeof(buf) - 1; 7498dbcf02cSchristos ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, 7508dbcf02cSchristos hostapd_cli_msg_cb); 7518dbcf02cSchristos if (ret == -2) { 7528dbcf02cSchristos printf("'%s' command timed out.\n", cmd); 7538dbcf02cSchristos return -2; 7548dbcf02cSchristos } else if (ret < 0) { 7558dbcf02cSchristos printf("'%s' command failed.\n", cmd); 7568dbcf02cSchristos return -1; 7578dbcf02cSchristos } 7588dbcf02cSchristos 7598dbcf02cSchristos buf[len] = '\0'; 7608dbcf02cSchristos if (memcmp(buf, "FAIL", 4) == 0) 7618dbcf02cSchristos return -1; 762be6b3c4dSchristos if (print) 7638dbcf02cSchristos printf("%s", buf); 7648dbcf02cSchristos 7658dbcf02cSchristos pos = buf; 7668dbcf02cSchristos while (*pos != '\0' && *pos != '\n') 7678dbcf02cSchristos pos++; 7688dbcf02cSchristos *pos = '\0'; 7698dbcf02cSchristos os_strlcpy(addr, buf, addr_len); 7708dbcf02cSchristos return 0; 7718dbcf02cSchristos } 7728dbcf02cSchristos 7738dbcf02cSchristos 7748dbcf02cSchristos static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, 7758dbcf02cSchristos char *argv[]) 7768dbcf02cSchristos { 7778dbcf02cSchristos char addr[32], cmd[64]; 7788dbcf02cSchristos 779be6b3c4dSchristos if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 1)) 7808dbcf02cSchristos return 0; 7818dbcf02cSchristos do { 7828dbcf02cSchristos snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr); 783be6b3c4dSchristos } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 1) == 0); 7848dbcf02cSchristos 7858dbcf02cSchristos return -1; 7868dbcf02cSchristos } 7878dbcf02cSchristos 7888dbcf02cSchristos 789be6b3c4dSchristos static int hostapd_cli_cmd_list_sta(struct wpa_ctrl *ctrl, int argc, 790be6b3c4dSchristos char *argv[]) 791be6b3c4dSchristos { 792be6b3c4dSchristos char addr[32], cmd[64]; 793be6b3c4dSchristos 794be6b3c4dSchristos if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0)) 795be6b3c4dSchristos return 0; 796be6b3c4dSchristos do { 797be6b3c4dSchristos if (os_strcmp(addr, "") != 0) 798be6b3c4dSchristos printf("%s\n", addr); 799be6b3c4dSchristos os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr); 800be6b3c4dSchristos } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0); 801be6b3c4dSchristos 802be6b3c4dSchristos return 0; 803be6b3c4dSchristos } 804be6b3c4dSchristos 805be6b3c4dSchristos 8068dbcf02cSchristos static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[]) 8078dbcf02cSchristos { 808ecc36642Schristos print_help(stdout, argc > 0 ? argv[0] : NULL); 8098dbcf02cSchristos return 0; 8108dbcf02cSchristos } 8118dbcf02cSchristos 8128dbcf02cSchristos 813ecc36642Schristos static char ** hostapd_cli_complete_help(const char *str, int pos) 814ecc36642Schristos { 815ecc36642Schristos int arg = get_cmd_arg_num(str, pos); 816ecc36642Schristos char **res = NULL; 817ecc36642Schristos 818ecc36642Schristos switch (arg) { 819ecc36642Schristos case 1: 820ecc36642Schristos res = list_cmd_list(); 821ecc36642Schristos break; 822ecc36642Schristos } 823ecc36642Schristos 824ecc36642Schristos return res; 825ecc36642Schristos } 826ecc36642Schristos 827ecc36642Schristos 8288dbcf02cSchristos static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, 8298dbcf02cSchristos char *argv[]) 8308dbcf02cSchristos { 831ecc36642Schristos printf("%s\n\n%s\n", hostapd_cli_version, cli_full_license); 8328dbcf02cSchristos return 0; 8338dbcf02cSchristos } 8348dbcf02cSchristos 8358dbcf02cSchristos 8363c5783d3Schristos static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl, 8373c5783d3Schristos int argc, char *argv[]) 8383c5783d3Schristos { 8393c5783d3Schristos char buf[200]; 8403c5783d3Schristos int res; 8413c5783d3Schristos 8423c5783d3Schristos if (argc != 1) { 8433c5783d3Schristos printf("Invalid 'set_qos_map_set' command - " 8443c5783d3Schristos "one argument (comma delimited QoS map set) " 8453c5783d3Schristos "is needed\n"); 8463c5783d3Schristos return -1; 8473c5783d3Schristos } 8483c5783d3Schristos 8493c5783d3Schristos res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]); 850299bbf24Schristos if (os_snprintf_error(sizeof(buf), res)) 8513c5783d3Schristos return -1; 8523c5783d3Schristos return wpa_ctrl_command(ctrl, buf); 8533c5783d3Schristos } 8543c5783d3Schristos 8553c5783d3Schristos 8563c5783d3Schristos static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl, 8573c5783d3Schristos int argc, char *argv[]) 8583c5783d3Schristos { 8593c5783d3Schristos char buf[50]; 8603c5783d3Schristos int res; 8613c5783d3Schristos 8623c5783d3Schristos if (argc != 1) { 8633c5783d3Schristos printf("Invalid 'send_qos_map_conf' command - " 8643c5783d3Schristos "one argument (STA addr) is needed\n"); 8653c5783d3Schristos return -1; 8663c5783d3Schristos } 8673c5783d3Schristos 8683c5783d3Schristos res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]); 869299bbf24Schristos if (os_snprintf_error(sizeof(buf), res)) 8703c5783d3Schristos return -1; 8713c5783d3Schristos return wpa_ctrl_command(ctrl, buf); 8723c5783d3Schristos } 8733c5783d3Schristos 8743c5783d3Schristos 8753c5783d3Schristos static int hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc, 8763c5783d3Schristos char *argv[]) 8773c5783d3Schristos { 8783c5783d3Schristos char buf[300]; 8793c5783d3Schristos int res; 8803c5783d3Schristos 8813c5783d3Schristos if (argc < 2) { 8823c5783d3Schristos printf("Invalid 'hs20_wnm_notif' command - two arguments (STA " 8833c5783d3Schristos "addr and URL) are needed\n"); 8843c5783d3Schristos return -1; 8853c5783d3Schristos } 8863c5783d3Schristos 8873c5783d3Schristos res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s", 8883c5783d3Schristos argv[0], argv[1]); 889299bbf24Schristos if (os_snprintf_error(sizeof(buf), res)) 8903c5783d3Schristos return -1; 8913c5783d3Schristos return wpa_ctrl_command(ctrl, buf); 8923c5783d3Schristos } 8933c5783d3Schristos 8943c5783d3Schristos 8953c5783d3Schristos static int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc, 8963c5783d3Schristos char *argv[]) 8973c5783d3Schristos { 8983c5783d3Schristos char buf[300]; 8993c5783d3Schristos int res; 9003c5783d3Schristos 9013c5783d3Schristos if (argc < 3) { 9023c5783d3Schristos printf("Invalid 'hs20_deauth_req' command - at least three arguments (STA addr, Code, Re-auth Delay) are needed\n"); 9033c5783d3Schristos return -1; 9043c5783d3Schristos } 9053c5783d3Schristos 9063c5783d3Schristos if (argc > 3) 9073c5783d3Schristos res = os_snprintf(buf, sizeof(buf), 9083c5783d3Schristos "HS20_DEAUTH_REQ %s %s %s %s", 9093c5783d3Schristos argv[0], argv[1], argv[2], argv[3]); 9103c5783d3Schristos else 9113c5783d3Schristos res = os_snprintf(buf, sizeof(buf), 9123c5783d3Schristos "HS20_DEAUTH_REQ %s %s %s", 9133c5783d3Schristos argv[0], argv[1], argv[2]); 914299bbf24Schristos if (os_snprintf_error(sizeof(buf), res)) 9153c5783d3Schristos return -1; 9163c5783d3Schristos return wpa_ctrl_command(ctrl, buf); 9173c5783d3Schristos } 9183c5783d3Schristos 9193c5783d3Schristos 9208dbcf02cSchristos static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[]) 9218dbcf02cSchristos { 9228dbcf02cSchristos hostapd_cli_quit = 1; 923b8fa3219Schristos if (interactive) 924b8fa3219Schristos eloop_terminate(); 9258dbcf02cSchristos return 0; 9268dbcf02cSchristos } 9278dbcf02cSchristos 9288dbcf02cSchristos 9298dbcf02cSchristos static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) 9308dbcf02cSchristos { 9318dbcf02cSchristos char cmd[256]; 9328dbcf02cSchristos if (argc != 1) { 9338dbcf02cSchristos printf("Invalid LEVEL command: needs one argument (debug " 9348dbcf02cSchristos "level)\n"); 9358dbcf02cSchristos return 0; 9368dbcf02cSchristos } 9378dbcf02cSchristos snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]); 9388dbcf02cSchristos return wpa_ctrl_command(ctrl, cmd); 9398dbcf02cSchristos } 9408dbcf02cSchristos 9418dbcf02cSchristos 942be6b3c4dSchristos static void update_stations(struct wpa_ctrl *ctrl) 943be6b3c4dSchristos { 944be6b3c4dSchristos char addr[32], cmd[64]; 945be6b3c4dSchristos 946be6b3c4dSchristos if (!ctrl || !interactive) 947be6b3c4dSchristos return; 948be6b3c4dSchristos 949be6b3c4dSchristos cli_txt_list_flush(&stations); 950be6b3c4dSchristos 951be6b3c4dSchristos if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0)) 952be6b3c4dSchristos return; 953be6b3c4dSchristos do { 954be6b3c4dSchristos if (os_strcmp(addr, "") != 0) 955be6b3c4dSchristos cli_txt_list_add(&stations, addr); 956be6b3c4dSchristos os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr); 957be6b3c4dSchristos } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0); 958be6b3c4dSchristos } 959be6b3c4dSchristos 960be6b3c4dSchristos 961ecc36642Schristos static void hostapd_cli_get_interfaces(struct wpa_ctrl *ctrl, 962ecc36642Schristos struct dl_list *interfaces) 963ecc36642Schristos { 964ecc36642Schristos struct dirent *dent; 965ecc36642Schristos DIR *dir; 966ecc36642Schristos 967ecc36642Schristos if (!ctrl || !interfaces) 968ecc36642Schristos return; 969ecc36642Schristos dir = opendir(ctrl_iface_dir); 970ecc36642Schristos if (dir == NULL) 971ecc36642Schristos return; 972ecc36642Schristos 973ecc36642Schristos while ((dent = readdir(dir))) { 974ecc36642Schristos if (strcmp(dent->d_name, ".") == 0 || 975ecc36642Schristos strcmp(dent->d_name, "..") == 0) 976ecc36642Schristos continue; 977ecc36642Schristos cli_txt_list_add(interfaces, dent->d_name); 978ecc36642Schristos } 979ecc36642Schristos closedir(dir); 980ecc36642Schristos } 981ecc36642Schristos 982ecc36642Schristos 9838dbcf02cSchristos static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl) 9848dbcf02cSchristos { 9858dbcf02cSchristos struct dirent *dent; 9868dbcf02cSchristos DIR *dir; 9878dbcf02cSchristos 9888dbcf02cSchristos dir = opendir(ctrl_iface_dir); 9898dbcf02cSchristos if (dir == NULL) { 9908dbcf02cSchristos printf("Control interface directory '%s' could not be " 991*45d3cc13Schristos "opened.\n", ctrl_iface_dir); 9928dbcf02cSchristos return; 9938dbcf02cSchristos } 9948dbcf02cSchristos 9958dbcf02cSchristos printf("Available interfaces:\n"); 9968dbcf02cSchristos while ((dent = readdir(dir))) { 9978dbcf02cSchristos if (strcmp(dent->d_name, ".") == 0 || 9988dbcf02cSchristos strcmp(dent->d_name, "..") == 0) 9998dbcf02cSchristos continue; 10008dbcf02cSchristos printf("%s\n", dent->d_name); 10018dbcf02cSchristos } 10028dbcf02cSchristos closedir(dir); 10038dbcf02cSchristos } 10048dbcf02cSchristos 10058dbcf02cSchristos 10068dbcf02cSchristos static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, 10078dbcf02cSchristos char *argv[]) 10088dbcf02cSchristos { 10098dbcf02cSchristos if (argc < 1) { 10108dbcf02cSchristos hostapd_cli_list_interfaces(ctrl); 10118dbcf02cSchristos return 0; 10128dbcf02cSchristos } 1013be6b3c4dSchristos if (hostapd_cli_reconnect(argv[0]) != 0) { 10148dbcf02cSchristos printf("Could not connect to interface '%s' - re-trying\n", 10158dbcf02cSchristos ctrl_ifname); 10168dbcf02cSchristos } 10178dbcf02cSchristos return 0; 10188dbcf02cSchristos } 10198dbcf02cSchristos 10208dbcf02cSchristos 1021ecc36642Schristos static char ** hostapd_complete_interface(const char *str, int pos) 1022ecc36642Schristos { 1023ecc36642Schristos int arg = get_cmd_arg_num(str, pos); 1024ecc36642Schristos char **res = NULL; 1025ecc36642Schristos DEFINE_DL_LIST(interfaces); 1026ecc36642Schristos 1027ecc36642Schristos switch (arg) { 1028ecc36642Schristos case 1: 1029ecc36642Schristos hostapd_cli_get_interfaces(ctrl_conn, &interfaces); 1030ecc36642Schristos res = cli_txt_list_array(&interfaces); 1031ecc36642Schristos cli_txt_list_flush(&interfaces); 1032ecc36642Schristos break; 1033ecc36642Schristos } 1034ecc36642Schristos 1035ecc36642Schristos return res; 1036ecc36642Schristos } 1037ecc36642Schristos 1038ecc36642Schristos 1039b8fa3219Schristos static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1040b8fa3219Schristos { 1041be6b3c4dSchristos char cmd[2048]; 1042b8fa3219Schristos int res; 1043b8fa3219Schristos 1044b8fa3219Schristos if (argc != 2) { 1045b8fa3219Schristos printf("Invalid SET command: needs two arguments (variable " 1046b8fa3219Schristos "name and value)\n"); 1047b8fa3219Schristos return -1; 1048b8fa3219Schristos } 1049b8fa3219Schristos 1050b8fa3219Schristos res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]); 1051299bbf24Schristos if (os_snprintf_error(sizeof(cmd), res)) { 1052b8fa3219Schristos printf("Too long SET command.\n"); 1053b8fa3219Schristos return -1; 1054b8fa3219Schristos } 1055b8fa3219Schristos return wpa_ctrl_command(ctrl, cmd); 1056b8fa3219Schristos } 1057b8fa3219Schristos 1058b8fa3219Schristos 1059be6b3c4dSchristos static char ** hostapd_complete_set(const char *str, int pos) 1060be6b3c4dSchristos { 1061be6b3c4dSchristos int arg = get_cmd_arg_num(str, pos); 1062be6b3c4dSchristos const char *fields[] = { 1063be6b3c4dSchristos #ifdef CONFIG_WPS_TESTING 1064*45d3cc13Schristos "wps_version_number", "wps_testing_stub_cred", 1065be6b3c4dSchristos "wps_corrupt_pkhash", 1066be6b3c4dSchristos #endif /* CONFIG_WPS_TESTING */ 1067be6b3c4dSchristos #ifdef CONFIG_INTERWORKING 1068be6b3c4dSchristos "gas_frag_limit", 1069be6b3c4dSchristos #endif /* CONFIG_INTERWORKING */ 1070be6b3c4dSchristos #ifdef CONFIG_TESTING_OPTIONS 1071be6b3c4dSchristos "ext_mgmt_frame_handling", "ext_eapol_frame_io", 1072be6b3c4dSchristos #endif /* CONFIG_TESTING_OPTIONS */ 1073be6b3c4dSchristos #ifdef CONFIG_MBO 1074be6b3c4dSchristos "mbo_assoc_disallow", 1075be6b3c4dSchristos #endif /* CONFIG_MBO */ 1076be6b3c4dSchristos "deny_mac_file", "accept_mac_file", 1077be6b3c4dSchristos }; 1078be6b3c4dSchristos int i, num_fields = ARRAY_SIZE(fields); 1079be6b3c4dSchristos 1080be6b3c4dSchristos if (arg == 1) { 1081be6b3c4dSchristos char **res; 1082be6b3c4dSchristos 1083be6b3c4dSchristos res = os_calloc(num_fields + 1, sizeof(char *)); 1084be6b3c4dSchristos if (!res) 1085be6b3c4dSchristos return NULL; 1086be6b3c4dSchristos for (i = 0; i < num_fields; i++) { 1087be6b3c4dSchristos res[i] = os_strdup(fields[i]); 1088be6b3c4dSchristos if (!res[i]) 1089be6b3c4dSchristos return res; 1090be6b3c4dSchristos } 1091be6b3c4dSchristos return res; 1092be6b3c4dSchristos } 1093be6b3c4dSchristos return NULL; 1094be6b3c4dSchristos } 1095be6b3c4dSchristos 1096be6b3c4dSchristos 1097b8fa3219Schristos static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1098b8fa3219Schristos { 1099b8fa3219Schristos char cmd[256]; 1100b8fa3219Schristos int res; 1101b8fa3219Schristos 1102b8fa3219Schristos if (argc != 1) { 1103b8fa3219Schristos printf("Invalid GET command: needs one argument (variable " 1104b8fa3219Schristos "name)\n"); 1105b8fa3219Schristos return -1; 1106b8fa3219Schristos } 1107b8fa3219Schristos 1108b8fa3219Schristos res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]); 1109299bbf24Schristos if (os_snprintf_error(sizeof(cmd), res)) { 1110b8fa3219Schristos printf("Too long GET command.\n"); 1111b8fa3219Schristos return -1; 1112b8fa3219Schristos } 1113b8fa3219Schristos return wpa_ctrl_command(ctrl, cmd); 1114b8fa3219Schristos } 1115b8fa3219Schristos 1116b8fa3219Schristos 1117be6b3c4dSchristos static char ** hostapd_complete_get(const char *str, int pos) 1118be6b3c4dSchristos { 1119be6b3c4dSchristos int arg = get_cmd_arg_num(str, pos); 1120be6b3c4dSchristos const char *fields[] = { 1121be6b3c4dSchristos "version", "tls_library", 1122be6b3c4dSchristos }; 1123be6b3c4dSchristos int i, num_fields = ARRAY_SIZE(fields); 1124be6b3c4dSchristos 1125be6b3c4dSchristos if (arg == 1) { 1126be6b3c4dSchristos char **res; 1127be6b3c4dSchristos 1128be6b3c4dSchristos res = os_calloc(num_fields + 1, sizeof(char *)); 1129be6b3c4dSchristos if (!res) 1130be6b3c4dSchristos return NULL; 1131be6b3c4dSchristos for (i = 0; i < num_fields; i++) { 1132be6b3c4dSchristos res[i] = os_strdup(fields[i]); 1133be6b3c4dSchristos if (!res[i]) 1134be6b3c4dSchristos return res; 1135be6b3c4dSchristos } 1136be6b3c4dSchristos return res; 1137be6b3c4dSchristos } 1138be6b3c4dSchristos return NULL; 1139be6b3c4dSchristos } 1140be6b3c4dSchristos 1141be6b3c4dSchristos 1142ecc36642Schristos #ifdef CONFIG_FST 1143ecc36642Schristos static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1144ecc36642Schristos { 1145ecc36642Schristos char cmd[256]; 1146ecc36642Schristos int res; 1147ecc36642Schristos int i; 1148ecc36642Schristos int total; 1149ecc36642Schristos 1150ecc36642Schristos if (argc <= 0) { 1151ecc36642Schristos printf("FST command: parameters are required.\n"); 1152ecc36642Schristos return -1; 1153ecc36642Schristos } 1154ecc36642Schristos 1155ecc36642Schristos total = os_snprintf(cmd, sizeof(cmd), "FST-MANAGER"); 1156ecc36642Schristos 1157ecc36642Schristos for (i = 0; i < argc; i++) { 1158ecc36642Schristos res = os_snprintf(cmd + total, sizeof(cmd) - total, " %s", 1159ecc36642Schristos argv[i]); 1160ecc36642Schristos if (os_snprintf_error(sizeof(cmd) - total, res)) { 1161ecc36642Schristos printf("Too long fst command.\n"); 1162ecc36642Schristos return -1; 1163ecc36642Schristos } 1164ecc36642Schristos total += res; 1165ecc36642Schristos } 1166ecc36642Schristos return wpa_ctrl_command(ctrl, cmd); 1167ecc36642Schristos } 1168ecc36642Schristos #endif /* CONFIG_FST */ 1169ecc36642Schristos 1170ecc36642Schristos 1171*45d3cc13Schristos #ifdef CONFIG_IEEE80211AX 1172*45d3cc13Schristos static int hostapd_cli_cmd_color_change(struct wpa_ctrl *ctrl, 1173*45d3cc13Schristos int argc, char *argv[]) 1174*45d3cc13Schristos { 1175*45d3cc13Schristos return hostapd_cli_cmd(ctrl, "COLOR_CHANGE", 1, argc, argv); 1176*45d3cc13Schristos } 1177*45d3cc13Schristos #endif /* CONFIG_IEEE80211AX */ 1178*45d3cc13Schristos 1179*45d3cc13Schristos 11803c5783d3Schristos static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl, 11813c5783d3Schristos int argc, char *argv[]) 11823c5783d3Schristos { 11833c5783d3Schristos char cmd[256]; 11843c5783d3Schristos int res; 11853c5783d3Schristos int i; 11863c5783d3Schristos char *tmp; 11873c5783d3Schristos int total; 11883c5783d3Schristos 11893c5783d3Schristos if (argc < 2) { 11903c5783d3Schristos printf("Invalid chan_switch command: needs at least two " 11913c5783d3Schristos "arguments (count and freq)\n" 11923c5783d3Schristos "usage: <cs_count> <freq> [sec_channel_offset=] " 11933c5783d3Schristos "[center_freq1=] [center_freq2=] [bandwidth=] " 1194*45d3cc13Schristos "[blocktx] [ht|vht|he|eht]\n"); 11953c5783d3Schristos return -1; 11963c5783d3Schristos } 11973c5783d3Schristos 11983c5783d3Schristos res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s", 11993c5783d3Schristos argv[0], argv[1]); 1200299bbf24Schristos if (os_snprintf_error(sizeof(cmd), res)) { 12013c5783d3Schristos printf("Too long CHAN_SWITCH command.\n"); 12023c5783d3Schristos return -1; 12033c5783d3Schristos } 12043c5783d3Schristos 12053c5783d3Schristos total = res; 12063c5783d3Schristos for (i = 2; i < argc; i++) { 12073c5783d3Schristos tmp = cmd + total; 12083c5783d3Schristos res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]); 1209299bbf24Schristos if (os_snprintf_error(sizeof(cmd) - total, res)) { 12103c5783d3Schristos printf("Too long CHAN_SWITCH command.\n"); 12113c5783d3Schristos return -1; 12123c5783d3Schristos } 12133c5783d3Schristos total += res; 12143c5783d3Schristos } 12153c5783d3Schristos return wpa_ctrl_command(ctrl, cmd); 12163c5783d3Schristos } 12173c5783d3Schristos 12183c5783d3Schristos 1219*45d3cc13Schristos static int hostapd_cli_cmd_notify_cw_change(struct wpa_ctrl *ctrl, 1220*45d3cc13Schristos int argc, char *argv[]) 1221*45d3cc13Schristos { 1222*45d3cc13Schristos return hostapd_cli_cmd(ctrl, "NOTIFY_CW_CHANGE", 1, argc, argv); 1223*45d3cc13Schristos } 1224*45d3cc13Schristos 1225*45d3cc13Schristos 1226299bbf24Schristos static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc, 1227299bbf24Schristos char *argv[]) 1228299bbf24Schristos { 1229299bbf24Schristos return wpa_ctrl_command(ctrl, "ENABLE"); 1230299bbf24Schristos } 1231299bbf24Schristos 1232299bbf24Schristos 1233299bbf24Schristos static int hostapd_cli_cmd_reload(struct wpa_ctrl *ctrl, int argc, 1234299bbf24Schristos char *argv[]) 1235299bbf24Schristos { 1236299bbf24Schristos return wpa_ctrl_command(ctrl, "RELOAD"); 1237299bbf24Schristos } 1238299bbf24Schristos 1239299bbf24Schristos 1240*45d3cc13Schristos static int hostapd_cli_cmd_reload_bss(struct wpa_ctrl *ctrl, int argc, 1241*45d3cc13Schristos char *argv[]) 1242*45d3cc13Schristos { 1243*45d3cc13Schristos return wpa_ctrl_command(ctrl, "RELOAD_BSS"); 1244*45d3cc13Schristos } 1245*45d3cc13Schristos 1246*45d3cc13Schristos 1247*45d3cc13Schristos static int hostapd_cli_cmd_reload_config(struct wpa_ctrl *ctrl, int argc, 1248*45d3cc13Schristos char *argv[]) 1249*45d3cc13Schristos { 1250*45d3cc13Schristos return wpa_ctrl_command(ctrl, "RELOAD_CONFIG"); 1251*45d3cc13Schristos } 1252*45d3cc13Schristos 1253*45d3cc13Schristos 1254299bbf24Schristos static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc, 1255299bbf24Schristos char *argv[]) 1256299bbf24Schristos { 1257299bbf24Schristos return wpa_ctrl_command(ctrl, "DISABLE"); 1258299bbf24Schristos } 1259299bbf24Schristos 1260299bbf24Schristos 1261*45d3cc13Schristos static int hostapd_cli_cmd_enable_mld(struct wpa_ctrl *ctrl, int argc, 1262*45d3cc13Schristos char *argv[]) 1263*45d3cc13Schristos { 1264*45d3cc13Schristos return wpa_ctrl_command(ctrl, "ENABLE_MLD"); 1265*45d3cc13Schristos } 1266*45d3cc13Schristos 1267*45d3cc13Schristos 1268*45d3cc13Schristos static int hostapd_cli_cmd_disable_mld(struct wpa_ctrl *ctrl, int argc, 1269*45d3cc13Schristos char *argv[]) 1270*45d3cc13Schristos { 1271*45d3cc13Schristos return wpa_ctrl_command(ctrl, "DISABLE_MLD"); 1272*45d3cc13Schristos } 1273*45d3cc13Schristos 1274*45d3cc13Schristos 1275460bb4fcSchristos static int hostapd_cli_cmd_update_beacon(struct wpa_ctrl *ctrl, int argc, 1276460bb4fcSchristos char *argv[]) 1277460bb4fcSchristos { 1278460bb4fcSchristos return wpa_ctrl_command(ctrl, "UPDATE_BEACON"); 1279460bb4fcSchristos } 1280460bb4fcSchristos 1281460bb4fcSchristos 1282*45d3cc13Schristos static int hostapd_cli_cmd_stop_ap(struct wpa_ctrl *ctrl, int argc, 1283*45d3cc13Schristos char *argv[]) 1284*45d3cc13Schristos { 1285*45d3cc13Schristos return wpa_ctrl_command(ctrl, "STOP_AP"); 1286*45d3cc13Schristos } 1287*45d3cc13Schristos 1288*45d3cc13Schristos 12893c5783d3Schristos static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[]) 12903c5783d3Schristos { 12913c5783d3Schristos char cmd[256]; 12923c5783d3Schristos int res; 12933c5783d3Schristos 1294*45d3cc13Schristos if (argc < 2 || argc > 4) { 12953c5783d3Schristos printf("Invalid vendor command\n" 1296*45d3cc13Schristos "usage: <vendor id> <command id> [<hex formatted command argument>] [nested=<0|1>]\n"); 12973c5783d3Schristos return -1; 12983c5783d3Schristos } 12993c5783d3Schristos 1300*45d3cc13Schristos res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s%s%s", argv[0], 1301*45d3cc13Schristos argv[1], argc >= 3 ? argv[2] : "", 1302*45d3cc13Schristos argc == 4 ? " " : "", argc == 4 ? argv[3] : ""); 1303299bbf24Schristos if (os_snprintf_error(sizeof(cmd), res)) { 13043c5783d3Schristos printf("Too long VENDOR command.\n"); 13053c5783d3Schristos return -1; 13063c5783d3Schristos } 13073c5783d3Schristos return wpa_ctrl_command(ctrl, cmd); 13083c5783d3Schristos } 13093c5783d3Schristos 13103c5783d3Schristos 1311299bbf24Schristos static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc, 1312299bbf24Schristos char *argv[]) 1313299bbf24Schristos { 1314299bbf24Schristos return wpa_ctrl_command(ctrl, "ERP_FLUSH"); 1315299bbf24Schristos } 1316299bbf24Schristos 1317299bbf24Schristos 1318ecc36642Schristos static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, 1319ecc36642Schristos char *argv[]) 1320ecc36642Schristos { 1321ecc36642Schristos char cmd[256]; 1322ecc36642Schristos int res; 1323ecc36642Schristos 1324ecc36642Schristos res = os_snprintf(cmd, sizeof(cmd), "LOG_LEVEL%s%s%s%s", 1325ecc36642Schristos argc >= 1 ? " " : "", 1326ecc36642Schristos argc >= 1 ? argv[0] : "", 1327ecc36642Schristos argc == 2 ? " " : "", 1328ecc36642Schristos argc == 2 ? argv[1] : ""); 1329ecc36642Schristos if (os_snprintf_error(sizeof(cmd), res)) { 1330ecc36642Schristos printf("Too long option\n"); 1331ecc36642Schristos return -1; 1332ecc36642Schristos } 1333ecc36642Schristos return wpa_ctrl_command(ctrl, cmd); 1334ecc36642Schristos } 1335ecc36642Schristos 1336ecc36642Schristos 1337ecc36642Schristos static int hostapd_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1338ecc36642Schristos { 1339ecc36642Schristos if (argc == 0) 1340ecc36642Schristos return -1; 1341ecc36642Schristos return hostapd_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]); 1342ecc36642Schristos } 1343ecc36642Schristos 1344ecc36642Schristos 1345ecc36642Schristos static int hostapd_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1346ecc36642Schristos { 1347ecc36642Schristos return wpa_ctrl_command(ctrl, "PMKSA"); 1348ecc36642Schristos } 1349ecc36642Schristos 1350ecc36642Schristos 1351ecc36642Schristos static int hostapd_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc, 1352ecc36642Schristos char *argv[]) 1353ecc36642Schristos { 1354ecc36642Schristos return wpa_ctrl_command(ctrl, "PMKSA_FLUSH"); 1355ecc36642Schristos } 1356ecc36642Schristos 1357ecc36642Schristos 1358ecc36642Schristos static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc, 1359ecc36642Schristos char *argv[]) 1360ecc36642Schristos { 1361ecc36642Schristos char cmd[2048]; 1362ecc36642Schristos int res; 1363ecc36642Schristos 1364be6b3c4dSchristos if (argc < 3 || argc > 6) { 1365be6b3c4dSchristos printf("Invalid set_neighbor command: needs 3-6 arguments\n"); 1366ecc36642Schristos return -1; 1367ecc36642Schristos } 1368ecc36642Schristos 1369be6b3c4dSchristos res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s %s", 1370ecc36642Schristos argv[0], argv[1], argv[2], argc >= 4 ? argv[3] : "", 1371be6b3c4dSchristos argc >= 5 ? argv[4] : "", argc == 6 ? argv[5] : ""); 1372ecc36642Schristos if (os_snprintf_error(sizeof(cmd), res)) { 1373ecc36642Schristos printf("Too long SET_NEIGHBOR command.\n"); 1374ecc36642Schristos return -1; 1375ecc36642Schristos } 1376ecc36642Schristos return wpa_ctrl_command(ctrl, cmd); 1377ecc36642Schristos } 1378ecc36642Schristos 1379ecc36642Schristos 1380*45d3cc13Schristos static int hostapd_cli_cmd_show_neighbor(struct wpa_ctrl *ctrl, int argc, 1381*45d3cc13Schristos char *argv[]) 1382*45d3cc13Schristos { 1383*45d3cc13Schristos return wpa_ctrl_command(ctrl, "SHOW_NEIGHBOR"); 1384*45d3cc13Schristos } 1385*45d3cc13Schristos 1386*45d3cc13Schristos 1387ecc36642Schristos static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc, 1388ecc36642Schristos char *argv[]) 1389ecc36642Schristos { 1390*45d3cc13Schristos return hostapd_cli_cmd(ctrl, "REMOVE_NEIGHBOR", 1, argc, argv); 1391ecc36642Schristos } 1392ecc36642Schristos 1393ecc36642Schristos 1394ecc36642Schristos static int hostapd_cli_cmd_req_lci(struct wpa_ctrl *ctrl, int argc, 1395ecc36642Schristos char *argv[]) 1396ecc36642Schristos { 1397ecc36642Schristos char cmd[256]; 1398ecc36642Schristos int res; 1399ecc36642Schristos 1400ecc36642Schristos if (argc != 1) { 1401ecc36642Schristos printf("Invalid req_lci command - requires destination address\n"); 1402ecc36642Schristos return -1; 1403ecc36642Schristos } 1404ecc36642Schristos 1405ecc36642Schristos res = os_snprintf(cmd, sizeof(cmd), "REQ_LCI %s", argv[0]); 1406ecc36642Schristos if (os_snprintf_error(sizeof(cmd), res)) { 1407ecc36642Schristos printf("Too long REQ_LCI command.\n"); 1408ecc36642Schristos return -1; 1409ecc36642Schristos } 1410ecc36642Schristos return wpa_ctrl_command(ctrl, cmd); 1411ecc36642Schristos } 1412ecc36642Schristos 1413ecc36642Schristos 1414ecc36642Schristos static int hostapd_cli_cmd_req_range(struct wpa_ctrl *ctrl, int argc, 1415ecc36642Schristos char *argv[]) 1416ecc36642Schristos { 1417ecc36642Schristos if (argc < 4) { 1418ecc36642Schristos printf("Invalid req_range command: needs at least 4 arguments - dest address, randomization interval, min AP count, and 1 to 16 AP addresses\n"); 1419ecc36642Schristos return -1; 1420ecc36642Schristos } 1421ecc36642Schristos 1422ecc36642Schristos return hostapd_cli_cmd(ctrl, "REQ_RANGE", 4, argc, argv); 1423ecc36642Schristos } 1424ecc36642Schristos 1425ecc36642Schristos 1426ecc36642Schristos static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc, 1427ecc36642Schristos char *argv[]) 1428ecc36642Schristos { 1429ecc36642Schristos return wpa_ctrl_command(ctrl, "DRIVER_FLAGS"); 1430ecc36642Schristos } 1431ecc36642Schristos 1432ecc36642Schristos 1433*45d3cc13Schristos static int hostapd_cli_cmd_driver_flags2(struct wpa_ctrl *ctrl, int argc, 1434*45d3cc13Schristos char *argv[]) 1435*45d3cc13Schristos { 1436*45d3cc13Schristos return wpa_ctrl_command(ctrl, "DRIVER_FLAGS2"); 1437*45d3cc13Schristos } 1438*45d3cc13Schristos 1439*45d3cc13Schristos 1440be6b3c4dSchristos #ifdef CONFIG_DPP 1441be6b3c4dSchristos 1442be6b3c4dSchristos static int hostapd_cli_cmd_dpp_qr_code(struct wpa_ctrl *ctrl, int argc, 1443be6b3c4dSchristos char *argv[]) 1444be6b3c4dSchristos { 1445be6b3c4dSchristos return hostapd_cli_cmd(ctrl, "DPP_QR_CODE", 1, argc, argv); 1446be6b3c4dSchristos } 1447be6b3c4dSchristos 1448be6b3c4dSchristos 1449be6b3c4dSchristos static int hostapd_cli_cmd_dpp_bootstrap_gen(struct wpa_ctrl *ctrl, int argc, 1450be6b3c4dSchristos char *argv[]) 1451be6b3c4dSchristos { 1452be6b3c4dSchristos return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_GEN", 1, argc, argv); 1453be6b3c4dSchristos } 1454be6b3c4dSchristos 1455be6b3c4dSchristos 1456be6b3c4dSchristos static int hostapd_cli_cmd_dpp_bootstrap_remove(struct wpa_ctrl *ctrl, int argc, 1457be6b3c4dSchristos char *argv[]) 1458be6b3c4dSchristos { 1459be6b3c4dSchristos return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_REMOVE", 1, argc, argv); 1460be6b3c4dSchristos } 1461be6b3c4dSchristos 1462be6b3c4dSchristos 1463be6b3c4dSchristos static int hostapd_cli_cmd_dpp_bootstrap_get_uri(struct wpa_ctrl *ctrl, 1464be6b3c4dSchristos int argc, char *argv[]) 1465be6b3c4dSchristos { 1466be6b3c4dSchristos return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_GET_URI", 1, argc, argv); 1467be6b3c4dSchristos } 1468be6b3c4dSchristos 1469be6b3c4dSchristos 1470be6b3c4dSchristos static int hostapd_cli_cmd_dpp_bootstrap_info(struct wpa_ctrl *ctrl, int argc, 1471be6b3c4dSchristos char *argv[]) 1472be6b3c4dSchristos { 1473be6b3c4dSchristos return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_INFO", 1, argc, argv); 1474be6b3c4dSchristos } 1475be6b3c4dSchristos 1476be6b3c4dSchristos 1477*45d3cc13Schristos static int hostapd_cli_cmd_dpp_bootstrap_set(struct wpa_ctrl *ctrl, int argc, 1478*45d3cc13Schristos char *argv[]) 1479*45d3cc13Schristos { 1480*45d3cc13Schristos return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_SET", 1, argc, argv); 1481*45d3cc13Schristos } 1482*45d3cc13Schristos 1483*45d3cc13Schristos 1484be6b3c4dSchristos static int hostapd_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc, 1485be6b3c4dSchristos char *argv[]) 1486be6b3c4dSchristos { 1487be6b3c4dSchristos return hostapd_cli_cmd(ctrl, "DPP_AUTH_INIT", 1, argc, argv); 1488be6b3c4dSchristos } 1489be6b3c4dSchristos 1490be6b3c4dSchristos 1491be6b3c4dSchristos static int hostapd_cli_cmd_dpp_listen(struct wpa_ctrl *ctrl, int argc, 1492be6b3c4dSchristos char *argv[]) 1493be6b3c4dSchristos { 1494be6b3c4dSchristos return hostapd_cli_cmd(ctrl, "DPP_LISTEN", 1, argc, argv); 1495be6b3c4dSchristos } 1496be6b3c4dSchristos 1497be6b3c4dSchristos 1498be6b3c4dSchristos static int hostapd_cli_cmd_dpp_stop_listen(struct wpa_ctrl *ctrl, int argc, 1499be6b3c4dSchristos char *argv[]) 1500be6b3c4dSchristos { 1501be6b3c4dSchristos return wpa_ctrl_command(ctrl, "DPP_STOP_LISTEN"); 1502be6b3c4dSchristos } 1503be6b3c4dSchristos 1504be6b3c4dSchristos 1505be6b3c4dSchristos static int hostapd_cli_cmd_dpp_configurator_add(struct wpa_ctrl *ctrl, int argc, 1506be6b3c4dSchristos char *argv[]) 1507be6b3c4dSchristos { 1508be6b3c4dSchristos return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_ADD", 0, argc, argv); 1509be6b3c4dSchristos } 1510be6b3c4dSchristos 1511be6b3c4dSchristos 1512be6b3c4dSchristos static int hostapd_cli_cmd_dpp_configurator_remove(struct wpa_ctrl *ctrl, 1513be6b3c4dSchristos int argc, char *argv[]) 1514be6b3c4dSchristos { 1515be6b3c4dSchristos return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_REMOVE", 1, argc, argv); 1516be6b3c4dSchristos } 1517be6b3c4dSchristos 1518be6b3c4dSchristos 1519be6b3c4dSchristos static int hostapd_cli_cmd_dpp_configurator_get_key(struct wpa_ctrl *ctrl, 1520be6b3c4dSchristos int argc, char *argv[]) 1521be6b3c4dSchristos { 1522be6b3c4dSchristos return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_GET_KEY", 1, argc, argv); 1523be6b3c4dSchristos } 1524be6b3c4dSchristos 1525be6b3c4dSchristos 1526460bb4fcSchristos static int hostapd_cli_cmd_dpp_configurator_sign(struct wpa_ctrl *ctrl, 1527460bb4fcSchristos int argc, char *argv[]) 1528460bb4fcSchristos { 1529460bb4fcSchristos return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_SIGN", 1, argc, argv); 1530460bb4fcSchristos } 1531460bb4fcSchristos 1532460bb4fcSchristos 1533be6b3c4dSchristos static int hostapd_cli_cmd_dpp_pkex_add(struct wpa_ctrl *ctrl, int argc, 1534be6b3c4dSchristos char *argv[]) 1535be6b3c4dSchristos { 1536be6b3c4dSchristos return hostapd_cli_cmd(ctrl, "DPP_PKEX_ADD", 1, argc, argv); 1537be6b3c4dSchristos } 1538be6b3c4dSchristos 1539be6b3c4dSchristos 1540be6b3c4dSchristos static int hostapd_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc, 1541be6b3c4dSchristos char *argv[]) 1542be6b3c4dSchristos { 1543be6b3c4dSchristos return hostapd_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv); 1544be6b3c4dSchristos } 1545be6b3c4dSchristos 1546*45d3cc13Schristos 1547*45d3cc13Schristos #ifdef CONFIG_DPP2 1548*45d3cc13Schristos 1549*45d3cc13Schristos static int hostapd_cli_cmd_dpp_controller_start(struct wpa_ctrl *ctrl, int argc, 1550*45d3cc13Schristos char *argv[]) 1551*45d3cc13Schristos { 1552*45d3cc13Schristos return hostapd_cli_cmd(ctrl, "DPP_CONTROLLER_START", 0, argc, argv); 1553*45d3cc13Schristos } 1554*45d3cc13Schristos 1555*45d3cc13Schristos 1556*45d3cc13Schristos static int hostapd_cli_cmd_dpp_controller_stop(struct wpa_ctrl *ctrl, int argc, 1557*45d3cc13Schristos char *argv[]) 1558*45d3cc13Schristos { 1559*45d3cc13Schristos return wpa_ctrl_command(ctrl, "DPP_CONTROLLER_STOP"); 1560*45d3cc13Schristos } 1561*45d3cc13Schristos 1562*45d3cc13Schristos 1563*45d3cc13Schristos static int hostapd_cli_cmd_dpp_chirp(struct wpa_ctrl *ctrl, int argc, 1564*45d3cc13Schristos char *argv[]) 1565*45d3cc13Schristos { 1566*45d3cc13Schristos return hostapd_cli_cmd(ctrl, "DPP_CHIRP", 1, argc, argv); 1567*45d3cc13Schristos } 1568*45d3cc13Schristos 1569*45d3cc13Schristos 1570*45d3cc13Schristos static int hostapd_cli_cmd_dpp_stop_chirp(struct wpa_ctrl *ctrl, int argc, 1571*45d3cc13Schristos char *argv[]) 1572*45d3cc13Schristos { 1573*45d3cc13Schristos return wpa_ctrl_command(ctrl, "DPP_STOP_CHIRP"); 1574*45d3cc13Schristos } 1575*45d3cc13Schristos 1576*45d3cc13Schristos #endif /* CONFIG_DPP2 */ 1577*45d3cc13Schristos 1578*45d3cc13Schristos 1579*45d3cc13Schristos #ifdef CONFIG_DPP3 1580*45d3cc13Schristos static int hostapd_cli_cmd_dpp_push_button(struct wpa_ctrl *ctrl, int argc, 1581*45d3cc13Schristos char *argv[]) 1582*45d3cc13Schristos { 1583*45d3cc13Schristos return hostapd_cli_cmd(ctrl, "DPP_PUSH_BUTTON", 0, argc, argv); 1584*45d3cc13Schristos } 1585*45d3cc13Schristos #endif /* CONFIG_DPP3 */ 1586be6b3c4dSchristos #endif /* CONFIG_DPP */ 1587be6b3c4dSchristos 1588be6b3c4dSchristos 1589be6b3c4dSchristos static int hostapd_cli_cmd_accept_macacl(struct wpa_ctrl *ctrl, int argc, 1590be6b3c4dSchristos char *argv[]) 1591be6b3c4dSchristos { 1592be6b3c4dSchristos return hostapd_cli_cmd(ctrl, "ACCEPT_ACL", 1, argc, argv); 1593be6b3c4dSchristos } 1594be6b3c4dSchristos 1595be6b3c4dSchristos 1596be6b3c4dSchristos static int hostapd_cli_cmd_deny_macacl(struct wpa_ctrl *ctrl, int argc, 1597be6b3c4dSchristos char *argv[]) 1598be6b3c4dSchristos { 1599be6b3c4dSchristos return hostapd_cli_cmd(ctrl, "DENY_ACL", 1, argc, argv); 1600be6b3c4dSchristos } 1601be6b3c4dSchristos 1602be6b3c4dSchristos 1603be6b3c4dSchristos static int hostapd_cli_cmd_poll_sta(struct wpa_ctrl *ctrl, int argc, 1604be6b3c4dSchristos char *argv[]) 1605be6b3c4dSchristos { 1606be6b3c4dSchristos return hostapd_cli_cmd(ctrl, "POLL_STA", 1, argc, argv); 1607be6b3c4dSchristos } 1608be6b3c4dSchristos 1609be6b3c4dSchristos 1610460bb4fcSchristos static int hostapd_cli_cmd_req_beacon(struct wpa_ctrl *ctrl, int argc, 1611460bb4fcSchristos char *argv[]) 1612460bb4fcSchristos { 1613460bb4fcSchristos return hostapd_cli_cmd(ctrl, "REQ_BEACON", 2, argc, argv); 1614460bb4fcSchristos } 1615460bb4fcSchristos 1616460bb4fcSchristos 1617*45d3cc13Schristos static int hostapd_cli_cmd_req_link_measurement(struct wpa_ctrl *ctrl, int argc, 1618*45d3cc13Schristos char *argv[]) 1619*45d3cc13Schristos { 1620*45d3cc13Schristos return hostapd_cli_cmd(ctrl, "REQ_LINK_MEASUREMENT", 1, argc, argv); 1621*45d3cc13Schristos } 1622*45d3cc13Schristos 1623*45d3cc13Schristos 1624460bb4fcSchristos static int hostapd_cli_cmd_reload_wpa_psk(struct wpa_ctrl *ctrl, int argc, 1625460bb4fcSchristos char *argv[]) 1626460bb4fcSchristos { 1627460bb4fcSchristos return wpa_ctrl_command(ctrl, "RELOAD_WPA_PSK"); 1628460bb4fcSchristos } 1629460bb4fcSchristos 1630460bb4fcSchristos 1631*45d3cc13Schristos #ifdef CONFIG_IEEE80211R_AP 1632*45d3cc13Schristos 1633*45d3cc13Schristos static int hostapd_cli_cmd_get_rxkhs(struct wpa_ctrl *ctrl, int argc, 1634*45d3cc13Schristos char *argv[]) 1635*45d3cc13Schristos { 1636*45d3cc13Schristos return wpa_ctrl_command(ctrl, "GET_RXKHS"); 1637*45d3cc13Schristos } 1638*45d3cc13Schristos 1639*45d3cc13Schristos 1640*45d3cc13Schristos static int hostapd_cli_cmd_reload_rxkhs(struct wpa_ctrl *ctrl, int argc, 1641*45d3cc13Schristos char *argv[]) 1642*45d3cc13Schristos { 1643*45d3cc13Schristos return wpa_ctrl_command(ctrl, "RELOAD_RXKHS"); 1644*45d3cc13Schristos } 1645*45d3cc13Schristos 1646*45d3cc13Schristos #endif /* CONFIG_IEEE80211R_AP */ 1647*45d3cc13Schristos 1648*45d3cc13Schristos 1649*45d3cc13Schristos #ifdef ANDROID 1650*45d3cc13Schristos static int hostapd_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1651*45d3cc13Schristos { 1652*45d3cc13Schristos return hostapd_cli_cmd(ctrl, "DRIVER", 1, argc, argv); 1653*45d3cc13Schristos } 1654*45d3cc13Schristos #endif /* ANDROID */ 1655*45d3cc13Schristos 1656*45d3cc13Schristos 16578dbcf02cSchristos struct hostapd_cli_cmd { 16588dbcf02cSchristos const char *cmd; 16598dbcf02cSchristos int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); 1660ecc36642Schristos char ** (*completion)(const char *str, int pos); 1661ecc36642Schristos const char *usage; 16628dbcf02cSchristos }; 16638dbcf02cSchristos 1664ecc36642Schristos static const struct hostapd_cli_cmd hostapd_cli_commands[] = { 1665ecc36642Schristos { "ping", hostapd_cli_cmd_ping, NULL, 1666ecc36642Schristos "= pings hostapd" }, 1667ecc36642Schristos { "mib", hostapd_cli_cmd_mib, NULL, 1668ecc36642Schristos "= get MIB variables (dot1x, dot11, radius)" }, 1669be6b3c4dSchristos { "relog", hostapd_cli_cmd_relog, NULL, 1670be6b3c4dSchristos "= reload/truncate debug log output file" }, 1671*45d3cc13Schristos { "close_log", hostapd_cli_cmd_close_log, NULL, 1672*45d3cc13Schristos "= disable debug log output file" }, 1673be6b3c4dSchristos { "status", hostapd_cli_cmd_status, NULL, 1674be6b3c4dSchristos "= show interface status info" }, 1675be6b3c4dSchristos { "sta", hostapd_cli_cmd_sta, hostapd_complete_stations, 1676ecc36642Schristos "<addr> = get MIB variables for one station" }, 1677ecc36642Schristos { "all_sta", hostapd_cli_cmd_all_sta, NULL, 1678ecc36642Schristos "= get MIB variables for all stations" }, 1679be6b3c4dSchristos { "list_sta", hostapd_cli_cmd_list_sta, NULL, 1680be6b3c4dSchristos "= list all stations" }, 1681ecc36642Schristos { "new_sta", hostapd_cli_cmd_new_sta, NULL, 1682ecc36642Schristos "<addr> = add a new station" }, 1683ecc36642Schristos { "deauthenticate", hostapd_cli_cmd_deauthenticate, 1684be6b3c4dSchristos hostapd_complete_stations, 1685ecc36642Schristos "<addr> = deauthenticate a station" }, 1686ecc36642Schristos { "disassociate", hostapd_cli_cmd_disassociate, 1687be6b3c4dSchristos hostapd_complete_stations, 1688ecc36642Schristos "<addr> = disassociate a station" }, 1689ecc36642Schristos #ifdef CONFIG_TAXONOMY 1690be6b3c4dSchristos { "signature", hostapd_cli_cmd_signature, hostapd_complete_stations, 1691ecc36642Schristos "<addr> = get taxonomy signature for a station" }, 1692ecc36642Schristos #endif /* CONFIG_TAXONOMY */ 1693be6b3c4dSchristos { "sa_query", hostapd_cli_cmd_sa_query, hostapd_complete_stations, 1694ecc36642Schristos "<addr> = send SA Query to a station" }, 16958dbcf02cSchristos #ifdef CONFIG_WPS 1696ecc36642Schristos { "wps_pin", hostapd_cli_cmd_wps_pin, NULL, 1697ecc36642Schristos "<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" }, 1698ecc36642Schristos { "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL, 1699ecc36642Schristos "<PIN> = verify PIN checksum" }, 1700ecc36642Schristos { "wps_pbc", hostapd_cli_cmd_wps_pbc, NULL, 1701ecc36642Schristos "= indicate button pushed to initiate PBC" }, 1702ecc36642Schristos { "wps_cancel", hostapd_cli_cmd_wps_cancel, NULL, 1703ecc36642Schristos "= cancel the pending WPS operation" }, 1704316ee512Schristos #ifdef CONFIG_WPS_NFC 1705ecc36642Schristos { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read, NULL, 1706ecc36642Schristos "<hexdump> = report read NFC tag with WPS data" }, 1707ecc36642Schristos { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token, NULL, 1708ecc36642Schristos "<WPS/NDEF> = build NFC configuration token" }, 1709ecc36642Schristos { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token, NULL, 1710ecc36642Schristos "<WPS/NDEF/enable/disable> = manager NFC password token" }, 1711ecc36642Schristos { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel, NULL, 1712ecc36642Schristos NULL }, 1713316ee512Schristos #endif /* CONFIG_WPS_NFC */ 1714ecc36642Schristos { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin, NULL, 1715ecc36642Schristos "<cmd> [params..] = enable/disable AP PIN" }, 1716ecc36642Schristos { "wps_config", hostapd_cli_cmd_wps_config, NULL, 1717ecc36642Schristos "<SSID> <auth> <encr> <key> = configure AP" }, 1718ecc36642Schristos { "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL, 1719ecc36642Schristos "= show current WPS status" }, 17208dbcf02cSchristos #endif /* CONFIG_WPS */ 1721be6b3c4dSchristos { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL, 1722be6b3c4dSchristos "= send Disassociation Imminent notification" }, 1723be6b3c4dSchristos { "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL, 1724be6b3c4dSchristos "= send ESS Dissassociation Imminent notification" }, 1725be6b3c4dSchristos { "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL, 1726be6b3c4dSchristos "= send BSS Transition Management Request" }, 1727ecc36642Schristos { "get_config", hostapd_cli_cmd_get_config, NULL, 1728ecc36642Schristos "= show current configuration" }, 1729ecc36642Schristos { "help", hostapd_cli_cmd_help, hostapd_cli_complete_help, 1730ecc36642Schristos "= show this usage help" }, 1731ecc36642Schristos { "interface", hostapd_cli_cmd_interface, hostapd_complete_interface, 1732ecc36642Schristos "[ifname] = show interfaces/select interface" }, 1733ecc36642Schristos #ifdef CONFIG_FST 1734be6b3c4dSchristos { "fst", hostapd_cli_cmd_fst, NULL, 1735be6b3c4dSchristos "<params...> = send FST-MANAGER control interface command" }, 1736ecc36642Schristos #endif /* CONFIG_FST */ 1737be6b3c4dSchristos { "raw", hostapd_cli_cmd_raw, NULL, 1738be6b3c4dSchristos "<params..> = send unprocessed command" }, 1739ecc36642Schristos { "level", hostapd_cli_cmd_level, NULL, 1740ecc36642Schristos "<debug level> = change debug level" }, 1741ecc36642Schristos { "license", hostapd_cli_cmd_license, NULL, 1742ecc36642Schristos "= show full hostapd_cli license" }, 1743ecc36642Schristos { "quit", hostapd_cli_cmd_quit, NULL, 1744ecc36642Schristos "= exit hostapd_cli" }, 1745be6b3c4dSchristos { "set", hostapd_cli_cmd_set, hostapd_complete_set, 1746be6b3c4dSchristos "<name> <value> = set runtime variables" }, 1747be6b3c4dSchristos { "get", hostapd_cli_cmd_get, hostapd_complete_get, 1748be6b3c4dSchristos "<name> = get runtime info" }, 1749be6b3c4dSchristos { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL, 1750be6b3c4dSchristos "<arg,arg,...> = set QoS Map set element" }, 1751be6b3c4dSchristos { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf, 1752be6b3c4dSchristos hostapd_complete_stations, 1753be6b3c4dSchristos "<addr> = send QoS Map Configure frame" }, 1754be6b3c4dSchristos { "chan_switch", hostapd_cli_cmd_chan_switch, NULL, 1755be6b3c4dSchristos "<cs_count> <freq> [sec_channel_offset=] [center_freq1=]\n" 1756be6b3c4dSchristos " [center_freq2=] [bandwidth=] [blocktx] [ht|vht]\n" 1757be6b3c4dSchristos " = initiate channel switch announcement" }, 1758*45d3cc13Schristos #ifdef CONFIG_IEEE80211AX 1759*45d3cc13Schristos { "color_change", hostapd_cli_cmd_color_change, NULL, 1760*45d3cc13Schristos "<color> = initiate BSS color change to set the specified color\n" 1761*45d3cc13Schristos "Value 0 will disable the color.\n"}, 1762*45d3cc13Schristos #endif /* CONFIG_IEEE80211AX */ 1763*45d3cc13Schristos { "notify_cw_change", hostapd_cli_cmd_notify_cw_change, NULL, 1764*45d3cc13Schristos "<channel_width> = 0 - 20 MHz, 1 - 40 MHz, 2 - 80 MHz, 3 - 160 MHz" }, 1765be6b3c4dSchristos { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL, 1766be6b3c4dSchristos "<addr> <url>\n" 1767be6b3c4dSchristos " = send WNM-Notification Subscription Remediation Request" }, 1768be6b3c4dSchristos { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL, 1769be6b3c4dSchristos "<addr> <code (0/1)> <Re-auth-Delay(sec)> [url]\n" 1770be6b3c4dSchristos " = send WNM-Notification imminent deauthentication indication" }, 1771be6b3c4dSchristos { "vendor", hostapd_cli_cmd_vendor, NULL, 1772be6b3c4dSchristos "<vendor id> <sub command id> [<hex formatted data>]\n" 1773be6b3c4dSchristos " = send vendor driver command" }, 1774be6b3c4dSchristos { "enable", hostapd_cli_cmd_enable, NULL, 1775be6b3c4dSchristos "= enable hostapd on current interface" }, 1776be6b3c4dSchristos { "reload", hostapd_cli_cmd_reload, NULL, 1777be6b3c4dSchristos "= reload configuration for current interface" }, 1778*45d3cc13Schristos { "reload_bss", hostapd_cli_cmd_reload_bss, NULL, 1779*45d3cc13Schristos "= reload configuration for current BSS" }, 1780*45d3cc13Schristos { "reload_config", hostapd_cli_cmd_reload_config, NULL, 1781*45d3cc13Schristos "= reload configuration for current interface" }, 1782be6b3c4dSchristos { "disable", hostapd_cli_cmd_disable, NULL, 1783be6b3c4dSchristos "= disable hostapd on current interface" }, 1784*45d3cc13Schristos { "enable_mld", hostapd_cli_cmd_enable_mld, NULL, 1785*45d3cc13Schristos "= enable AP MLD to which the interface is affiliated" }, 1786*45d3cc13Schristos { "disable_mld", hostapd_cli_cmd_disable_mld, NULL, 1787*45d3cc13Schristos "= disable AP MLD to which the interface is affiliated" }, 1788460bb4fcSchristos { "update_beacon", hostapd_cli_cmd_update_beacon, NULL, 1789460bb4fcSchristos "= update Beacon frame contents\n"}, 1790*45d3cc13Schristos { "stop_ap", hostapd_cli_cmd_stop_ap, NULL, 1791*45d3cc13Schristos "= stop AP\n"}, 1792be6b3c4dSchristos { "erp_flush", hostapd_cli_cmd_erp_flush, NULL, 1793be6b3c4dSchristos "= drop all ERP keys"}, 1794be6b3c4dSchristos { "log_level", hostapd_cli_cmd_log_level, NULL, 1795be6b3c4dSchristos "[level] = show/change log verbosity level" }, 1796be6b3c4dSchristos { "pmksa", hostapd_cli_cmd_pmksa, NULL, 1797be6b3c4dSchristos " = show PMKSA cache entries" }, 1798be6b3c4dSchristos { "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL, 1799be6b3c4dSchristos " = flush PMKSA cache" }, 1800be6b3c4dSchristos { "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL, 1801be6b3c4dSchristos "<addr> <ssid=> <nr=> [lci=] [civic=] [stat]\n" 1802be6b3c4dSchristos " = add AP to neighbor database" }, 1803*45d3cc13Schristos { "show_neighbor", hostapd_cli_cmd_show_neighbor, NULL, 1804*45d3cc13Schristos " = show neighbor database entries" }, 1805be6b3c4dSchristos { "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL, 1806*45d3cc13Schristos "<addr> [ssid=<hex>] = remove AP from neighbor database" }, 1807be6b3c4dSchristos { "req_lci", hostapd_cli_cmd_req_lci, hostapd_complete_stations, 1808be6b3c4dSchristos "<addr> = send LCI request to a station"}, 1809be6b3c4dSchristos { "req_range", hostapd_cli_cmd_req_range, NULL, 1810be6b3c4dSchristos " = send FTM range request"}, 1811be6b3c4dSchristos { "driver_flags", hostapd_cli_cmd_driver_flags, NULL, 1812be6b3c4dSchristos " = show supported driver flags"}, 1813*45d3cc13Schristos { "driver_flags2", hostapd_cli_cmd_driver_flags2, NULL, 1814*45d3cc13Schristos " = show supported driver flags2"}, 1815be6b3c4dSchristos #ifdef CONFIG_DPP 1816be6b3c4dSchristos { "dpp_qr_code", hostapd_cli_cmd_dpp_qr_code, NULL, 1817be6b3c4dSchristos "report a scanned DPP URI from a QR Code" }, 1818be6b3c4dSchristos { "dpp_bootstrap_gen", hostapd_cli_cmd_dpp_bootstrap_gen, NULL, 1819be6b3c4dSchristos "type=<qrcode> [chan=..] [mac=..] [info=..] [curve=..] [key=..] = generate DPP bootstrap information" }, 1820be6b3c4dSchristos { "dpp_bootstrap_remove", hostapd_cli_cmd_dpp_bootstrap_remove, NULL, 1821be6b3c4dSchristos "*|<id> = remove DPP bootstrap information" }, 1822be6b3c4dSchristos { "dpp_bootstrap_get_uri", hostapd_cli_cmd_dpp_bootstrap_get_uri, NULL, 1823be6b3c4dSchristos "<id> = get DPP bootstrap URI" }, 1824be6b3c4dSchristos { "dpp_bootstrap_info", hostapd_cli_cmd_dpp_bootstrap_info, NULL, 1825be6b3c4dSchristos "<id> = show DPP bootstrap information" }, 1826*45d3cc13Schristos { "dpp_bootstrap_set", hostapd_cli_cmd_dpp_bootstrap_set, NULL, 1827*45d3cc13Schristos "<id> [conf=..] [ssid=<SSID>] [ssid_charset=#] [psk=<PSK>] [pass=<passphrase>] [configurator=<id>] [conn_status=#] [akm_use_selector=<0|1>] [group_id=..] [expiry=#] [csrattrs=..] = set DPP configurator parameters" }, 1828be6b3c4dSchristos { "dpp_auth_init", hostapd_cli_cmd_dpp_auth_init, NULL, 1829be6b3c4dSchristos "peer=<id> [own=<id>] = initiate DPP bootstrapping" }, 1830be6b3c4dSchristos { "dpp_listen", hostapd_cli_cmd_dpp_listen, NULL, 1831be6b3c4dSchristos "<freq in MHz> = start DPP listen" }, 1832be6b3c4dSchristos { "dpp_stop_listen", hostapd_cli_cmd_dpp_stop_listen, NULL, 1833be6b3c4dSchristos "= stop DPP listen" }, 1834be6b3c4dSchristos { "dpp_configurator_add", hostapd_cli_cmd_dpp_configurator_add, NULL, 1835be6b3c4dSchristos "[curve=..] [key=..] = add DPP configurator" }, 1836be6b3c4dSchristos { "dpp_configurator_remove", hostapd_cli_cmd_dpp_configurator_remove, 1837be6b3c4dSchristos NULL, 1838be6b3c4dSchristos "*|<id> = remove DPP configurator" }, 1839be6b3c4dSchristos { "dpp_configurator_get_key", hostapd_cli_cmd_dpp_configurator_get_key, 1840be6b3c4dSchristos NULL, 1841be6b3c4dSchristos "<id> = Get DPP configurator's private key" }, 1842460bb4fcSchristos { "dpp_configurator_sign", hostapd_cli_cmd_dpp_configurator_sign, NULL, 1843460bb4fcSchristos "conf=<role> configurator=<id> = generate self DPP configuration" }, 1844be6b3c4dSchristos { "dpp_pkex_add", hostapd_cli_cmd_dpp_pkex_add, NULL, 1845be6b3c4dSchristos "add PKEX code" }, 1846be6b3c4dSchristos { "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL, 1847be6b3c4dSchristos "*|<id> = remove DPP pkex information" }, 1848*45d3cc13Schristos #ifdef CONFIG_DPP2 1849*45d3cc13Schristos { "dpp_controller_start", hostapd_cli_cmd_dpp_controller_start, NULL, 1850*45d3cc13Schristos "[tcp_port=<port>] [role=..] = start DPP controller" }, 1851*45d3cc13Schristos { "dpp_controller_stop", hostapd_cli_cmd_dpp_controller_stop, NULL, 1852*45d3cc13Schristos "= stop DPP controller" }, 1853*45d3cc13Schristos { "dpp_chirp", hostapd_cli_cmd_dpp_chirp, NULL, 1854*45d3cc13Schristos "own=<BI ID> iter=<count> = start DPP chirp" }, 1855*45d3cc13Schristos { "dpp_stop_chirp", hostapd_cli_cmd_dpp_stop_chirp, NULL, 1856*45d3cc13Schristos "= stop DPP chirp" }, 1857*45d3cc13Schristos #endif /* CONFIG_DPP2 */ 1858*45d3cc13Schristos #ifdef CONFIG_DPP3 1859*45d3cc13Schristos { "dpp_push_button", hostapd_cli_cmd_dpp_push_button, NULL, 1860*45d3cc13Schristos "= press DPP push button" }, 1861*45d3cc13Schristos #endif /* CONFIG_DPP3 */ 1862be6b3c4dSchristos #endif /* CONFIG_DPP */ 1863be6b3c4dSchristos { "accept_acl", hostapd_cli_cmd_accept_macacl, NULL, 1864be6b3c4dSchristos "=Add/Delete/Show/Clear accept MAC ACL" }, 1865be6b3c4dSchristos { "deny_acl", hostapd_cli_cmd_deny_macacl, NULL, 1866be6b3c4dSchristos "=Add/Delete/Show/Clear deny MAC ACL" }, 1867be6b3c4dSchristos { "poll_sta", hostapd_cli_cmd_poll_sta, hostapd_complete_stations, 1868be6b3c4dSchristos "<addr> = poll a STA to check connectivity with a QoS null frame" }, 1869460bb4fcSchristos { "req_beacon", hostapd_cli_cmd_req_beacon, NULL, 1870460bb4fcSchristos "<addr> [req_mode=] <measurement request hexdump> = send a Beacon report request to a station" }, 1871*45d3cc13Schristos { "req_link_measurement", hostapd_cli_cmd_req_link_measurement, NULL, 1872*45d3cc13Schristos "<addr> = send a link measurement report request to a station"}, 1873460bb4fcSchristos { "reload_wpa_psk", hostapd_cli_cmd_reload_wpa_psk, NULL, 1874460bb4fcSchristos "= reload wpa_psk_file only" }, 1875*45d3cc13Schristos #ifdef CONFIG_IEEE80211R_AP 1876*45d3cc13Schristos { "reload_rxkhs", hostapd_cli_cmd_reload_rxkhs, NULL, 1877*45d3cc13Schristos "= reload R0KHs and R1KHs" }, 1878*45d3cc13Schristos { "get_rxkhs", hostapd_cli_cmd_get_rxkhs, NULL, 1879*45d3cc13Schristos "= get R0KHs and R1KHs" }, 1880*45d3cc13Schristos #endif /* CONFIG_IEEE80211R_AP */ 1881*45d3cc13Schristos #ifdef ANDROID 1882*45d3cc13Schristos { "driver", hostapd_cli_cmd_driver, NULL, 1883*45d3cc13Schristos "<driver sub command> [<hex formatted data>] = send driver command data" }, 1884*45d3cc13Schristos #endif /* ANDROID */ 1885ecc36642Schristos { NULL, NULL, NULL, NULL } 18868dbcf02cSchristos }; 18878dbcf02cSchristos 18888dbcf02cSchristos 1889ecc36642Schristos /* 1890ecc36642Schristos * Prints command usage, lines are padded with the specified string. 1891ecc36642Schristos */ 1892ecc36642Schristos static void print_cmd_help(FILE *stream, const struct hostapd_cli_cmd *cmd, 1893ecc36642Schristos const char *pad) 1894ecc36642Schristos { 1895ecc36642Schristos char c; 1896ecc36642Schristos size_t n; 1897ecc36642Schristos 1898ecc36642Schristos if (cmd->usage == NULL) 1899ecc36642Schristos return; 1900ecc36642Schristos fprintf(stream, "%s%s ", pad, cmd->cmd); 1901ecc36642Schristos for (n = 0; (c = cmd->usage[n]); n++) { 1902ecc36642Schristos fprintf(stream, "%c", c); 1903ecc36642Schristos if (c == '\n') 1904ecc36642Schristos fprintf(stream, "%s", pad); 1905ecc36642Schristos } 1906ecc36642Schristos fprintf(stream, "\n"); 1907ecc36642Schristos } 1908ecc36642Schristos 1909ecc36642Schristos 1910ecc36642Schristos static void print_help(FILE *stream, const char *cmd) 1911ecc36642Schristos { 1912ecc36642Schristos int n; 1913ecc36642Schristos 1914ecc36642Schristos fprintf(stream, "commands:\n"); 1915ecc36642Schristos for (n = 0; hostapd_cli_commands[n].cmd; n++) { 1916ecc36642Schristos if (cmd == NULL || str_starts(hostapd_cli_commands[n].cmd, cmd)) 1917ecc36642Schristos print_cmd_help(stream, &hostapd_cli_commands[n], " "); 1918ecc36642Schristos } 1919ecc36642Schristos } 1920ecc36642Schristos 1921ecc36642Schristos 19228dbcf02cSchristos static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) 19238dbcf02cSchristos { 1924ecc36642Schristos const struct hostapd_cli_cmd *cmd, *match = NULL; 19258dbcf02cSchristos int count; 19268dbcf02cSchristos 19278dbcf02cSchristos count = 0; 19288dbcf02cSchristos cmd = hostapd_cli_commands; 19298dbcf02cSchristos while (cmd->cmd) { 19308dbcf02cSchristos if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) { 19318dbcf02cSchristos match = cmd; 1932b8fa3219Schristos if (os_strcasecmp(cmd->cmd, argv[0]) == 0) { 1933b8fa3219Schristos /* we have an exact match */ 1934b8fa3219Schristos count = 1; 1935b8fa3219Schristos break; 1936b8fa3219Schristos } 19378dbcf02cSchristos count++; 19388dbcf02cSchristos } 19398dbcf02cSchristos cmd++; 19408dbcf02cSchristos } 19418dbcf02cSchristos 19428dbcf02cSchristos if (count > 1) { 19438dbcf02cSchristos printf("Ambiguous command '%s'; possible commands:", argv[0]); 19448dbcf02cSchristos cmd = hostapd_cli_commands; 19458dbcf02cSchristos while (cmd->cmd) { 19468dbcf02cSchristos if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 19478dbcf02cSchristos 0) { 19488dbcf02cSchristos printf(" %s", cmd->cmd); 19498dbcf02cSchristos } 19508dbcf02cSchristos cmd++; 19518dbcf02cSchristos } 19528dbcf02cSchristos printf("\n"); 19538dbcf02cSchristos } else if (count == 0) { 19548dbcf02cSchristos printf("Unknown command '%s'\n", argv[0]); 19558dbcf02cSchristos } else { 19568dbcf02cSchristos match->handler(ctrl, argc - 1, &argv[1]); 19578dbcf02cSchristos } 19588dbcf02cSchristos } 19598dbcf02cSchristos 19608dbcf02cSchristos 1961ecc36642Schristos static void cli_event(const char *str) 1962ecc36642Schristos { 1963ecc36642Schristos const char *start, *s; 1964ecc36642Schristos 1965ecc36642Schristos start = os_strchr(str, '>'); 1966ecc36642Schristos if (start == NULL) 1967ecc36642Schristos return; 1968ecc36642Schristos 1969ecc36642Schristos start++; 1970ecc36642Schristos 1971ecc36642Schristos if (str_starts(start, AP_STA_CONNECTED)) { 1972ecc36642Schristos s = os_strchr(start, ' '); 1973ecc36642Schristos if (s == NULL) 1974ecc36642Schristos return; 1975ecc36642Schristos cli_txt_list_add(&stations, s + 1); 1976ecc36642Schristos return; 1977ecc36642Schristos } 1978ecc36642Schristos 1979ecc36642Schristos if (str_starts(start, AP_STA_DISCONNECTED)) { 1980ecc36642Schristos s = os_strchr(start, ' '); 1981ecc36642Schristos if (s == NULL) 1982ecc36642Schristos return; 1983ecc36642Schristos cli_txt_list_del_addr(&stations, s + 1); 1984ecc36642Schristos return; 1985ecc36642Schristos } 1986ecc36642Schristos } 1987ecc36642Schristos 1988ecc36642Schristos 19898dbcf02cSchristos static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read, 19908dbcf02cSchristos int action_monitor) 19918dbcf02cSchristos { 19928dbcf02cSchristos int first = 1; 19938dbcf02cSchristos if (ctrl_conn == NULL) 19948dbcf02cSchristos return; 19958dbcf02cSchristos while (wpa_ctrl_pending(ctrl)) { 1996be6b3c4dSchristos char buf[4096]; 19978dbcf02cSchristos size_t len = sizeof(buf) - 1; 19988dbcf02cSchristos if (wpa_ctrl_recv(ctrl, buf, &len) == 0) { 19998dbcf02cSchristos buf[len] = '\0'; 20008dbcf02cSchristos if (action_monitor) 20018dbcf02cSchristos hostapd_cli_action_process(buf, len); 20028dbcf02cSchristos else { 2003ecc36642Schristos cli_event(buf); 20048dbcf02cSchristos if (in_read && first) 20058dbcf02cSchristos printf("\n"); 20068dbcf02cSchristos first = 0; 20078dbcf02cSchristos printf("%s\n", buf); 20088dbcf02cSchristos } 20098dbcf02cSchristos } else { 20108dbcf02cSchristos printf("Could not read pending message.\n"); 20118dbcf02cSchristos break; 20128dbcf02cSchristos } 20138dbcf02cSchristos } 20148dbcf02cSchristos } 20158dbcf02cSchristos 20168dbcf02cSchristos 2017ecc36642Schristos static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx) 2018b8fa3219Schristos { 2019ecc36642Schristos hostapd_cli_recv_pending(ctrl_conn, 0, 0); 20208dbcf02cSchristos } 20218dbcf02cSchristos 20228dbcf02cSchristos 2023b8fa3219Schristos static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx) 20248dbcf02cSchristos { 20258dbcf02cSchristos if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) { 20268dbcf02cSchristos printf("Connection to hostapd lost - trying to reconnect\n"); 20278dbcf02cSchristos hostapd_cli_close_connection(); 20288dbcf02cSchristos } 2029be6b3c4dSchristos if (!ctrl_conn && hostapd_cli_reconnect(ctrl_ifname) == 0) 20308dbcf02cSchristos printf("Connection to hostapd re-established\n"); 20318dbcf02cSchristos if (ctrl_conn) 20328dbcf02cSchristos hostapd_cli_recv_pending(ctrl_conn, 1, 0); 2033b8fa3219Schristos eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL); 2034b8fa3219Schristos } 2035b8fa3219Schristos 2036b8fa3219Schristos 2037b8fa3219Schristos static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx) 2038b8fa3219Schristos { 2039b8fa3219Schristos eloop_terminate(); 2040b8fa3219Schristos } 2041b8fa3219Schristos 2042b8fa3219Schristos 2043b8fa3219Schristos static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd) 2044b8fa3219Schristos { 2045b8fa3219Schristos char *argv[max_args]; 2046b8fa3219Schristos int argc; 2047b8fa3219Schristos argc = tokenize_cmd(cmd, argv); 2048b8fa3219Schristos if (argc) 2049b8fa3219Schristos wpa_request(ctrl_conn, argc, argv); 2050b8fa3219Schristos } 2051b8fa3219Schristos 2052b8fa3219Schristos 2053b8fa3219Schristos static void hostapd_cli_edit_eof_cb(void *ctx) 2054b8fa3219Schristos { 2055b8fa3219Schristos eloop_terminate(); 2056b8fa3219Schristos } 2057b8fa3219Schristos 2058b8fa3219Schristos 2059ecc36642Schristos static char ** list_cmd_list(void) 2060ecc36642Schristos { 2061ecc36642Schristos char **res; 2062ecc36642Schristos int i, count; 2063ecc36642Schristos 2064ecc36642Schristos count = ARRAY_SIZE(hostapd_cli_commands); 2065ecc36642Schristos res = os_calloc(count + 1, sizeof(char *)); 2066ecc36642Schristos if (res == NULL) 2067ecc36642Schristos return NULL; 2068ecc36642Schristos 2069ecc36642Schristos for (i = 0; hostapd_cli_commands[i].cmd; i++) { 2070ecc36642Schristos res[i] = os_strdup(hostapd_cli_commands[i].cmd); 2071ecc36642Schristos if (res[i] == NULL) 2072ecc36642Schristos break; 2073ecc36642Schristos } 2074ecc36642Schristos 2075ecc36642Schristos return res; 2076ecc36642Schristos } 2077ecc36642Schristos 2078ecc36642Schristos 2079ecc36642Schristos static char ** hostapd_cli_cmd_completion(const char *cmd, const char *str, 2080ecc36642Schristos int pos) 2081ecc36642Schristos { 2082ecc36642Schristos int i; 2083ecc36642Schristos 2084ecc36642Schristos for (i = 0; hostapd_cli_commands[i].cmd; i++) { 2085ecc36642Schristos if (os_strcasecmp(hostapd_cli_commands[i].cmd, cmd) != 0) 2086ecc36642Schristos continue; 2087ecc36642Schristos if (hostapd_cli_commands[i].completion) 2088ecc36642Schristos return hostapd_cli_commands[i].completion(str, pos); 2089ecc36642Schristos if (!hostapd_cli_commands[i].usage) 2090ecc36642Schristos return NULL; 2091ecc36642Schristos edit_clear_line(); 2092ecc36642Schristos printf("\r%s\n", hostapd_cli_commands[i].usage); 2093ecc36642Schristos edit_redraw(); 2094ecc36642Schristos break; 2095ecc36642Schristos } 2096ecc36642Schristos 2097ecc36642Schristos return NULL; 2098ecc36642Schristos } 2099ecc36642Schristos 2100ecc36642Schristos 2101ecc36642Schristos static char ** hostapd_cli_edit_completion_cb(void *ctx, const char *str, 2102ecc36642Schristos int pos) 2103ecc36642Schristos { 2104ecc36642Schristos char **res; 2105ecc36642Schristos const char *end; 2106ecc36642Schristos char *cmd; 2107ecc36642Schristos 2108ecc36642Schristos end = os_strchr(str, ' '); 2109ecc36642Schristos if (end == NULL || str + pos < end) 2110ecc36642Schristos return list_cmd_list(); 2111ecc36642Schristos 2112ecc36642Schristos cmd = os_malloc(pos + 1); 2113ecc36642Schristos if (cmd == NULL) 2114ecc36642Schristos return NULL; 2115ecc36642Schristos os_memcpy(cmd, str, pos); 2116ecc36642Schristos cmd[end - str] = '\0'; 2117ecc36642Schristos res = hostapd_cli_cmd_completion(cmd, str, pos); 2118ecc36642Schristos os_free(cmd); 2119ecc36642Schristos return res; 2120ecc36642Schristos } 2121ecc36642Schristos 2122ecc36642Schristos 2123b8fa3219Schristos static void hostapd_cli_interactive(void) 2124b8fa3219Schristos { 2125be6b3c4dSchristos char *hfile = NULL; 2126be6b3c4dSchristos char *home; 2127be6b3c4dSchristos 2128b8fa3219Schristos printf("\nInteractive mode\n\n"); 2129b8fa3219Schristos 2130be6b3c4dSchristos #ifdef CONFIG_HOSTAPD_CLI_HISTORY_DIR 2131be6b3c4dSchristos home = CONFIG_HOSTAPD_CLI_HISTORY_DIR; 2132be6b3c4dSchristos #else /* CONFIG_HOSTAPD_CLI_HISTORY_DIR */ 2133be6b3c4dSchristos home = getenv("HOME"); 2134be6b3c4dSchristos #endif /* CONFIG_HOSTAPD_CLI_HISTORY_DIR */ 2135be6b3c4dSchristos if (home) { 2136be6b3c4dSchristos const char *fname = ".hostapd_cli_history"; 2137be6b3c4dSchristos int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1; 2138be6b3c4dSchristos hfile = os_malloc(hfile_len); 2139be6b3c4dSchristos if (hfile) 2140be6b3c4dSchristos os_snprintf(hfile, hfile_len, "%s/%s", home, fname); 2141be6b3c4dSchristos } 2142be6b3c4dSchristos 2143b8fa3219Schristos edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb, 2144be6b3c4dSchristos hostapd_cli_edit_completion_cb, NULL, hfile, NULL); 2145b8fa3219Schristos eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL); 2146b8fa3219Schristos 2147b8fa3219Schristos eloop_run(); 2148b8fa3219Schristos 2149ecc36642Schristos cli_txt_list_flush(&stations); 2150be6b3c4dSchristos edit_deinit(hfile, NULL); 2151be6b3c4dSchristos os_free(hfile); 2152b8fa3219Schristos eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL); 2153b8fa3219Schristos } 2154b8fa3219Schristos 2155b8fa3219Schristos 2156b8fa3219Schristos static void hostapd_cli_cleanup(void) 2157b8fa3219Schristos { 2158b8fa3219Schristos hostapd_cli_close_connection(); 2159b8fa3219Schristos if (pid_file) 2160b8fa3219Schristos os_daemonize_terminate(pid_file); 2161b8fa3219Schristos 2162b8fa3219Schristos os_program_deinit(); 21638dbcf02cSchristos } 21648dbcf02cSchristos 21658dbcf02cSchristos 2166*45d3cc13Schristos static void hostapd_cli_action_ping(void *eloop_ctx, void *timeout_ctx) 21678dbcf02cSchristos { 2168*45d3cc13Schristos struct wpa_ctrl *ctrl = eloop_ctx; 21698dbcf02cSchristos char buf[256]; 21708dbcf02cSchristos size_t len; 21718dbcf02cSchristos 2172*45d3cc13Schristos /* verify that connection is still working */ 21738dbcf02cSchristos len = sizeof(buf) - 1; 21748dbcf02cSchristos if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len, 2175*45d3cc13Schristos hostapd_cli_action_cb) < 0 || 21768dbcf02cSchristos len < 4 || os_memcmp(buf, "PONG", 4) != 0) { 2177*45d3cc13Schristos printf("hostapd did not reply to PING command - exiting\n"); 2178*45d3cc13Schristos eloop_terminate(); 2179*45d3cc13Schristos return; 21808dbcf02cSchristos } 2181*45d3cc13Schristos eloop_register_timeout(ping_interval, 0, hostapd_cli_action_ping, 2182*45d3cc13Schristos ctrl, NULL); 21838dbcf02cSchristos } 2184*45d3cc13Schristos 2185*45d3cc13Schristos 2186*45d3cc13Schristos static void hostapd_cli_action_receive(int sock, void *eloop_ctx, 2187*45d3cc13Schristos void *sock_ctx) 2188*45d3cc13Schristos { 2189*45d3cc13Schristos struct wpa_ctrl *ctrl = eloop_ctx; 2190*45d3cc13Schristos 2191*45d3cc13Schristos hostapd_cli_recv_pending(ctrl, 0, 1); 21928dbcf02cSchristos } 2193*45d3cc13Schristos 2194*45d3cc13Schristos 2195*45d3cc13Schristos static void hostapd_cli_action(struct wpa_ctrl *ctrl) 2196*45d3cc13Schristos { 2197*45d3cc13Schristos int fd; 2198*45d3cc13Schristos 2199*45d3cc13Schristos fd = wpa_ctrl_get_fd(ctrl); 2200*45d3cc13Schristos eloop_register_timeout(ping_interval, 0, hostapd_cli_action_ping, 2201*45d3cc13Schristos ctrl, NULL); 2202*45d3cc13Schristos eloop_register_read_sock(fd, hostapd_cli_action_receive, ctrl, NULL); 2203*45d3cc13Schristos eloop_run(); 2204*45d3cc13Schristos eloop_cancel_timeout(hostapd_cli_action_ping, ctrl, NULL); 2205*45d3cc13Schristos eloop_unregister_read_sock(fd); 22068dbcf02cSchristos } 22078dbcf02cSchristos 22088dbcf02cSchristos 22098dbcf02cSchristos int main(int argc, char *argv[]) 22108dbcf02cSchristos { 22118dbcf02cSchristos int warning_displayed = 0; 22128dbcf02cSchristos int c; 22138dbcf02cSchristos int daemonize = 0; 2214*45d3cc13Schristos int reconnect = 0; 22158dbcf02cSchristos 22168dbcf02cSchristos if (os_program_init()) 22178dbcf02cSchristos return -1; 22188dbcf02cSchristos 22198dbcf02cSchristos for (;;) { 2220*45d3cc13Schristos c = getopt(argc, argv, "a:BhG:i:p:P:rs:v"); 22218dbcf02cSchristos if (c < 0) 22228dbcf02cSchristos break; 22238dbcf02cSchristos switch (c) { 22248dbcf02cSchristos case 'a': 22258dbcf02cSchristos action_file = optarg; 22268dbcf02cSchristos break; 22278dbcf02cSchristos case 'B': 22288dbcf02cSchristos daemonize = 1; 22298dbcf02cSchristos break; 22308dbcf02cSchristos case 'G': 22318dbcf02cSchristos ping_interval = atoi(optarg); 22328dbcf02cSchristos break; 22338dbcf02cSchristos case 'h': 22348dbcf02cSchristos usage(); 22358dbcf02cSchristos return 0; 22368dbcf02cSchristos case 'v': 22378dbcf02cSchristos printf("%s\n", hostapd_cli_version); 22388dbcf02cSchristos return 0; 22398dbcf02cSchristos case 'i': 22408dbcf02cSchristos os_free(ctrl_ifname); 22418dbcf02cSchristos ctrl_ifname = os_strdup(optarg); 22428dbcf02cSchristos break; 22438dbcf02cSchristos case 'p': 22448dbcf02cSchristos ctrl_iface_dir = optarg; 22458dbcf02cSchristos break; 2246ecc36642Schristos case 'P': 2247ecc36642Schristos pid_file = optarg; 2248ecc36642Schristos break; 2249*45d3cc13Schristos case 'r': 2250*45d3cc13Schristos reconnect = 1; 2251*45d3cc13Schristos break; 2252ecc36642Schristos case 's': 2253ecc36642Schristos client_socket_dir = optarg; 2254ecc36642Schristos break; 22558dbcf02cSchristos default: 22568dbcf02cSchristos usage(); 22578dbcf02cSchristos return -1; 22588dbcf02cSchristos } 22598dbcf02cSchristos } 22608dbcf02cSchristos 22618dbcf02cSchristos interactive = (argc == optind) && (action_file == NULL); 22628dbcf02cSchristos 22638dbcf02cSchristos if (interactive) { 2264ecc36642Schristos printf("%s\n\n%s\n\n", hostapd_cli_version, cli_license); 22658dbcf02cSchristos } 22668dbcf02cSchristos 2267b8fa3219Schristos if (eloop_init()) 2268b8fa3219Schristos return -1; 2269b8fa3219Schristos 22708dbcf02cSchristos for (;;) { 22718dbcf02cSchristos if (ctrl_ifname == NULL) { 22728dbcf02cSchristos struct dirent *dent; 22738dbcf02cSchristos DIR *dir = opendir(ctrl_iface_dir); 22748dbcf02cSchristos if (dir) { 22758dbcf02cSchristos while ((dent = readdir(dir))) { 22768dbcf02cSchristos if (os_strcmp(dent->d_name, ".") == 0 22778dbcf02cSchristos || 22788dbcf02cSchristos os_strcmp(dent->d_name, "..") == 0) 22798dbcf02cSchristos continue; 22808dbcf02cSchristos printf("Selected interface '%s'\n", 22818dbcf02cSchristos dent->d_name); 22828dbcf02cSchristos ctrl_ifname = os_strdup(dent->d_name); 22838dbcf02cSchristos break; 22848dbcf02cSchristos } 22858dbcf02cSchristos closedir(dir); 22868dbcf02cSchristos } 22878dbcf02cSchristos } 2288be6b3c4dSchristos hostapd_cli_reconnect(ctrl_ifname); 22898dbcf02cSchristos if (ctrl_conn) { 22908dbcf02cSchristos if (warning_displayed) 22918dbcf02cSchristos printf("Connection established.\n"); 22928dbcf02cSchristos break; 22938dbcf02cSchristos } 2294*45d3cc13Schristos if (!interactive && !reconnect) { 22958dbcf02cSchristos perror("Failed to connect to hostapd - " 22968dbcf02cSchristos "wpa_ctrl_open"); 22978dbcf02cSchristos return -1; 22988dbcf02cSchristos } 22998dbcf02cSchristos 23008dbcf02cSchristos if (!warning_displayed) { 23018dbcf02cSchristos printf("Could not connect to hostapd - re-trying\n"); 23028dbcf02cSchristos warning_displayed = 1; 23038dbcf02cSchristos } 23048dbcf02cSchristos os_sleep(1, 0); 23058dbcf02cSchristos continue; 23068dbcf02cSchristos } 23078dbcf02cSchristos 2308*45d3cc13Schristos eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL); 2309*45d3cc13Schristos 2310be6b3c4dSchristos if (action_file && !hostapd_cli_attached) 23118dbcf02cSchristos return -1; 2312d2b81c07Sroy if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue()) 23138dbcf02cSchristos return -1; 2314*45d3cc13Schristos if (reconnect && action_file && ctrl_ifname) { 2315*45d3cc13Schristos while (!hostapd_cli_quit) { 2316*45d3cc13Schristos if (ctrl_conn) 2317*45d3cc13Schristos hostapd_cli_action(ctrl_conn); 2318*45d3cc13Schristos os_sleep(1, 0); 2319*45d3cc13Schristos hostapd_cli_reconnect(ctrl_ifname); 2320*45d3cc13Schristos } 2321*45d3cc13Schristos } else if (interactive) 23228dbcf02cSchristos hostapd_cli_interactive(); 23238dbcf02cSchristos else if (action_file) 23248dbcf02cSchristos hostapd_cli_action(ctrl_conn); 23258dbcf02cSchristos else 23268dbcf02cSchristos wpa_request(ctrl_conn, argc - optind, &argv[optind]); 23278dbcf02cSchristos 2328ecc36642Schristos unregister_event_handler(ctrl_conn); 23298dbcf02cSchristos os_free(ctrl_ifname); 2330b8fa3219Schristos eloop_destroy(); 23318dbcf02cSchristos hostapd_cli_cleanup(); 23328dbcf02cSchristos return 0; 23338dbcf02cSchristos } 2334ecc36642Schristos 2335ecc36642Schristos #else /* CONFIG_NO_CTRL_IFACE */ 2336ecc36642Schristos 2337ecc36642Schristos int main(int argc, char *argv[]) 2338ecc36642Schristos { 2339ecc36642Schristos return -1; 2340ecc36642Schristos } 2341ecc36642Schristos 2342ecc36642Schristos #endif /* CONFIG_NO_CTRL_IFACE */ 2343