xref: /netbsd-src/external/bsd/wpa/dist/hostapd/hostapd_cli.c (revision 45d3cc13f775755ee348416d64536fb30df46e06)
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