Home | History | Annotate | Download | only in hostapd
      1 /*
      2  * hostapd - command line interface for hostapd daemon
      3  * Copyright (c) 2004-2017, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This software may be distributed under the terms of the BSD license.
      6  * See README for more details.
      7  */
      8 
      9 #include "includes.h"
     10 #include <dirent.h>
     11 
     12 #include "common/wpa_ctrl.h"
     13 #include "common/ieee802_11_defs.h"
     14 #include "utils/common.h"
     15 #include "utils/eloop.h"
     16 #include "utils/edit.h"
     17 #include "common/version.h"
     18 #include "common/cli.h"
     19 
     20 #ifndef CONFIG_NO_CTRL_IFACE
     21 
     22 static const char *const hostapd_cli_version =
     23 "hostapd_cli v" VERSION_STR "\n"
     24 "Copyright (c) 2004-2017, Jouni Malinen <j (at) w1.fi> and contributors";
     25 
     26 static struct wpa_ctrl *ctrl_conn;
     27 static int hostapd_cli_quit = 0;
     28 static int hostapd_cli_attached = 0;
     29 
     30 #ifndef CONFIG_CTRL_IFACE_DIR
     31 #define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd"
     32 #endif /* CONFIG_CTRL_IFACE_DIR */
     33 static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
     34 static const char *client_socket_dir = NULL;
     35 
     36 static char *ctrl_ifname = NULL;
     37 static const char *pid_file = NULL;
     38 static const char *action_file = NULL;
     39 static int ping_interval = 5;
     40 static int interactive = 0;
     41 static int event_handler_registered = 0;
     42 
     43 static DEFINE_DL_LIST(stations); /* struct cli_txt_entry */
     44 
     45 static void print_help(FILE *stream, const char *cmd);
     46 static char ** list_cmd_list(void);
     47 static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx);
     48 static void update_stations(struct wpa_ctrl *ctrl);
     49 static void cli_event(const char *str);
     50 
     51 
     52 static void usage(void)
     53 {
     54 	fprintf(stderr, "%s\n", hostapd_cli_version);
     55 	fprintf(stderr,
     56 		"\n"
     57 		"usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
     58 		"[-a<path>] \\\n"
     59 		"                   [-P<pid file>] [-G<ping interval>] [command..]\n"
     60 		"\n"
     61 		"Options:\n"
     62 		"   -h           help (show this usage text)\n"
     63 		"   -v           shown version information\n"
     64 		"   -p<path>     path to find control sockets (default: "
     65 		"/var/run/hostapd)\n"
     66 		"   -s<dir_path> dir path to open client sockets (default: "
     67 		CONFIG_CTRL_IFACE_DIR ")\n"
     68 		"   -a<file>     run in daemon mode executing the action file "
     69 		"based on events\n"
     70 		"                from hostapd\n"
     71 		"   -B           run a daemon in the background\n"
     72 		"   -i<ifname>   Interface to listen on (default: first "
     73 		"interface found in the\n"
     74 		"                socket path)\n\n");
     75 	print_help(stderr, NULL);
     76 }
     77 
     78 
     79 static void register_event_handler(struct wpa_ctrl *ctrl)
     80 {
     81 	if (!ctrl_conn)
     82 		return;
     83 	if (interactive) {
     84 		event_handler_registered =
     85 			!eloop_register_read_sock(wpa_ctrl_get_fd(ctrl),
     86 						  hostapd_cli_receive,
     87 						  NULL, NULL);
     88 	}
     89 }
     90 
     91 
     92 static void unregister_event_handler(struct wpa_ctrl *ctrl)
     93 {
     94 	if (!ctrl_conn)
     95 		return;
     96 	if (interactive && event_handler_registered) {
     97 		eloop_unregister_read_sock(wpa_ctrl_get_fd(ctrl));
     98 		event_handler_registered = 0;
     99 	}
    100 }
    101 
    102 
    103 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
    104 {
    105 #ifndef CONFIG_CTRL_IFACE_UDP
    106 	char *cfile;
    107 	int flen;
    108 #endif /* !CONFIG_CTRL_IFACE_UDP */
    109 
    110 	if (ifname == NULL)
    111 		return NULL;
    112 
    113 #ifdef CONFIG_CTRL_IFACE_UDP
    114 	ctrl_conn = wpa_ctrl_open(ifname);
    115 	return ctrl_conn;
    116 #else /* CONFIG_CTRL_IFACE_UDP */
    117 	flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
    118 	cfile = malloc(flen);
    119 	if (cfile == NULL)
    120 		return NULL;
    121 	snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
    122 
    123 	if (client_socket_dir && client_socket_dir[0] &&
    124 	    access(client_socket_dir, F_OK) < 0) {
    125 		perror(client_socket_dir);
    126 		free(cfile);
    127 		return NULL;
    128 	}
    129 
    130 	ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir);
    131 	free(cfile);
    132 	return ctrl_conn;
    133 #endif /* CONFIG_CTRL_IFACE_UDP */
    134 }
    135 
    136 
    137 static void hostapd_cli_close_connection(void)
    138 {
    139 	if (ctrl_conn == NULL)
    140 		return;
    141 
    142 	unregister_event_handler(ctrl_conn);
    143 	if (hostapd_cli_attached) {
    144 		wpa_ctrl_detach(ctrl_conn);
    145 		hostapd_cli_attached = 0;
    146 	}
    147 	wpa_ctrl_close(ctrl_conn);
    148 	ctrl_conn = NULL;
    149 }
    150 
    151 
    152 static int hostapd_cli_reconnect(const char *ifname)
    153 {
    154 	char *next_ctrl_ifname;
    155 
    156 	hostapd_cli_close_connection();
    157 
    158 	if (!ifname)
    159 		return -1;
    160 
    161 	next_ctrl_ifname = os_strdup(ifname);
    162 	os_free(ctrl_ifname);
    163 	ctrl_ifname = next_ctrl_ifname;
    164 	if (!ctrl_ifname)
    165 		return -1;
    166 
    167 	ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
    168 	if (!ctrl_conn)
    169 		return -1;
    170 	if (!interactive && !action_file)
    171 		return 0;
    172 	if (wpa_ctrl_attach(ctrl_conn) == 0) {
    173 		hostapd_cli_attached = 1;
    174 		register_event_handler(ctrl_conn);
    175 		update_stations(ctrl_conn);
    176 	} else {
    177 		printf("Warning: Failed to attach to hostapd.\n");
    178 	}
    179 	return 0;
    180 }
    181 
    182 
    183 static void hostapd_cli_msg_cb(char *msg, size_t len)
    184 {
    185 	cli_event(msg);
    186 	printf("%s\n", msg);
    187 }
    188 
    189 
    190 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd, int print)
    191 {
    192 	char buf[4096];
    193 	size_t len;
    194 	int ret;
    195 
    196 	if (ctrl_conn == NULL) {
    197 		printf("Not connected to hostapd - command dropped.\n");
    198 		return -1;
    199 	}
    200 	len = sizeof(buf) - 1;
    201 	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
    202 			       hostapd_cli_msg_cb);
    203 	if (ret == -2) {
    204 		printf("'%s' command timed out.\n", cmd);
    205 		return -2;
    206 	} else if (ret < 0) {
    207 		printf("'%s' command failed.\n", cmd);
    208 		return -1;
    209 	}
    210 	if (print) {
    211 		buf[len] = '\0';
    212 		printf("%s", buf);
    213 	}
    214 	return 0;
    215 }
    216 
    217 
    218 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd)
    219 {
    220 	return _wpa_ctrl_command(ctrl, cmd, 1);
    221 }
    222 
    223 
    224 static int hostapd_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd,
    225 			   int min_args, int argc, char *argv[])
    226 {
    227 	char buf[4096];
    228 
    229 	if (argc < min_args) {
    230 		printf("Invalid %s command - at least %d argument%s required.\n",
    231 		       cmd, min_args, min_args > 1 ? "s are" : " is");
    232 		return -1;
    233 	}
    234 	if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0)
    235 		return -1;
    236 	return wpa_ctrl_command(ctrl, buf);
    237 }
    238 
    239 
    240 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
    241 {
    242 	return wpa_ctrl_command(ctrl, "PING");
    243 }
    244 
    245 
    246 static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
    247 {
    248 	return wpa_ctrl_command(ctrl, "RELOG");
    249 }
    250 
    251 
    252 static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
    253 {
    254 	if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
    255 		return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
    256 	return wpa_ctrl_command(ctrl, "STATUS");
    257 }
    258 
    259 
    260 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
    261 {
    262 	if (argc > 0) {
    263 		char buf[100];
    264 		os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]);
    265 		return wpa_ctrl_command(ctrl, buf);
    266 	}
    267 	return wpa_ctrl_command(ctrl, "MIB");
    268 }
    269 
    270 
    271 static int hostapd_cli_exec(const char *program, const char *arg1,
    272 			    const char *arg2)
    273 {
    274 	char *arg;
    275 	size_t len;
    276 	int res;
    277 
    278 	len = os_strlen(arg1) + os_strlen(arg2) + 2;
    279 	arg = os_malloc(len);
    280 	if (arg == NULL)
    281 		return -1;
    282 	os_snprintf(arg, len, "%s %s", arg1, arg2);
    283 	res = os_exec(program, arg, 1);
    284 	os_free(arg);
    285 
    286 	return res;
    287 }
    288 
    289 
    290 static void hostapd_cli_action_process(char *msg, size_t len)
    291 {
    292 	const char *pos;
    293 
    294 	pos = msg;
    295 	if (*pos == '<') {
    296 		pos = os_strchr(pos, '>');
    297 		if (pos)
    298 			pos++;
    299 		else
    300 			pos = msg;
    301 	}
    302 
    303 	hostapd_cli_exec(action_file, ctrl_ifname, pos);
    304 }
    305 
    306 
    307 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
    308 {
    309 	char buf[64];
    310 	if (argc < 1) {
    311 		printf("Invalid 'sta' command - at least one argument, STA "
    312 		       "address, is required.\n");
    313 		return -1;
    314 	}
    315 	if (argc > 1)
    316 		snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]);
    317 	else
    318 		snprintf(buf, sizeof(buf), "STA %s", argv[0]);
    319 	return wpa_ctrl_command(ctrl, buf);
    320 }
    321 
    322 
    323 static char ** hostapd_complete_stations(const char *str, int pos)
    324 {
    325 	int arg = get_cmd_arg_num(str, pos);
    326 	char **res = NULL;
    327 
    328 	switch (arg) {
    329 	case 1:
    330 		res = cli_txt_list_array(&stations);
    331 		break;
    332 	}
    333 
    334 	return res;
    335 }
    336 
    337 
    338 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
    339 				   char *argv[])
    340 {
    341 	char buf[64];
    342 	if (argc != 1) {
    343 		printf("Invalid 'new_sta' command - exactly one argument, STA "
    344 		       "address, is required.\n");
    345 		return -1;
    346 	}
    347 	snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
    348 	return wpa_ctrl_command(ctrl, buf);
    349 }
    350 
    351 
    352 static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
    353 					  char *argv[])
    354 {
    355 	char buf[64];
    356 	if (argc < 1) {
    357 		printf("Invalid 'deauthenticate' command - exactly one "
    358 		       "argument, STA address, is required.\n");
    359 		return -1;
    360 	}
    361 	if (argc > 1)
    362 		os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
    363 			    argv[0], argv[1]);
    364 	else
    365 		os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
    366 	return wpa_ctrl_command(ctrl, buf);
    367 }
    368 
    369 
    370 static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
    371 					char *argv[])
    372 {
    373 	char buf[64];
    374 	if (argc < 1) {
    375 		printf("Invalid 'disassociate' command - exactly one "
    376 		       "argument, STA address, is required.\n");
    377 		return -1;
    378 	}
    379 	if (argc > 1)
    380 		os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
    381 			    argv[0], argv[1]);
    382 	else
    383 		os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
    384 	return wpa_ctrl_command(ctrl, buf);
    385 }
    386 
    387 
    388 #ifdef CONFIG_TAXONOMY
    389 static int hostapd_cli_cmd_signature(struct wpa_ctrl *ctrl, int argc,
    390 				     char *argv[])
    391 {
    392 	char buf[64];
    393 
    394 	if (argc != 1) {
    395 		printf("Invalid 'signature' command - exactly one argument, STA address, is required.\n");
    396 		return -1;
    397 	}
    398 	os_snprintf(buf, sizeof(buf), "SIGNATURE %s", argv[0]);
    399 	return wpa_ctrl_command(ctrl, buf);
    400 }
    401 #endif /* CONFIG_TAXONOMY */
    402 
    403 
    404 #ifdef CONFIG_IEEE80211W
    405 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
    406 				    char *argv[])
    407 {
    408 	char buf[64];
    409 	if (argc != 1) {
    410 		printf("Invalid 'sa_query' command - exactly one argument, "
    411 		       "STA address, is required.\n");
    412 		return -1;
    413 	}
    414 	snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
    415 	return wpa_ctrl_command(ctrl, buf);
    416 }
    417 #endif /* CONFIG_IEEE80211W */
    418 
    419 
    420 #ifdef CONFIG_WPS
    421 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
    422 				   char *argv[])
    423 {
    424 	char buf[256];
    425 	if (argc < 2) {
    426 		printf("Invalid 'wps_pin' command - at least two arguments, "
    427 		       "UUID and PIN, are required.\n");
    428 		return -1;
    429 	}
    430 	if (argc > 3)
    431 		snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
    432 			 argv[0], argv[1], argv[2], argv[3]);
    433 	else if (argc > 2)
    434 		snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
    435 			 argv[0], argv[1], argv[2]);
    436 	else
    437 		snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
    438 	return wpa_ctrl_command(ctrl, buf);
    439 }
    440 
    441 
    442 static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
    443 					 char *argv[])
    444 {
    445 	char cmd[256];
    446 	int res;
    447 
    448 	if (argc != 1 && argc != 2) {
    449 		printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
    450 		       "- PIN to be verified\n");
    451 		return -1;
    452 	}
    453 
    454 	if (argc == 2)
    455 		res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
    456 				  argv[0], argv[1]);
    457 	else
    458 		res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
    459 				  argv[0]);
    460 	if (os_snprintf_error(sizeof(cmd), res)) {
    461 		printf("Too long WPS_CHECK_PIN command.\n");
    462 		return -1;
    463 	}
    464 	return wpa_ctrl_command(ctrl, cmd);
    465 }
    466 
    467 
    468 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
    469 				   char *argv[])
    470 {
    471 	return wpa_ctrl_command(ctrl, "WPS_PBC");
    472 }
    473 
    474 
    475 static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
    476 				      char *argv[])
    477 {
    478 	return wpa_ctrl_command(ctrl, "WPS_CANCEL");
    479 }
    480 
    481 
    482 #ifdef CONFIG_WPS_NFC
    483 static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
    484 					    char *argv[])
    485 {
    486 	int ret;
    487 	char *buf;
    488 	size_t buflen;
    489 
    490 	if (argc != 1) {
    491 		printf("Invalid 'wps_nfc_tag_read' command - one argument "
    492 		       "is required.\n");
    493 		return -1;
    494 	}
    495 
    496 	buflen = 18 + os_strlen(argv[0]);
    497 	buf = os_malloc(buflen);
    498 	if (buf == NULL)
    499 		return -1;
    500 	os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
    501 
    502 	ret = wpa_ctrl_command(ctrl, buf);
    503 	os_free(buf);
    504 
    505 	return ret;
    506 }
    507 
    508 
    509 static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
    510 						int argc, char *argv[])
    511 {
    512 	char cmd[64];
    513 	int res;
    514 
    515 	if (argc != 1) {
    516 		printf("Invalid 'wps_nfc_config_token' command - one argument "
    517 		       "is required.\n");
    518 		return -1;
    519 	}
    520 
    521 	res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
    522 			  argv[0]);
    523 	if (os_snprintf_error(sizeof(cmd), res)) {
    524 		printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
    525 		return -1;
    526 	}
    527 	return wpa_ctrl_command(ctrl, cmd);
    528 }
    529 
    530 
    531 static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
    532 					 int argc, char *argv[])
    533 {
    534 	char cmd[64];
    535 	int res;
    536 
    537 	if (argc != 1) {
    538 		printf("Invalid 'wps_nfc_token' command - one argument is "
    539 		       "required.\n");
    540 		return -1;
    541 	}
    542 
    543 	res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
    544 	if (os_snprintf_error(sizeof(cmd), res)) {
    545 		printf("Too long WPS_NFC_TOKEN command.\n");
    546 		return -1;
    547 	}
    548 	return wpa_ctrl_command(ctrl, cmd);
    549 }
    550 
    551 
    552 static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
    553 						int argc, char *argv[])
    554 {
    555 	char cmd[64];
    556 	int res;
    557 
    558 	if (argc != 2) {
    559 		printf("Invalid 'nfc_get_handover_sel' command - two arguments "
    560 		       "are required.\n");
    561 		return -1;
    562 	}
    563 
    564 	res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
    565 			  argv[0], argv[1]);
    566 	if (os_snprintf_error(sizeof(cmd), res)) {
    567 		printf("Too long NFC_GET_HANDOVER_SEL command.\n");
    568 		return -1;
    569 	}
    570 	return wpa_ctrl_command(ctrl, cmd);
    571 }
    572 
    573 #endif /* CONFIG_WPS_NFC */
    574 
    575 
    576 static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
    577 				      char *argv[])
    578 {
    579 	char buf[64];
    580 	if (argc < 1) {
    581 		printf("Invalid 'wps_ap_pin' command - at least one argument "
    582 		       "is required.\n");
    583 		return -1;
    584 	}
    585 	if (argc > 2)
    586 		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
    587 			 argv[0], argv[1], argv[2]);
    588 	else if (argc > 1)
    589 		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
    590 			 argv[0], argv[1]);
    591 	else
    592 		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
    593 	return wpa_ctrl_command(ctrl, buf);
    594 }
    595 
    596 
    597 static int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc,
    598 					  char *argv[])
    599 {
    600 	return wpa_ctrl_command(ctrl, "WPS_GET_STATUS");
    601 }
    602 
    603 
    604 static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
    605 				      char *argv[])
    606 {
    607 	char buf[256];
    608 	char ssid_hex[2 * SSID_MAX_LEN + 1];
    609 	char key_hex[2 * 64 + 1];
    610 	int i;
    611 
    612 	if (argc < 1) {
    613 		printf("Invalid 'wps_config' command - at least two arguments "
    614 		       "are required.\n");
    615 		return -1;
    616 	}
    617 
    618 	ssid_hex[0] = '\0';
    619 	for (i = 0; i < SSID_MAX_LEN; i++) {
    620 		if (argv[0][i] == '\0')
    621 			break;
    622 		os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
    623 	}
    624 
    625 	key_hex[0] = '\0';
    626 	if (argc > 3) {
    627 		for (i = 0; i < 64; i++) {
    628 			if (argv[3][i] == '\0')
    629 				break;
    630 			os_snprintf(&key_hex[i * 2], 3, "%02x",
    631 				    argv[3][i]);
    632 		}
    633 	}
    634 
    635 	if (argc > 3)
    636 		snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
    637 			 ssid_hex, argv[1], argv[2], key_hex);
    638 	else if (argc > 2)
    639 		snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
    640 			 ssid_hex, argv[1], argv[2]);
    641 	else
    642 		snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
    643 			 ssid_hex, argv[1]);
    644 	return wpa_ctrl_command(ctrl, buf);
    645 }
    646 #endif /* CONFIG_WPS */
    647 
    648 
    649 static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
    650 					     char *argv[])
    651 {
    652 	char buf[300];
    653 	int res;
    654 
    655 	if (argc < 2) {
    656 		printf("Invalid 'disassoc_imminent' command - two arguments "
    657 		       "(STA addr and Disassociation Timer) are needed\n");
    658 		return -1;
    659 	}
    660 
    661 	res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
    662 			  argv[0], argv[1]);
    663 	if (os_snprintf_error(sizeof(buf), res))
    664 		return -1;
    665 	return wpa_ctrl_command(ctrl, buf);
    666 }
    667 
    668 
    669 static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
    670 					char *argv[])
    671 {
    672 	char buf[300];
    673 	int res;
    674 
    675 	if (argc < 3) {
    676 		printf("Invalid 'ess_disassoc' command - three arguments (STA "
    677 		       "addr, disassoc timer, and URL) are needed\n");
    678 		return -1;
    679 	}
    680 
    681 	res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
    682 			  argv[0], argv[1], argv[2]);
    683 	if (os_snprintf_error(sizeof(buf), res))
    684 		return -1;
    685 	return wpa_ctrl_command(ctrl, buf);
    686 }
    687 
    688 
    689 static int hostapd_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc,
    690 				      char *argv[])
    691 {
    692 	char buf[2000], *tmp;
    693 	int res, i, total;
    694 
    695 	if (argc < 1) {
    696 		printf("Invalid 'bss_tm_req' command - at least one argument (STA addr) is needed\n");
    697 		return -1;
    698 	}
    699 
    700 	res = os_snprintf(buf, sizeof(buf), "BSS_TM_REQ %s", argv[0]);
    701 	if (os_snprintf_error(sizeof(buf), res))
    702 		return -1;
    703 
    704 	total = res;
    705 	for (i = 1; i < argc; i++) {
    706 		tmp = &buf[total];
    707 		res = os_snprintf(tmp, sizeof(buf) - total, " %s", argv[i]);
    708 		if (os_snprintf_error(sizeof(buf) - total, res))
    709 			return -1;
    710 		total += res;
    711 	}
    712 	return wpa_ctrl_command(ctrl, buf);
    713 }
    714 
    715 
    716 static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
    717 				      char *argv[])
    718 {
    719 	return wpa_ctrl_command(ctrl, "GET_CONFIG");
    720 }
    721 
    722 
    723 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, const char *cmd,
    724 				char *addr, size_t addr_len, int print)
    725 {
    726 	char buf[4096], *pos;
    727 	size_t len;
    728 	int ret;
    729 
    730 	if (ctrl_conn == NULL) {
    731 		printf("Not connected to hostapd - command dropped.\n");
    732 		return -1;
    733 	}
    734 	len = sizeof(buf) - 1;
    735 	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
    736 			       hostapd_cli_msg_cb);
    737 	if (ret == -2) {
    738 		printf("'%s' command timed out.\n", cmd);
    739 		return -2;
    740 	} else if (ret < 0) {
    741 		printf("'%s' command failed.\n", cmd);
    742 		return -1;
    743 	}
    744 
    745 	buf[len] = '\0';
    746 	if (memcmp(buf, "FAIL", 4) == 0)
    747 		return -1;
    748 	if (print)
    749 		printf("%s", buf);
    750 
    751 	pos = buf;
    752 	while (*pos != '\0' && *pos != '\n')
    753 		pos++;
    754 	*pos = '\0';
    755 	os_strlcpy(addr, buf, addr_len);
    756 	return 0;
    757 }
    758 
    759 
    760 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
    761 				   char *argv[])
    762 {
    763 	char addr[32], cmd[64];
    764 
    765 	if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 1))
    766 		return 0;
    767 	do {
    768 		snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
    769 	} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 1) == 0);
    770 
    771 	return -1;
    772 }
    773 
    774 
    775 static int hostapd_cli_cmd_list_sta(struct wpa_ctrl *ctrl, int argc,
    776 				    char *argv[])
    777 {
    778 	char addr[32], cmd[64];
    779 
    780 	if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0))
    781 		return 0;
    782 	do {
    783 		if (os_strcmp(addr, "") != 0)
    784 			printf("%s\n", addr);
    785 		os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
    786 	} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0);
    787 
    788 	return 0;
    789 }
    790 
    791 
    792 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
    793 {
    794 	print_help(stdout, argc > 0 ? argv[0] : NULL);
    795 	return 0;
    796 }
    797 
    798 
    799 static char ** hostapd_cli_complete_help(const char *str, int pos)
    800 {
    801 	int arg = get_cmd_arg_num(str, pos);
    802 	char **res = NULL;
    803 
    804 	switch (arg) {
    805 	case 1:
    806 		res = list_cmd_list();
    807 		break;
    808 	}
    809 
    810 	return res;
    811 }
    812 
    813 
    814 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
    815 				   char *argv[])
    816 {
    817 	printf("%s\n\n%s\n", hostapd_cli_version, cli_full_license);
    818 	return 0;
    819 }
    820 
    821 
    822 static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl,
    823 					   int argc, char *argv[])
    824 {
    825 	char buf[200];
    826 	int res;
    827 
    828 	if (argc != 1) {
    829 		printf("Invalid 'set_qos_map_set' command - "
    830 		       "one argument (comma delimited QoS map set) "
    831 		       "is needed\n");
    832 		return -1;
    833 	}
    834 
    835 	res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
    836 	if (os_snprintf_error(sizeof(buf), res))
    837 		return -1;
    838 	return wpa_ctrl_command(ctrl, buf);
    839 }
    840 
    841 
    842 static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
    843 					     int argc, char *argv[])
    844 {
    845 	char buf[50];
    846 	int res;
    847 
    848 	if (argc != 1) {
    849 		printf("Invalid 'send_qos_map_conf' command - "
    850 		       "one argument (STA addr) is needed\n");
    851 		return -1;
    852 	}
    853 
    854 	res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
    855 	if (os_snprintf_error(sizeof(buf), res))
    856 		return -1;
    857 	return wpa_ctrl_command(ctrl, buf);
    858 }
    859 
    860 
    861 static int hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc,
    862 					  char *argv[])
    863 {
    864 	char buf[300];
    865 	int res;
    866 
    867 	if (argc < 2) {
    868 		printf("Invalid 'hs20_wnm_notif' command - two arguments (STA "
    869 		       "addr and URL) are needed\n");
    870 		return -1;
    871 	}
    872 
    873 	res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s",
    874 			  argv[0], argv[1]);
    875 	if (os_snprintf_error(sizeof(buf), res))
    876 		return -1;
    877 	return wpa_ctrl_command(ctrl, buf);
    878 }
    879 
    880 
    881 static int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc,
    882 					   char *argv[])
    883 {
    884 	char buf[300];
    885 	int res;
    886 
    887 	if (argc < 3) {
    888 		printf("Invalid 'hs20_deauth_req' command - at least three arguments (STA addr, Code, Re-auth Delay) are needed\n");
    889 		return -1;
    890 	}
    891 
    892 	if (argc > 3)
    893 		res = os_snprintf(buf, sizeof(buf),
    894 				  "HS20_DEAUTH_REQ %s %s %s %s",
    895 				  argv[0], argv[1], argv[2], argv[3]);
    896 	else
    897 		res = os_snprintf(buf, sizeof(buf),
    898 				  "HS20_DEAUTH_REQ %s %s %s",
    899 				  argv[0], argv[1], argv[2]);
    900 	if (os_snprintf_error(sizeof(buf), res))
    901 		return -1;
    902 	return wpa_ctrl_command(ctrl, buf);
    903 }
    904 
    905 
    906 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
    907 {
    908 	hostapd_cli_quit = 1;
    909 	if (interactive)
    910 		eloop_terminate();
    911 	return 0;
    912 }
    913 
    914 
    915 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
    916 {
    917 	char cmd[256];
    918 	if (argc != 1) {
    919 		printf("Invalid LEVEL command: needs one argument (debug "
    920 		       "level)\n");
    921 		return 0;
    922 	}
    923 	snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
    924 	return wpa_ctrl_command(ctrl, cmd);
    925 }
    926 
    927 
    928 static void update_stations(struct wpa_ctrl *ctrl)
    929 {
    930 	char addr[32], cmd[64];
    931 
    932 	if (!ctrl || !interactive)
    933 		return;
    934 
    935 	cli_txt_list_flush(&stations);
    936 
    937 	if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0))
    938 		return;
    939 	do {
    940 		if (os_strcmp(addr, "") != 0)
    941 			cli_txt_list_add(&stations, addr);
    942 		os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
    943 	} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0);
    944 }
    945 
    946 
    947 static void hostapd_cli_get_interfaces(struct wpa_ctrl *ctrl,
    948 				       struct dl_list *interfaces)
    949 {
    950 	struct dirent *dent;
    951 	DIR *dir;
    952 
    953 	if (!ctrl || !interfaces)
    954 		return;
    955 	dir = opendir(ctrl_iface_dir);
    956 	if (dir == NULL)
    957 		return;
    958 
    959 	while ((dent = readdir(dir))) {
    960 		if (strcmp(dent->d_name, ".") == 0 ||
    961 		    strcmp(dent->d_name, "..") == 0)
    962 			continue;
    963 		cli_txt_list_add(interfaces, dent->d_name);
    964 	}
    965 	closedir(dir);
    966 }
    967 
    968 
    969 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
    970 {
    971 	struct dirent *dent;
    972 	DIR *dir;
    973 
    974 	dir = opendir(ctrl_iface_dir);
    975 	if (dir == NULL) {
    976 		printf("Control interface directory '%s' could not be "
    977 		       "openned.\n", ctrl_iface_dir);
    978 		return;
    979 	}
    980 
    981 	printf("Available interfaces:\n");
    982 	while ((dent = readdir(dir))) {
    983 		if (strcmp(dent->d_name, ".") == 0 ||
    984 		    strcmp(dent->d_name, "..") == 0)
    985 			continue;
    986 		printf("%s\n", dent->d_name);
    987 	}
    988 	closedir(dir);
    989 }
    990 
    991 
    992 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
    993 				     char *argv[])
    994 {
    995 	if (argc < 1) {
    996 		hostapd_cli_list_interfaces(ctrl);
    997 		return 0;
    998 	}
    999 	if (hostapd_cli_reconnect(argv[0]) != 0) {
   1000 		printf("Could not connect to interface '%s' - re-trying\n",
   1001 			ctrl_ifname);
   1002 	}
   1003 	return 0;
   1004 }
   1005 
   1006 
   1007 static char ** hostapd_complete_interface(const char *str, int pos)
   1008 {
   1009 	int arg = get_cmd_arg_num(str, pos);
   1010 	char **res = NULL;
   1011 	DEFINE_DL_LIST(interfaces);
   1012 
   1013 	switch (arg) {
   1014 	case 1:
   1015 		hostapd_cli_get_interfaces(ctrl_conn, &interfaces);
   1016 		res = cli_txt_list_array(&interfaces);
   1017 		cli_txt_list_flush(&interfaces);
   1018 		break;
   1019 	}
   1020 
   1021 	return res;
   1022 }
   1023 
   1024 
   1025 static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
   1026 {
   1027 	char cmd[2048];
   1028 	int res;
   1029 
   1030 	if (argc != 2) {
   1031 		printf("Invalid SET command: needs two arguments (variable "
   1032 		       "name and value)\n");
   1033 		return -1;
   1034 	}
   1035 
   1036 	res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
   1037 	if (os_snprintf_error(sizeof(cmd), res)) {
   1038 		printf("Too long SET command.\n");
   1039 		return -1;
   1040 	}
   1041 	return wpa_ctrl_command(ctrl, cmd);
   1042 }
   1043 
   1044 
   1045 static char ** hostapd_complete_set(const char *str, int pos)
   1046 {
   1047 	int arg = get_cmd_arg_num(str, pos);
   1048 	const char *fields[] = {
   1049 #ifdef CONFIG_WPS_TESTING
   1050 		"wps_version_number", "wps_testing_dummy_cred",
   1051 		"wps_corrupt_pkhash",
   1052 #endif /* CONFIG_WPS_TESTING */
   1053 #ifdef CONFIG_INTERWORKING
   1054 		"gas_frag_limit",
   1055 #endif /* CONFIG_INTERWORKING */
   1056 #ifdef CONFIG_TESTING_OPTIONS
   1057 		"ext_mgmt_frame_handling", "ext_eapol_frame_io",
   1058 #endif /* CONFIG_TESTING_OPTIONS */
   1059 #ifdef CONFIG_MBO
   1060 		"mbo_assoc_disallow",
   1061 #endif /* CONFIG_MBO */
   1062 		"deny_mac_file", "accept_mac_file",
   1063 	};
   1064 	int i, num_fields = ARRAY_SIZE(fields);
   1065 
   1066 	if (arg == 1) {
   1067 		char **res;
   1068 
   1069 		res = os_calloc(num_fields + 1, sizeof(char *));
   1070 		if (!res)
   1071 			return NULL;
   1072 		for (i = 0; i < num_fields; i++) {
   1073 			res[i] = os_strdup(fields[i]);
   1074 			if (!res[i])
   1075 				return res;
   1076 		}
   1077 		return res;
   1078 	}
   1079 	return NULL;
   1080 }
   1081 
   1082 
   1083 static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
   1084 {
   1085 	char cmd[256];
   1086 	int res;
   1087 
   1088 	if (argc != 1) {
   1089 		printf("Invalid GET command: needs one argument (variable "
   1090 		       "name)\n");
   1091 		return -1;
   1092 	}
   1093 
   1094 	res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
   1095 	if (os_snprintf_error(sizeof(cmd), res)) {
   1096 		printf("Too long GET command.\n");
   1097 		return -1;
   1098 	}
   1099 	return wpa_ctrl_command(ctrl, cmd);
   1100 }
   1101 
   1102 
   1103 static char ** hostapd_complete_get(const char *str, int pos)
   1104 {
   1105 	int arg = get_cmd_arg_num(str, pos);
   1106 	const char *fields[] = {
   1107 		"version", "tls_library",
   1108 	};
   1109 	int i, num_fields = ARRAY_SIZE(fields);
   1110 
   1111 	if (arg == 1) {
   1112 		char **res;
   1113 
   1114 		res = os_calloc(num_fields + 1, sizeof(char *));
   1115 		if (!res)
   1116 			return NULL;
   1117 		for (i = 0; i < num_fields; i++) {
   1118 			res[i] = os_strdup(fields[i]);
   1119 			if (!res[i])
   1120 				return res;
   1121 		}
   1122 		return res;
   1123 	}
   1124 	return NULL;
   1125 }
   1126 
   1127 
   1128 #ifdef CONFIG_FST
   1129 static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[])
   1130 {
   1131 	char cmd[256];
   1132 	int res;
   1133 	int i;
   1134 	int total;
   1135 
   1136 	if (argc <= 0) {
   1137 		printf("FST command: parameters are required.\n");
   1138 		return -1;
   1139 	}
   1140 
   1141 	total = os_snprintf(cmd, sizeof(cmd), "FST-MANAGER");
   1142 
   1143 	for (i = 0; i < argc; i++) {
   1144 		res = os_snprintf(cmd + total, sizeof(cmd) - total, " %s",
   1145 				  argv[i]);
   1146 		if (os_snprintf_error(sizeof(cmd) - total, res)) {
   1147 			printf("Too long fst command.\n");
   1148 			return -1;
   1149 		}
   1150 		total += res;
   1151 	}
   1152 	return wpa_ctrl_command(ctrl, cmd);
   1153 }
   1154 #endif /* CONFIG_FST */
   1155 
   1156 
   1157 static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
   1158 				       int argc, char *argv[])
   1159 {
   1160 	char cmd[256];
   1161 	int res;
   1162 	int i;
   1163 	char *tmp;
   1164 	int total;
   1165 
   1166 	if (argc < 2) {
   1167 		printf("Invalid chan_switch command: needs at least two "
   1168 		       "arguments (count and freq)\n"
   1169 		       "usage: <cs_count> <freq> [sec_channel_offset=] "
   1170 		       "[center_freq1=] [center_freq2=] [bandwidth=] "
   1171 		       "[blocktx] [ht|vht]\n");
   1172 		return -1;
   1173 	}
   1174 
   1175 	res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
   1176 			  argv[0], argv[1]);
   1177 	if (os_snprintf_error(sizeof(cmd), res)) {
   1178 		printf("Too long CHAN_SWITCH command.\n");
   1179 		return -1;
   1180 	}
   1181 
   1182 	total = res;
   1183 	for (i = 2; i < argc; i++) {
   1184 		tmp = cmd + total;
   1185 		res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
   1186 		if (os_snprintf_error(sizeof(cmd) - total, res)) {
   1187 			printf("Too long CHAN_SWITCH command.\n");
   1188 			return -1;
   1189 		}
   1190 		total += res;
   1191 	}
   1192 	return wpa_ctrl_command(ctrl, cmd);
   1193 }
   1194 
   1195 
   1196 static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc,
   1197 				      char *argv[])
   1198 {
   1199 	return wpa_ctrl_command(ctrl, "ENABLE");
   1200 }
   1201 
   1202 
   1203 static int hostapd_cli_cmd_reload(struct wpa_ctrl *ctrl, int argc,
   1204 				      char *argv[])
   1205 {
   1206 	return wpa_ctrl_command(ctrl, "RELOAD");
   1207 }
   1208 
   1209 
   1210 static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc,
   1211 				      char *argv[])
   1212 {
   1213 	return wpa_ctrl_command(ctrl, "DISABLE");
   1214 }
   1215 
   1216 
   1217 static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
   1218 {
   1219 	char cmd[256];
   1220 	int res;
   1221 
   1222 	if (argc < 2 || argc > 3) {
   1223 		printf("Invalid vendor command\n"
   1224 		       "usage: <vendor id> <command id> [<hex formatted command argument>]\n");
   1225 		return -1;
   1226 	}
   1227 
   1228 	res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
   1229 			  argc == 3 ? argv[2] : "");
   1230 	if (os_snprintf_error(sizeof(cmd), res)) {
   1231 		printf("Too long VENDOR command.\n");
   1232 		return -1;
   1233 	}
   1234 	return wpa_ctrl_command(ctrl, cmd);
   1235 }
   1236 
   1237 
   1238 static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc,
   1239 				     char *argv[])
   1240 {
   1241 	return wpa_ctrl_command(ctrl, "ERP_FLUSH");
   1242 }
   1243 
   1244 
   1245 static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc,
   1246 				     char *argv[])
   1247 {
   1248 	char cmd[256];
   1249 	int res;
   1250 
   1251 	res = os_snprintf(cmd, sizeof(cmd), "LOG_LEVEL%s%s%s%s",
   1252 			  argc >= 1 ? " " : "",
   1253 			  argc >= 1 ? argv[0] : "",
   1254 			  argc == 2 ? " " : "",
   1255 			  argc == 2 ? argv[1] : "");
   1256 	if (os_snprintf_error(sizeof(cmd), res)) {
   1257 		printf("Too long option\n");
   1258 		return -1;
   1259 	}
   1260 	return wpa_ctrl_command(ctrl, cmd);
   1261 }
   1262 
   1263 
   1264 static int hostapd_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
   1265 {
   1266 	if (argc == 0)
   1267 		return -1;
   1268 	return hostapd_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]);
   1269 }
   1270 
   1271 
   1272 static int hostapd_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
   1273 {
   1274 	return wpa_ctrl_command(ctrl, "PMKSA");
   1275 }
   1276 
   1277 
   1278 static int hostapd_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc,
   1279 				       char *argv[])
   1280 {
   1281 	return wpa_ctrl_command(ctrl, "PMKSA_FLUSH");
   1282 }
   1283 
   1284 
   1285 static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc,
   1286 					char *argv[])
   1287 {
   1288 	char cmd[2048];
   1289 	int res;
   1290 
   1291 	if (argc < 3 || argc > 6) {
   1292 		printf("Invalid set_neighbor command: needs 3-6 arguments\n");
   1293 		return -1;
   1294 	}
   1295 
   1296 	res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s %s",
   1297 			  argv[0], argv[1], argv[2], argc >= 4 ? argv[3] : "",
   1298 			  argc >= 5 ? argv[4] : "", argc == 6 ? argv[5] : "");
   1299 	if (os_snprintf_error(sizeof(cmd), res)) {
   1300 		printf("Too long SET_NEIGHBOR command.\n");
   1301 		return -1;
   1302 	}
   1303 	return wpa_ctrl_command(ctrl, cmd);
   1304 }
   1305 
   1306 
   1307 static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc,
   1308 					   char *argv[])
   1309 {
   1310 	char cmd[400];
   1311 	int res;
   1312 
   1313 	if (argc != 2) {
   1314 		printf("Invalid remove_neighbor command: needs 2 arguments\n");
   1315 		return -1;
   1316 	}
   1317 
   1318 	res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NEIGHBOR %s %s",
   1319 			  argv[0], argv[1]);
   1320 	if (os_snprintf_error(sizeof(cmd), res)) {
   1321 		printf("Too long REMOVE_NEIGHBOR command.\n");
   1322 		return -1;
   1323 	}
   1324 	return wpa_ctrl_command(ctrl, cmd);
   1325 }
   1326 
   1327 
   1328 static int hostapd_cli_cmd_req_lci(struct wpa_ctrl *ctrl, int argc,
   1329 				   char *argv[])
   1330 {
   1331 	char cmd[256];
   1332 	int res;
   1333 
   1334 	if (argc != 1) {
   1335 		printf("Invalid req_lci command - requires destination address\n");
   1336 		return -1;
   1337 	}
   1338 
   1339 	res = os_snprintf(cmd, sizeof(cmd), "REQ_LCI %s", argv[0]);
   1340 	if (os_snprintf_error(sizeof(cmd), res)) {
   1341 		printf("Too long REQ_LCI command.\n");
   1342 		return -1;
   1343 	}
   1344 	return wpa_ctrl_command(ctrl, cmd);
   1345 }
   1346 
   1347 
   1348 static int hostapd_cli_cmd_req_range(struct wpa_ctrl *ctrl, int argc,
   1349 				     char *argv[])
   1350 {
   1351 	if (argc < 4) {
   1352 		printf("Invalid req_range command: needs at least 4 arguments - dest address, randomization interval, min AP count, and 1 to 16 AP addresses\n");
   1353 		return -1;
   1354 	}
   1355 
   1356 	return hostapd_cli_cmd(ctrl, "REQ_RANGE", 4, argc, argv);
   1357 }
   1358 
   1359 
   1360 static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
   1361 					char *argv[])
   1362 {
   1363 	return wpa_ctrl_command(ctrl, "DRIVER_FLAGS");
   1364 }
   1365 
   1366 
   1367 #ifdef CONFIG_DPP
   1368 
   1369 static int hostapd_cli_cmd_dpp_qr_code(struct wpa_ctrl *ctrl, int argc,
   1370 				       char *argv[])
   1371 {
   1372 	return hostapd_cli_cmd(ctrl, "DPP_QR_CODE", 1, argc, argv);
   1373 }
   1374 
   1375 
   1376 static int hostapd_cli_cmd_dpp_bootstrap_gen(struct wpa_ctrl *ctrl, int argc,
   1377 					     char *argv[])
   1378 {
   1379 	return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_GEN", 1, argc, argv);
   1380 }
   1381 
   1382 
   1383 static int hostapd_cli_cmd_dpp_bootstrap_remove(struct wpa_ctrl *ctrl, int argc,
   1384 						char *argv[])
   1385 {
   1386 	return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_REMOVE", 1, argc, argv);
   1387 }
   1388 
   1389 
   1390 static int hostapd_cli_cmd_dpp_bootstrap_get_uri(struct wpa_ctrl *ctrl,
   1391 						 int argc, char *argv[])
   1392 {
   1393 	return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_GET_URI", 1, argc, argv);
   1394 }
   1395 
   1396 
   1397 static int hostapd_cli_cmd_dpp_bootstrap_info(struct wpa_ctrl *ctrl, int argc,
   1398 					      char *argv[])
   1399 {
   1400 	return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_INFO", 1, argc, argv);
   1401 }
   1402 
   1403 
   1404 static int hostapd_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc,
   1405 					 char *argv[])
   1406 {
   1407 	return hostapd_cli_cmd(ctrl, "DPP_AUTH_INIT", 1, argc, argv);
   1408 }
   1409 
   1410 
   1411 static int hostapd_cli_cmd_dpp_configurator_add(struct wpa_ctrl *ctrl, int argc,
   1412 						char *argv[])
   1413 {
   1414 	return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_ADD", 0, argc, argv);
   1415 }
   1416 
   1417 
   1418 static int hostapd_cli_cmd_dpp_configurator_remove(struct wpa_ctrl *ctrl,
   1419 						   int argc, char *argv[])
   1420 {
   1421 	return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_REMOVE", 1, argc, argv);
   1422 }
   1423 
   1424 
   1425 static int hostapd_cli_cmd_dpp_pkex_add(struct wpa_ctrl *ctrl, int argc,
   1426 					char *argv[])
   1427 {
   1428 	return hostapd_cli_cmd(ctrl, "DPP_PKEX_ADD", 1, argc, argv);
   1429 }
   1430 
   1431 
   1432 static int hostapd_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc,
   1433 					   char *argv[])
   1434 {
   1435 	return hostapd_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv);
   1436 }
   1437 
   1438 #endif /* CONFIG_DPP */
   1439 
   1440 
   1441 struct hostapd_cli_cmd {
   1442 	const char *cmd;
   1443 	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
   1444 	char ** (*completion)(const char *str, int pos);
   1445 	const char *usage;
   1446 };
   1447 
   1448 static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
   1449 	{ "ping", hostapd_cli_cmd_ping, NULL,
   1450 	  "= pings hostapd" },
   1451 	{ "mib", hostapd_cli_cmd_mib, NULL,
   1452 	  "= get MIB variables (dot1x, dot11, radius)" },
   1453 	{ "relog", hostapd_cli_cmd_relog, NULL,
   1454 	  "= reload/truncate debug log output file" },
   1455 	{ "status", hostapd_cli_cmd_status, NULL,
   1456 	  "= show interface status info" },
   1457 	{ "sta", hostapd_cli_cmd_sta, hostapd_complete_stations,
   1458 	  "<addr> = get MIB variables for one station" },
   1459 	{ "all_sta", hostapd_cli_cmd_all_sta, NULL,
   1460 	   "= get MIB variables for all stations" },
   1461 	{ "list_sta", hostapd_cli_cmd_list_sta, NULL,
   1462 	   "= list all stations" },
   1463 	{ "new_sta", hostapd_cli_cmd_new_sta, NULL,
   1464 	  "<addr> = add a new station" },
   1465 	{ "deauthenticate", hostapd_cli_cmd_deauthenticate,
   1466 	  hostapd_complete_stations,
   1467 	  "<addr> = deauthenticate a station" },
   1468 	{ "disassociate", hostapd_cli_cmd_disassociate,
   1469 	  hostapd_complete_stations,
   1470 	  "<addr> = disassociate a station" },
   1471 #ifdef CONFIG_TAXONOMY
   1472 	{ "signature", hostapd_cli_cmd_signature, hostapd_complete_stations,
   1473 	  "<addr> = get taxonomy signature for a station" },
   1474 #endif /* CONFIG_TAXONOMY */
   1475 #ifdef CONFIG_IEEE80211W
   1476 	{ "sa_query", hostapd_cli_cmd_sa_query, hostapd_complete_stations,
   1477 	  "<addr> = send SA Query to a station" },
   1478 #endif /* CONFIG_IEEE80211W */
   1479 #ifdef CONFIG_WPS
   1480 	{ "wps_pin", hostapd_cli_cmd_wps_pin, NULL,
   1481 	  "<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" },
   1482 	{ "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL,
   1483 	  "<PIN> = verify PIN checksum" },
   1484 	{ "wps_pbc", hostapd_cli_cmd_wps_pbc, NULL,
   1485 	  "= indicate button pushed to initiate PBC" },
   1486 	{ "wps_cancel", hostapd_cli_cmd_wps_cancel, NULL,
   1487 	  "= cancel the pending WPS operation" },
   1488 #ifdef CONFIG_WPS_NFC
   1489 	{ "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read, NULL,
   1490 	  "<hexdump> = report read NFC tag with WPS data" },
   1491 	{ "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token, NULL,
   1492 	  "<WPS/NDEF> = build NFC configuration token" },
   1493 	{ "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token, NULL,
   1494 	  "<WPS/NDEF/enable/disable> = manager NFC password token" },
   1495 	{ "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel, NULL,
   1496 	  NULL },
   1497 #endif /* CONFIG_WPS_NFC */
   1498 	{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin, NULL,
   1499 	  "<cmd> [params..] = enable/disable AP PIN" },
   1500 	{ "wps_config", hostapd_cli_cmd_wps_config, NULL,
   1501 	  "<SSID> <auth> <encr> <key> = configure AP" },
   1502 	{ "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL,
   1503 	  "= show current WPS status" },
   1504 #endif /* CONFIG_WPS */
   1505 	{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL,
   1506 	  "= send Disassociation Imminent notification" },
   1507 	{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL,
   1508 	  "= send ESS Dissassociation Imminent notification" },
   1509 	{ "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL,
   1510 	  "= send BSS Transition Management Request" },
   1511 	{ "get_config", hostapd_cli_cmd_get_config, NULL,
   1512 	  "= show current configuration" },
   1513 	{ "help", hostapd_cli_cmd_help, hostapd_cli_complete_help,
   1514 	  "= show this usage help" },
   1515 	{ "interface", hostapd_cli_cmd_interface, hostapd_complete_interface,
   1516 	  "[ifname] = show interfaces/select interface" },
   1517 #ifdef CONFIG_FST
   1518 	{ "fst", hostapd_cli_cmd_fst, NULL,
   1519 	  "<params...> = send FST-MANAGER control interface command" },
   1520 #endif /* CONFIG_FST */
   1521 	{ "raw", hostapd_cli_cmd_raw, NULL,
   1522 	  "<params..> = send unprocessed command" },
   1523 	{ "level", hostapd_cli_cmd_level, NULL,
   1524 	  "<debug level> = change debug level" },
   1525 	{ "license", hostapd_cli_cmd_license, NULL,
   1526 	  "= show full hostapd_cli license" },
   1527 	{ "quit", hostapd_cli_cmd_quit, NULL,
   1528 	  "= exit hostapd_cli" },
   1529 	{ "set", hostapd_cli_cmd_set, hostapd_complete_set,
   1530 	  "<name> <value> = set runtime variables" },
   1531 	{ "get", hostapd_cli_cmd_get, hostapd_complete_get,
   1532 	  "<name> = get runtime info" },
   1533 	{ "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL,
   1534 	  "<arg,arg,...> = set QoS Map set element" },
   1535 	{ "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf,
   1536 	  hostapd_complete_stations,
   1537 	  "<addr> = send QoS Map Configure frame" },
   1538 	{ "chan_switch", hostapd_cli_cmd_chan_switch, NULL,
   1539 	  "<cs_count> <freq> [sec_channel_offset=] [center_freq1=]\n"
   1540 	  "  [center_freq2=] [bandwidth=] [blocktx] [ht|vht]\n"
   1541 	  "  = initiate channel switch announcement" },
   1542 	{ "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL,
   1543 	  "<addr> <url>\n"
   1544 	  "  = send WNM-Notification Subscription Remediation Request" },
   1545 	{ "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL,
   1546 	  "<addr> <code (0/1)> <Re-auth-Delay(sec)> [url]\n"
   1547 	  "  = send WNM-Notification imminent deauthentication indication" },
   1548 	{ "vendor", hostapd_cli_cmd_vendor, NULL,
   1549 	  "<vendor id> <sub command id> [<hex formatted data>]\n"
   1550 	  "  = send vendor driver command" },
   1551 	{ "enable", hostapd_cli_cmd_enable, NULL,
   1552 	  "= enable hostapd on current interface" },
   1553 	{ "reload", hostapd_cli_cmd_reload, NULL,
   1554 	  "= reload configuration for current interface" },
   1555 	{ "disable", hostapd_cli_cmd_disable, NULL,
   1556 	  "= disable hostapd on current interface" },
   1557 	{ "erp_flush", hostapd_cli_cmd_erp_flush, NULL,
   1558 	  "= drop all ERP keys"},
   1559 	{ "log_level", hostapd_cli_cmd_log_level, NULL,
   1560 	  "[level] = show/change log verbosity level" },
   1561 	{ "pmksa", hostapd_cli_cmd_pmksa, NULL,
   1562 	  " = show PMKSA cache entries" },
   1563 	{ "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL,
   1564 	  " = flush PMKSA cache" },
   1565 	{ "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL,
   1566 	  "<addr> <ssid=> <nr=> [lci=] [civic=] [stat]\n"
   1567 	  "  = add AP to neighbor database" },
   1568 	{ "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL,
   1569 	  "<addr> <ssid=> = remove AP from neighbor database" },
   1570 	{ "req_lci", hostapd_cli_cmd_req_lci, hostapd_complete_stations,
   1571 	  "<addr> = send LCI request to a station"},
   1572 	{ "req_range", hostapd_cli_cmd_req_range, NULL,
   1573 	  " = send FTM range request"},
   1574 	{ "driver_flags", hostapd_cli_cmd_driver_flags, NULL,
   1575 	  " = show supported driver flags"},
   1576 #ifdef CONFIG_DPP
   1577 	{ "dpp_qr_code", hostapd_cli_cmd_dpp_qr_code, NULL,
   1578 	  "report a scanned DPP URI from a QR Code" },
   1579 	{ "dpp_bootstrap_gen", hostapd_cli_cmd_dpp_bootstrap_gen, NULL,
   1580 	  "type=<qrcode> [chan=..] [mac=..] [info=..] [curve=..] [key=..] = generate DPP bootstrap information" },
   1581 	{ "dpp_bootstrap_remove", hostapd_cli_cmd_dpp_bootstrap_remove, NULL,
   1582 	  "*|<id> = remove DPP bootstrap information" },
   1583 	{ "dpp_bootstrap_get_uri", hostapd_cli_cmd_dpp_bootstrap_get_uri, NULL,
   1584 	  "<id> = get DPP bootstrap URI" },
   1585 	{ "dpp_bootstrap_info", hostapd_cli_cmd_dpp_bootstrap_info, NULL,
   1586 	  "<id> = show DPP bootstrap information" },
   1587 	{ "dpp_auth_init", hostapd_cli_cmd_dpp_auth_init, NULL,
   1588 	  "peer=<id> [own=<id>] = initiate DPP bootstrapping" },
   1589 	{ "dpp_configurator_add", hostapd_cli_cmd_dpp_configurator_add, NULL,
   1590 	  "[curve=..] [key=..] = add DPP configurator" },
   1591 	{ "dpp_configurator_remove", hostapd_cli_cmd_dpp_configurator_remove,
   1592 	  NULL,
   1593 	  "*|<id> = remove DPP configurator" },
   1594 	{ "dpp_pkex_add", hostapd_cli_cmd_dpp_pkex_add, NULL,
   1595 	  "add PKEX code" },
   1596 	{ "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL,
   1597 	  "*|<id> = remove DPP pkex information" },
   1598 #endif /* CONFIG_DPP */
   1599 	{ NULL, NULL, NULL, NULL }
   1600 };
   1601 
   1602 
   1603 /*
   1604  * Prints command usage, lines are padded with the specified string.
   1605  */
   1606 static void print_cmd_help(FILE *stream, const struct hostapd_cli_cmd *cmd,
   1607 			   const char *pad)
   1608 {
   1609 	char c;
   1610 	size_t n;
   1611 
   1612 	if (cmd->usage == NULL)
   1613 		return;
   1614 	fprintf(stream, "%s%s ", pad, cmd->cmd);
   1615 	for (n = 0; (c = cmd->usage[n]); n++) {
   1616 		fprintf(stream, "%c", c);
   1617 		if (c == '\n')
   1618 			fprintf(stream, "%s", pad);
   1619 	}
   1620 	fprintf(stream, "\n");
   1621 }
   1622 
   1623 
   1624 static void print_help(FILE *stream, const char *cmd)
   1625 {
   1626 	int n;
   1627 
   1628 	fprintf(stream, "commands:\n");
   1629 	for (n = 0; hostapd_cli_commands[n].cmd; n++) {
   1630 		if (cmd == NULL || str_starts(hostapd_cli_commands[n].cmd, cmd))
   1631 			print_cmd_help(stream, &hostapd_cli_commands[n], "  ");
   1632 	}
   1633 }
   1634 
   1635 
   1636 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
   1637 {
   1638 	const struct hostapd_cli_cmd *cmd, *match = NULL;
   1639 	int count;
   1640 
   1641 	count = 0;
   1642 	cmd = hostapd_cli_commands;
   1643 	while (cmd->cmd) {
   1644 		if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
   1645 			match = cmd;
   1646 			if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
   1647 				/* we have an exact match */
   1648 				count = 1;
   1649 				break;
   1650 			}
   1651 			count++;
   1652 		}
   1653 		cmd++;
   1654 	}
   1655 
   1656 	if (count > 1) {
   1657 		printf("Ambiguous command '%s'; possible commands:", argv[0]);
   1658 		cmd = hostapd_cli_commands;
   1659 		while (cmd->cmd) {
   1660 			if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
   1661 			    0) {
   1662 				printf(" %s", cmd->cmd);
   1663 			}
   1664 			cmd++;
   1665 		}
   1666 		printf("\n");
   1667 	} else if (count == 0) {
   1668 		printf("Unknown command '%s'\n", argv[0]);
   1669 	} else {
   1670 		match->handler(ctrl, argc - 1, &argv[1]);
   1671 	}
   1672 }
   1673 
   1674 
   1675 static void cli_event(const char *str)
   1676 {
   1677 	const char *start, *s;
   1678 
   1679 	start = os_strchr(str, '>');
   1680 	if (start == NULL)
   1681 		return;
   1682 
   1683 	start++;
   1684 
   1685 	if (str_starts(start, AP_STA_CONNECTED)) {
   1686 		s = os_strchr(start, ' ');
   1687 		if (s == NULL)
   1688 			return;
   1689 		cli_txt_list_add(&stations, s + 1);
   1690 		return;
   1691 	}
   1692 
   1693 	if (str_starts(start, AP_STA_DISCONNECTED)) {
   1694 		s = os_strchr(start, ' ');
   1695 		if (s == NULL)
   1696 			return;
   1697 		cli_txt_list_del_addr(&stations, s + 1);
   1698 		return;
   1699 	}
   1700 }
   1701 
   1702 
   1703 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
   1704 				     int action_monitor)
   1705 {
   1706 	int first = 1;
   1707 	if (ctrl_conn == NULL)
   1708 		return;
   1709 	while (wpa_ctrl_pending(ctrl)) {
   1710 		char buf[4096];
   1711 		size_t len = sizeof(buf) - 1;
   1712 		if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
   1713 			buf[len] = '\0';
   1714 			if (action_monitor)
   1715 				hostapd_cli_action_process(buf, len);
   1716 			else {
   1717 				cli_event(buf);
   1718 				if (in_read && first)
   1719 					printf("\n");
   1720 				first = 0;
   1721 				printf("%s\n", buf);
   1722 			}
   1723 		} else {
   1724 			printf("Could not read pending message.\n");
   1725 			break;
   1726 		}
   1727 	}
   1728 }
   1729 
   1730 
   1731 static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx)
   1732 {
   1733 	hostapd_cli_recv_pending(ctrl_conn, 0, 0);
   1734 }
   1735 
   1736 
   1737 static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
   1738 {
   1739 	if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
   1740 		printf("Connection to hostapd lost - trying to reconnect\n");
   1741 		hostapd_cli_close_connection();
   1742 	}
   1743 	if (!ctrl_conn && hostapd_cli_reconnect(ctrl_ifname) == 0)
   1744 		printf("Connection to hostapd re-established\n");
   1745 	if (ctrl_conn)
   1746 		hostapd_cli_recv_pending(ctrl_conn, 1, 0);
   1747 	eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
   1748 }
   1749 
   1750 
   1751 static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
   1752 {
   1753 	eloop_terminate();
   1754 }
   1755 
   1756 
   1757 static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
   1758 {
   1759 	char *argv[max_args];
   1760 	int argc;
   1761 	argc = tokenize_cmd(cmd, argv);
   1762 	if (argc)
   1763 		wpa_request(ctrl_conn, argc, argv);
   1764 }
   1765 
   1766 
   1767 static void hostapd_cli_edit_eof_cb(void *ctx)
   1768 {
   1769 	eloop_terminate();
   1770 }
   1771 
   1772 
   1773 static char ** list_cmd_list(void)
   1774 {
   1775 	char **res;
   1776 	int i, count;
   1777 
   1778 	count = ARRAY_SIZE(hostapd_cli_commands);
   1779 	res = os_calloc(count + 1, sizeof(char *));
   1780 	if (res == NULL)
   1781 		return NULL;
   1782 
   1783 	for (i = 0; hostapd_cli_commands[i].cmd; i++) {
   1784 		res[i] = os_strdup(hostapd_cli_commands[i].cmd);
   1785 		if (res[i] == NULL)
   1786 			break;
   1787 	}
   1788 
   1789 	return res;
   1790 }
   1791 
   1792 
   1793 static char ** hostapd_cli_cmd_completion(const char *cmd, const char *str,
   1794 				      int pos)
   1795 {
   1796 	int i;
   1797 
   1798 	for (i = 0; hostapd_cli_commands[i].cmd; i++) {
   1799 		if (os_strcasecmp(hostapd_cli_commands[i].cmd, cmd) != 0)
   1800 			continue;
   1801 		if (hostapd_cli_commands[i].completion)
   1802 			return hostapd_cli_commands[i].completion(str, pos);
   1803 		if (!hostapd_cli_commands[i].usage)
   1804 			return NULL;
   1805 		edit_clear_line();
   1806 		printf("\r%s\n", hostapd_cli_commands[i].usage);
   1807 		edit_redraw();
   1808 		break;
   1809 	}
   1810 
   1811 	return NULL;
   1812 }
   1813 
   1814 
   1815 static char ** hostapd_cli_edit_completion_cb(void *ctx, const char *str,
   1816 					      int pos)
   1817 {
   1818 	char **res;
   1819 	const char *end;
   1820 	char *cmd;
   1821 
   1822 	end = os_strchr(str, ' ');
   1823 	if (end == NULL || str + pos < end)
   1824 		return list_cmd_list();
   1825 
   1826 	cmd = os_malloc(pos + 1);
   1827 	if (cmd == NULL)
   1828 		return NULL;
   1829 	os_memcpy(cmd, str, pos);
   1830 	cmd[end - str] = '\0';
   1831 	res = hostapd_cli_cmd_completion(cmd, str, pos);
   1832 	os_free(cmd);
   1833 	return res;
   1834 }
   1835 
   1836 
   1837 static void hostapd_cli_interactive(void)
   1838 {
   1839 	char *hfile = NULL;
   1840 	char *home;
   1841 
   1842 	printf("\nInteractive mode\n\n");
   1843 
   1844 #ifdef CONFIG_HOSTAPD_CLI_HISTORY_DIR
   1845 	home = CONFIG_HOSTAPD_CLI_HISTORY_DIR;
   1846 #else /* CONFIG_HOSTAPD_CLI_HISTORY_DIR */
   1847 	home = getenv("HOME");
   1848 #endif /* CONFIG_HOSTAPD_CLI_HISTORY_DIR */
   1849 	if (home) {
   1850 		const char *fname = ".hostapd_cli_history";
   1851 		int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
   1852 		hfile = os_malloc(hfile_len);
   1853 		if (hfile)
   1854 			os_snprintf(hfile, hfile_len, "%s/%s", home, fname);
   1855 	}
   1856 
   1857 	eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
   1858 	edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
   1859 		  hostapd_cli_edit_completion_cb, NULL, hfile, NULL);
   1860 	eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
   1861 
   1862 	eloop_run();
   1863 
   1864 	cli_txt_list_flush(&stations);
   1865 	edit_deinit(hfile, NULL);
   1866 	os_free(hfile);
   1867 	eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
   1868 }
   1869 
   1870 
   1871 static void hostapd_cli_cleanup(void)
   1872 {
   1873 	hostapd_cli_close_connection();
   1874 	if (pid_file)
   1875 		os_daemonize_terminate(pid_file);
   1876 
   1877 	os_program_deinit();
   1878 }
   1879 
   1880 
   1881 static void hostapd_cli_action(struct wpa_ctrl *ctrl)
   1882 {
   1883 	fd_set rfds;
   1884 	int fd, res;
   1885 	struct timeval tv;
   1886 	char buf[256];
   1887 	size_t len;
   1888 
   1889 	fd = wpa_ctrl_get_fd(ctrl);
   1890 
   1891 	while (!hostapd_cli_quit) {
   1892 		FD_ZERO(&rfds);
   1893 		FD_SET(fd, &rfds);
   1894 		tv.tv_sec = ping_interval;
   1895 		tv.tv_usec = 0;
   1896 		res = select(fd + 1, &rfds, NULL, NULL, &tv);
   1897 		if (res < 0 && errno != EINTR) {
   1898 			perror("select");
   1899 			break;
   1900 		}
   1901 
   1902 		if (FD_ISSET(fd, &rfds))
   1903 			hostapd_cli_recv_pending(ctrl, 0, 1);
   1904 		else {
   1905 			len = sizeof(buf) - 1;
   1906 			if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
   1907 					     hostapd_cli_action_process) < 0 ||
   1908 			    len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
   1909 				printf("hostapd did not reply to PING "
   1910 				       "command - exiting\n");
   1911 				break;
   1912 			}
   1913 		}
   1914 	}
   1915 }
   1916 
   1917 
   1918 int main(int argc, char *argv[])
   1919 {
   1920 	int warning_displayed = 0;
   1921 	int c;
   1922 	int daemonize = 0;
   1923 
   1924 	if (os_program_init())
   1925 		return -1;
   1926 
   1927 	for (;;) {
   1928 		c = getopt(argc, argv, "a:BhG:i:p:P:s:v");
   1929 		if (c < 0)
   1930 			break;
   1931 		switch (c) {
   1932 		case 'a':
   1933 			action_file = optarg;
   1934 			break;
   1935 		case 'B':
   1936 			daemonize = 1;
   1937 			break;
   1938 		case 'G':
   1939 			ping_interval = atoi(optarg);
   1940 			break;
   1941 		case 'h':
   1942 			usage();
   1943 			return 0;
   1944 		case 'v':
   1945 			printf("%s\n", hostapd_cli_version);
   1946 			return 0;
   1947 		case 'i':
   1948 			os_free(ctrl_ifname);
   1949 			ctrl_ifname = os_strdup(optarg);
   1950 			break;
   1951 		case 'p':
   1952 			ctrl_iface_dir = optarg;
   1953 			break;
   1954 		case 'P':
   1955 			pid_file = optarg;
   1956 			break;
   1957 		case 's':
   1958 			client_socket_dir = optarg;
   1959 			break;
   1960 		default:
   1961 			usage();
   1962 			return -1;
   1963 		}
   1964 	}
   1965 
   1966 	interactive = (argc == optind) && (action_file == NULL);
   1967 
   1968 	if (interactive) {
   1969 		printf("%s\n\n%s\n\n", hostapd_cli_version, cli_license);
   1970 	}
   1971 
   1972 	if (eloop_init())
   1973 		return -1;
   1974 
   1975 	for (;;) {
   1976 		if (ctrl_ifname == NULL) {
   1977 			struct dirent *dent;
   1978 			DIR *dir = opendir(ctrl_iface_dir);
   1979 			if (dir) {
   1980 				while ((dent = readdir(dir))) {
   1981 					if (os_strcmp(dent->d_name, ".") == 0
   1982 					    ||
   1983 					    os_strcmp(dent->d_name, "..") == 0)
   1984 						continue;
   1985 					printf("Selected interface '%s'\n",
   1986 					       dent->d_name);
   1987 					ctrl_ifname = os_strdup(dent->d_name);
   1988 					break;
   1989 				}
   1990 				closedir(dir);
   1991 			}
   1992 		}
   1993 		hostapd_cli_reconnect(ctrl_ifname);
   1994 		if (ctrl_conn) {
   1995 			if (warning_displayed)
   1996 				printf("Connection established.\n");
   1997 			break;
   1998 		}
   1999 
   2000 		if (!interactive) {
   2001 			perror("Failed to connect to hostapd - "
   2002 			       "wpa_ctrl_open");
   2003 			return -1;
   2004 		}
   2005 
   2006 		if (!warning_displayed) {
   2007 			printf("Could not connect to hostapd - re-trying\n");
   2008 			warning_displayed = 1;
   2009 		}
   2010 		os_sleep(1, 0);
   2011 		continue;
   2012 	}
   2013 
   2014 	if (action_file && !hostapd_cli_attached)
   2015 		return -1;
   2016 	if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
   2017 		return -1;
   2018 
   2019 	if (interactive)
   2020 		hostapd_cli_interactive();
   2021 	else if (action_file)
   2022 		hostapd_cli_action(ctrl_conn);
   2023 	else
   2024 		wpa_request(ctrl_conn, argc - optind, &argv[optind]);
   2025 
   2026 	unregister_event_handler(ctrl_conn);
   2027 	os_free(ctrl_ifname);
   2028 	eloop_destroy();
   2029 	hostapd_cli_cleanup();
   2030 	return 0;
   2031 }
   2032 
   2033 #else /* CONFIG_NO_CTRL_IFACE */
   2034 
   2035 int main(int argc, char *argv[])
   2036 {
   2037 	return -1;
   2038 }
   2039 
   2040 #endif /* CONFIG_NO_CTRL_IFACE */
   2041