1214503Srpaulo/*
2214503Srpaulo * hostapd - command line interface for hostapd daemon
3346981Scy * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
4214503Srpaulo *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7214503Srpaulo */
8214503Srpaulo
9214503Srpaulo#include "includes.h"
10214503Srpaulo#include <dirent.h>
11214503Srpaulo
12214503Srpaulo#include "common/wpa_ctrl.h"
13289549Srpaulo#include "common/ieee802_11_defs.h"
14252726Srpaulo#include "utils/common.h"
15252726Srpaulo#include "utils/eloop.h"
16252726Srpaulo#include "utils/edit.h"
17214503Srpaulo#include "common/version.h"
18337817Scy#include "common/cli.h"
19214503Srpaulo
20337817Scy#ifndef CONFIG_NO_CTRL_IFACE
21214503Srpaulo
22289549Srpaulostatic const char *const hostapd_cli_version =
23214503Srpaulo"hostapd_cli v" VERSION_STR "\n"
24346981Scy"Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi> and contributors";
25214503Srpaulo
26214503Srpaulostatic struct wpa_ctrl *ctrl_conn;
27214503Srpaulostatic int hostapd_cli_quit = 0;
28214503Srpaulostatic int hostapd_cli_attached = 0;
29281806Srpaulo
30281806Srpaulo#ifndef CONFIG_CTRL_IFACE_DIR
31281806Srpaulo#define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd"
32281806Srpaulo#endif /* CONFIG_CTRL_IFACE_DIR */
33281806Srpaulostatic const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
34289549Srpaulostatic const char *client_socket_dir = NULL;
35281806Srpaulo
36214503Srpaulostatic char *ctrl_ifname = NULL;
37214503Srpaulostatic const char *pid_file = NULL;
38214503Srpaulostatic const char *action_file = NULL;
39214503Srpaulostatic int ping_interval = 5;
40252726Srpaulostatic int interactive = 0;
41337817Scystatic int event_handler_registered = 0;
42214503Srpaulo
43337817Scystatic DEFINE_DL_LIST(stations); /* struct cli_txt_entry */
44214503Srpaulo
45337817Scystatic void print_help(FILE *stream, const char *cmd);
46337817Scystatic char ** list_cmd_list(void);
47337817Scystatic void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx);
48346981Scystatic void update_stations(struct wpa_ctrl *ctrl);
49346981Scystatic void cli_event(const char *str);
50337817Scy
51337817Scy
52214503Srpaulostatic void usage(void)
53214503Srpaulo{
54214503Srpaulo	fprintf(stderr, "%s\n", hostapd_cli_version);
55214503Srpaulo	fprintf(stderr,
56214503Srpaulo		"\n"
57214503Srpaulo		"usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
58214503Srpaulo		"[-a<path>] \\\n"
59289549Srpaulo		"                   [-P<pid file>] [-G<ping interval>] [command..]\n"
60214503Srpaulo		"\n"
61214503Srpaulo		"Options:\n"
62214503Srpaulo		"   -h           help (show this usage text)\n"
63214503Srpaulo		"   -v           shown version information\n"
64214503Srpaulo		"   -p<path>     path to find control sockets (default: "
65214503Srpaulo		"/var/run/hostapd)\n"
66289549Srpaulo		"   -s<dir_path> dir path to open client sockets (default: "
67289549Srpaulo		CONFIG_CTRL_IFACE_DIR ")\n"
68214503Srpaulo		"   -a<file>     run in daemon mode executing the action file "
69214503Srpaulo		"based on events\n"
70214503Srpaulo		"                from hostapd\n"
71214503Srpaulo		"   -B           run a daemon in the background\n"
72214503Srpaulo		"   -i<ifname>   Interface to listen on (default: first "
73214503Srpaulo		"interface found in the\n"
74337817Scy		"                socket path)\n\n");
75337817Scy	print_help(stderr, NULL);
76214503Srpaulo}
77214503Srpaulo
78214503Srpaulo
79337817Scystatic void register_event_handler(struct wpa_ctrl *ctrl)
80337817Scy{
81337817Scy	if (!ctrl_conn)
82337817Scy		return;
83337817Scy	if (interactive) {
84337817Scy		event_handler_registered =
85337817Scy			!eloop_register_read_sock(wpa_ctrl_get_fd(ctrl),
86337817Scy						  hostapd_cli_receive,
87337817Scy						  NULL, NULL);
88337817Scy	}
89337817Scy}
90337817Scy
91337817Scy
92337817Scystatic void unregister_event_handler(struct wpa_ctrl *ctrl)
93337817Scy{
94337817Scy	if (!ctrl_conn)
95337817Scy		return;
96337817Scy	if (interactive && event_handler_registered) {
97337817Scy		eloop_unregister_read_sock(wpa_ctrl_get_fd(ctrl));
98337817Scy		event_handler_registered = 0;
99337817Scy	}
100337817Scy}
101337817Scy
102337817Scy
103214503Srpaulostatic struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
104214503Srpaulo{
105337817Scy#ifndef CONFIG_CTRL_IFACE_UDP
106214503Srpaulo	char *cfile;
107214503Srpaulo	int flen;
108337817Scy#endif /* !CONFIG_CTRL_IFACE_UDP */
109214503Srpaulo
110214503Srpaulo	if (ifname == NULL)
111214503Srpaulo		return NULL;
112214503Srpaulo
113337817Scy#ifdef CONFIG_CTRL_IFACE_UDP
114337817Scy	ctrl_conn = wpa_ctrl_open(ifname);
115337817Scy	return ctrl_conn;
116337817Scy#else /* CONFIG_CTRL_IFACE_UDP */
117214503Srpaulo	flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
118214503Srpaulo	cfile = malloc(flen);
119214503Srpaulo	if (cfile == NULL)
120214503Srpaulo		return NULL;
121214503Srpaulo	snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
122214503Srpaulo
123289549Srpaulo	if (client_socket_dir && client_socket_dir[0] &&
124289549Srpaulo	    access(client_socket_dir, F_OK) < 0) {
125289549Srpaulo		perror(client_socket_dir);
126289549Srpaulo		free(cfile);
127289549Srpaulo		return NULL;
128289549Srpaulo	}
129289549Srpaulo
130289549Srpaulo	ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir);
131214503Srpaulo	free(cfile);
132214503Srpaulo	return ctrl_conn;
133337817Scy#endif /* CONFIG_CTRL_IFACE_UDP */
134214503Srpaulo}
135214503Srpaulo
136214503Srpaulo
137214503Srpaulostatic void hostapd_cli_close_connection(void)
138214503Srpaulo{
139214503Srpaulo	if (ctrl_conn == NULL)
140214503Srpaulo		return;
141214503Srpaulo
142337817Scy	unregister_event_handler(ctrl_conn);
143214503Srpaulo	if (hostapd_cli_attached) {
144214503Srpaulo		wpa_ctrl_detach(ctrl_conn);
145214503Srpaulo		hostapd_cli_attached = 0;
146214503Srpaulo	}
147214503Srpaulo	wpa_ctrl_close(ctrl_conn);
148214503Srpaulo	ctrl_conn = NULL;
149214503Srpaulo}
150214503Srpaulo
151214503Srpaulo
152346981Scystatic int hostapd_cli_reconnect(const char *ifname)
153346981Scy{
154346981Scy	char *next_ctrl_ifname;
155346981Scy
156346981Scy	hostapd_cli_close_connection();
157346981Scy
158346981Scy	if (!ifname)
159346981Scy		return -1;
160346981Scy
161346981Scy	next_ctrl_ifname = os_strdup(ifname);
162346981Scy	os_free(ctrl_ifname);
163346981Scy	ctrl_ifname = next_ctrl_ifname;
164346981Scy	if (!ctrl_ifname)
165346981Scy		return -1;
166346981Scy
167346981Scy	ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
168346981Scy	if (!ctrl_conn)
169346981Scy		return -1;
170346981Scy	if (!interactive && !action_file)
171346981Scy		return 0;
172346981Scy	if (wpa_ctrl_attach(ctrl_conn) == 0) {
173346981Scy		hostapd_cli_attached = 1;
174346981Scy		register_event_handler(ctrl_conn);
175346981Scy		update_stations(ctrl_conn);
176346981Scy	} else {
177346981Scy		printf("Warning: Failed to attach to hostapd.\n");
178346981Scy	}
179346981Scy	return 0;
180346981Scy}
181346981Scy
182346981Scy
183214503Srpaulostatic void hostapd_cli_msg_cb(char *msg, size_t len)
184214503Srpaulo{
185346981Scy	cli_event(msg);
186214503Srpaulo	printf("%s\n", msg);
187214503Srpaulo}
188214503Srpaulo
189214503Srpaulo
190346981Scystatic int _wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd, int print)
191214503Srpaulo{
192214503Srpaulo	char buf[4096];
193214503Srpaulo	size_t len;
194214503Srpaulo	int ret;
195214503Srpaulo
196214503Srpaulo	if (ctrl_conn == NULL) {
197214503Srpaulo		printf("Not connected to hostapd - command dropped.\n");
198214503Srpaulo		return -1;
199214503Srpaulo	}
200214503Srpaulo	len = sizeof(buf) - 1;
201214503Srpaulo	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
202214503Srpaulo			       hostapd_cli_msg_cb);
203214503Srpaulo	if (ret == -2) {
204214503Srpaulo		printf("'%s' command timed out.\n", cmd);
205214503Srpaulo		return -2;
206214503Srpaulo	} else if (ret < 0) {
207214503Srpaulo		printf("'%s' command failed.\n", cmd);
208214503Srpaulo		return -1;
209214503Srpaulo	}
210214503Srpaulo	if (print) {
211214503Srpaulo		buf[len] = '\0';
212214503Srpaulo		printf("%s", buf);
213214503Srpaulo	}
214214503Srpaulo	return 0;
215214503Srpaulo}
216214503Srpaulo
217214503Srpaulo
218346981Scystatic inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd)
219214503Srpaulo{
220214503Srpaulo	return _wpa_ctrl_command(ctrl, cmd, 1);
221214503Srpaulo}
222214503Srpaulo
223214503Srpaulo
224337817Scystatic int hostapd_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd,
225337817Scy			   int min_args, int argc, char *argv[])
226337817Scy{
227337817Scy	char buf[4096];
228337817Scy
229337817Scy	if (argc < min_args) {
230337817Scy		printf("Invalid %s command - at least %d argument%s required.\n",
231337817Scy		       cmd, min_args, min_args > 1 ? "s are" : " is");
232337817Scy		return -1;
233337817Scy	}
234337817Scy	if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0)
235337817Scy		return -1;
236337817Scy	return wpa_ctrl_command(ctrl, buf);
237337817Scy}
238337817Scy
239337817Scy
240214503Srpaulostatic int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
241214503Srpaulo{
242214503Srpaulo	return wpa_ctrl_command(ctrl, "PING");
243214503Srpaulo}
244214503Srpaulo
245214503Srpaulo
246252726Srpaulostatic int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
247252726Srpaulo{
248252726Srpaulo	return wpa_ctrl_command(ctrl, "RELOG");
249252726Srpaulo}
250252726Srpaulo
251252726Srpaulo
252281806Srpaulostatic int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
253281806Srpaulo{
254281806Srpaulo	if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
255281806Srpaulo		return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
256281806Srpaulo	return wpa_ctrl_command(ctrl, "STATUS");
257281806Srpaulo}
258281806Srpaulo
259281806Srpaulo
260214503Srpaulostatic int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
261214503Srpaulo{
262281806Srpaulo	if (argc > 0) {
263281806Srpaulo		char buf[100];
264281806Srpaulo		os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]);
265281806Srpaulo		return wpa_ctrl_command(ctrl, buf);
266281806Srpaulo	}
267214503Srpaulo	return wpa_ctrl_command(ctrl, "MIB");
268214503Srpaulo}
269214503Srpaulo
270214503Srpaulo
271214503Srpaulostatic int hostapd_cli_exec(const char *program, const char *arg1,
272214503Srpaulo			    const char *arg2)
273214503Srpaulo{
274281806Srpaulo	char *arg;
275214503Srpaulo	size_t len;
276214503Srpaulo	int res;
277214503Srpaulo
278281806Srpaulo	len = os_strlen(arg1) + os_strlen(arg2) + 2;
279281806Srpaulo	arg = os_malloc(len);
280281806Srpaulo	if (arg == NULL)
281214503Srpaulo		return -1;
282281806Srpaulo	os_snprintf(arg, len, "%s %s", arg1, arg2);
283281806Srpaulo	res = os_exec(program, arg, 1);
284281806Srpaulo	os_free(arg);
285214503Srpaulo
286281806Srpaulo	return res;
287214503Srpaulo}
288214503Srpaulo
289214503Srpaulo
290214503Srpaulostatic void hostapd_cli_action_process(char *msg, size_t len)
291214503Srpaulo{
292214503Srpaulo	const char *pos;
293214503Srpaulo
294214503Srpaulo	pos = msg;
295214503Srpaulo	if (*pos == '<') {
296214503Srpaulo		pos = os_strchr(pos, '>');
297214503Srpaulo		if (pos)
298214503Srpaulo			pos++;
299214503Srpaulo		else
300214503Srpaulo			pos = msg;
301214503Srpaulo	}
302214503Srpaulo
303214503Srpaulo	hostapd_cli_exec(action_file, ctrl_ifname, pos);
304214503Srpaulo}
305214503Srpaulo
306214503Srpaulo
307214503Srpaulostatic int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
308214503Srpaulo{
309214503Srpaulo	char buf[64];
310281806Srpaulo	if (argc < 1) {
311281806Srpaulo		printf("Invalid 'sta' command - at least one argument, STA "
312214503Srpaulo		       "address, is required.\n");
313214503Srpaulo		return -1;
314214503Srpaulo	}
315281806Srpaulo	if (argc > 1)
316281806Srpaulo		snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]);
317281806Srpaulo	else
318281806Srpaulo		snprintf(buf, sizeof(buf), "STA %s", argv[0]);
319214503Srpaulo	return wpa_ctrl_command(ctrl, buf);
320214503Srpaulo}
321214503Srpaulo
322214503Srpaulo
323346981Scystatic char ** hostapd_complete_stations(const char *str, int pos)
324346981Scy{
325346981Scy	int arg = get_cmd_arg_num(str, pos);
326346981Scy	char **res = NULL;
327346981Scy
328346981Scy	switch (arg) {
329346981Scy	case 1:
330346981Scy		res = cli_txt_list_array(&stations);
331346981Scy		break;
332346981Scy	}
333346981Scy
334346981Scy	return res;
335346981Scy}
336346981Scy
337346981Scy
338214503Srpaulostatic int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
339214503Srpaulo				   char *argv[])
340214503Srpaulo{
341214503Srpaulo	char buf[64];
342214503Srpaulo	if (argc != 1) {
343214503Srpaulo		printf("Invalid 'new_sta' command - exactly one argument, STA "
344214503Srpaulo		       "address, is required.\n");
345214503Srpaulo		return -1;
346214503Srpaulo	}
347214503Srpaulo	snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
348214503Srpaulo	return wpa_ctrl_command(ctrl, buf);
349214503Srpaulo}
350214503Srpaulo
351214503Srpaulo
352214503Srpaulostatic int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
353214503Srpaulo					  char *argv[])
354214503Srpaulo{
355214503Srpaulo	char buf[64];
356214503Srpaulo	if (argc < 1) {
357214503Srpaulo		printf("Invalid 'deauthenticate' command - exactly one "
358214503Srpaulo		       "argument, STA address, is required.\n");
359214503Srpaulo		return -1;
360214503Srpaulo	}
361214503Srpaulo	if (argc > 1)
362214503Srpaulo		os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
363214503Srpaulo			    argv[0], argv[1]);
364214503Srpaulo	else
365214503Srpaulo		os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
366214503Srpaulo	return wpa_ctrl_command(ctrl, buf);
367214503Srpaulo}
368214503Srpaulo
369214503Srpaulo
370214503Srpaulostatic int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
371214503Srpaulo					char *argv[])
372214503Srpaulo{
373214503Srpaulo	char buf[64];
374214503Srpaulo	if (argc < 1) {
375214503Srpaulo		printf("Invalid 'disassociate' command - exactly one "
376214503Srpaulo		       "argument, STA address, is required.\n");
377214503Srpaulo		return -1;
378214503Srpaulo	}
379214503Srpaulo	if (argc > 1)
380214503Srpaulo		os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
381214503Srpaulo			    argv[0], argv[1]);
382214503Srpaulo	else
383214503Srpaulo		os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
384214503Srpaulo	return wpa_ctrl_command(ctrl, buf);
385214503Srpaulo}
386214503Srpaulo
387214503Srpaulo
388337817Scy#ifdef CONFIG_TAXONOMY
389337817Scystatic int hostapd_cli_cmd_signature(struct wpa_ctrl *ctrl, int argc,
390337817Scy				     char *argv[])
391337817Scy{
392337817Scy	char buf[64];
393337817Scy
394337817Scy	if (argc != 1) {
395337817Scy		printf("Invalid 'signature' command - exactly one argument, STA address, is required.\n");
396337817Scy		return -1;
397337817Scy	}
398337817Scy	os_snprintf(buf, sizeof(buf), "SIGNATURE %s", argv[0]);
399337817Scy	return wpa_ctrl_command(ctrl, buf);
400337817Scy}
401337817Scy#endif /* CONFIG_TAXONOMY */
402337817Scy
403337817Scy
404214503Srpaulo#ifdef CONFIG_IEEE80211W
405214503Srpaulostatic int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
406214503Srpaulo				    char *argv[])
407214503Srpaulo{
408214503Srpaulo	char buf[64];
409214503Srpaulo	if (argc != 1) {
410214503Srpaulo		printf("Invalid 'sa_query' command - exactly one argument, "
411214503Srpaulo		       "STA address, is required.\n");
412214503Srpaulo		return -1;
413214503Srpaulo	}
414214503Srpaulo	snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
415214503Srpaulo	return wpa_ctrl_command(ctrl, buf);
416214503Srpaulo}
417214503Srpaulo#endif /* CONFIG_IEEE80211W */
418214503Srpaulo
419214503Srpaulo
420214503Srpaulo#ifdef CONFIG_WPS
421214503Srpaulostatic int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
422214503Srpaulo				   char *argv[])
423214503Srpaulo{
424252726Srpaulo	char buf[256];
425214503Srpaulo	if (argc < 2) {
426214503Srpaulo		printf("Invalid 'wps_pin' command - at least two arguments, "
427214503Srpaulo		       "UUID and PIN, are required.\n");
428214503Srpaulo		return -1;
429214503Srpaulo	}
430252726Srpaulo	if (argc > 3)
431252726Srpaulo		snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
432252726Srpaulo			 argv[0], argv[1], argv[2], argv[3]);
433252726Srpaulo	else if (argc > 2)
434214503Srpaulo		snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
435214503Srpaulo			 argv[0], argv[1], argv[2]);
436214503Srpaulo	else
437214503Srpaulo		snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
438214503Srpaulo	return wpa_ctrl_command(ctrl, buf);
439214503Srpaulo}
440214503Srpaulo
441214503Srpaulo
442252726Srpaulostatic int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
443252726Srpaulo					 char *argv[])
444252726Srpaulo{
445252726Srpaulo	char cmd[256];
446252726Srpaulo	int res;
447252726Srpaulo
448252726Srpaulo	if (argc != 1 && argc != 2) {
449252726Srpaulo		printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
450252726Srpaulo		       "- PIN to be verified\n");
451252726Srpaulo		return -1;
452252726Srpaulo	}
453252726Srpaulo
454252726Srpaulo	if (argc == 2)
455252726Srpaulo		res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
456252726Srpaulo				  argv[0], argv[1]);
457252726Srpaulo	else
458252726Srpaulo		res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
459252726Srpaulo				  argv[0]);
460281806Srpaulo	if (os_snprintf_error(sizeof(cmd), res)) {
461252726Srpaulo		printf("Too long WPS_CHECK_PIN command.\n");
462252726Srpaulo		return -1;
463252726Srpaulo	}
464252726Srpaulo	return wpa_ctrl_command(ctrl, cmd);
465252726Srpaulo}
466252726Srpaulo
467252726Srpaulo
468214503Srpaulostatic int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
469214503Srpaulo				   char *argv[])
470214503Srpaulo{
471214503Srpaulo	return wpa_ctrl_command(ctrl, "WPS_PBC");
472214503Srpaulo}
473214503Srpaulo
474214503Srpaulo
475252726Srpaulostatic int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
476252726Srpaulo				      char *argv[])
477214503Srpaulo{
478252726Srpaulo	return wpa_ctrl_command(ctrl, "WPS_CANCEL");
479252726Srpaulo}
480252726Srpaulo
481252726Srpaulo
482252726Srpaulo#ifdef CONFIG_WPS_NFC
483252726Srpaulostatic int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
484252726Srpaulo					    char *argv[])
485252726Srpaulo{
486252726Srpaulo	int ret;
487252726Srpaulo	char *buf;
488252726Srpaulo	size_t buflen;
489252726Srpaulo
490252726Srpaulo	if (argc != 1) {
491252726Srpaulo		printf("Invalid 'wps_nfc_tag_read' command - one argument "
492252726Srpaulo		       "is required.\n");
493252726Srpaulo		return -1;
494252726Srpaulo	}
495252726Srpaulo
496252726Srpaulo	buflen = 18 + os_strlen(argv[0]);
497252726Srpaulo	buf = os_malloc(buflen);
498252726Srpaulo	if (buf == NULL)
499252726Srpaulo		return -1;
500252726Srpaulo	os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
501252726Srpaulo
502252726Srpaulo	ret = wpa_ctrl_command(ctrl, buf);
503252726Srpaulo	os_free(buf);
504252726Srpaulo
505252726Srpaulo	return ret;
506252726Srpaulo}
507252726Srpaulo
508252726Srpaulo
509252726Srpaulostatic int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
510252726Srpaulo						int argc, char *argv[])
511252726Srpaulo{
512252726Srpaulo	char cmd[64];
513214503Srpaulo	int res;
514214503Srpaulo
515252726Srpaulo	if (argc != 1) {
516252726Srpaulo		printf("Invalid 'wps_nfc_config_token' command - one argument "
517252726Srpaulo		       "is required.\n");
518214503Srpaulo		return -1;
519214503Srpaulo	}
520214503Srpaulo
521252726Srpaulo	res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
522252726Srpaulo			  argv[0]);
523281806Srpaulo	if (os_snprintf_error(sizeof(cmd), res)) {
524252726Srpaulo		printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
525214503Srpaulo		return -1;
526214503Srpaulo	}
527214503Srpaulo	return wpa_ctrl_command(ctrl, cmd);
528214503Srpaulo}
529214503Srpaulo
530214503Srpaulo
531252726Srpaulostatic int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
532252726Srpaulo					 int argc, char *argv[])
533252726Srpaulo{
534252726Srpaulo	char cmd[64];
535252726Srpaulo	int res;
536252726Srpaulo
537252726Srpaulo	if (argc != 1) {
538252726Srpaulo		printf("Invalid 'wps_nfc_token' command - one argument is "
539252726Srpaulo		       "required.\n");
540252726Srpaulo		return -1;
541252726Srpaulo	}
542252726Srpaulo
543252726Srpaulo	res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
544281806Srpaulo	if (os_snprintf_error(sizeof(cmd), res)) {
545252726Srpaulo		printf("Too long WPS_NFC_TOKEN command.\n");
546252726Srpaulo		return -1;
547252726Srpaulo	}
548252726Srpaulo	return wpa_ctrl_command(ctrl, cmd);
549252726Srpaulo}
550281806Srpaulo
551281806Srpaulo
552281806Srpaulostatic int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
553281806Srpaulo						int argc, char *argv[])
554281806Srpaulo{
555281806Srpaulo	char cmd[64];
556281806Srpaulo	int res;
557281806Srpaulo
558281806Srpaulo	if (argc != 2) {
559281806Srpaulo		printf("Invalid 'nfc_get_handover_sel' command - two arguments "
560281806Srpaulo		       "are required.\n");
561281806Srpaulo		return -1;
562281806Srpaulo	}
563281806Srpaulo
564281806Srpaulo	res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
565281806Srpaulo			  argv[0], argv[1]);
566281806Srpaulo	if (os_snprintf_error(sizeof(cmd), res)) {
567281806Srpaulo		printf("Too long NFC_GET_HANDOVER_SEL command.\n");
568281806Srpaulo		return -1;
569281806Srpaulo	}
570281806Srpaulo	return wpa_ctrl_command(ctrl, cmd);
571281806Srpaulo}
572281806Srpaulo
573252726Srpaulo#endif /* CONFIG_WPS_NFC */
574252726Srpaulo
575252726Srpaulo
576214503Srpaulostatic int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
577214503Srpaulo				      char *argv[])
578214503Srpaulo{
579214503Srpaulo	char buf[64];
580214503Srpaulo	if (argc < 1) {
581214503Srpaulo		printf("Invalid 'wps_ap_pin' command - at least one argument "
582214503Srpaulo		       "is required.\n");
583214503Srpaulo		return -1;
584214503Srpaulo	}
585214503Srpaulo	if (argc > 2)
586214503Srpaulo		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
587214503Srpaulo			 argv[0], argv[1], argv[2]);
588214503Srpaulo	else if (argc > 1)
589214503Srpaulo		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
590214503Srpaulo			 argv[0], argv[1]);
591214503Srpaulo	else
592214503Srpaulo		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
593214503Srpaulo	return wpa_ctrl_command(ctrl, buf);
594214503Srpaulo}
595252726Srpaulo
596252726Srpaulo
597281806Srpaulostatic int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc,
598281806Srpaulo					  char *argv[])
599281806Srpaulo{
600281806Srpaulo	return wpa_ctrl_command(ctrl, "WPS_GET_STATUS");
601281806Srpaulo}
602281806Srpaulo
603281806Srpaulo
604252726Srpaulostatic int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
605252726Srpaulo				      char *argv[])
606252726Srpaulo{
607252726Srpaulo	char buf[256];
608289549Srpaulo	char ssid_hex[2 * SSID_MAX_LEN + 1];
609252726Srpaulo	char key_hex[2 * 64 + 1];
610252726Srpaulo	int i;
611252726Srpaulo
612252726Srpaulo	if (argc < 1) {
613252726Srpaulo		printf("Invalid 'wps_config' command - at least two arguments "
614252726Srpaulo		       "are required.\n");
615252726Srpaulo		return -1;
616252726Srpaulo	}
617252726Srpaulo
618252726Srpaulo	ssid_hex[0] = '\0';
619289549Srpaulo	for (i = 0; i < SSID_MAX_LEN; i++) {
620252726Srpaulo		if (argv[0][i] == '\0')
621252726Srpaulo			break;
622252726Srpaulo		os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
623252726Srpaulo	}
624252726Srpaulo
625252726Srpaulo	key_hex[0] = '\0';
626252726Srpaulo	if (argc > 3) {
627252726Srpaulo		for (i = 0; i < 64; i++) {
628252726Srpaulo			if (argv[3][i] == '\0')
629252726Srpaulo				break;
630252726Srpaulo			os_snprintf(&key_hex[i * 2], 3, "%02x",
631252726Srpaulo				    argv[3][i]);
632252726Srpaulo		}
633252726Srpaulo	}
634252726Srpaulo
635252726Srpaulo	if (argc > 3)
636252726Srpaulo		snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
637252726Srpaulo			 ssid_hex, argv[1], argv[2], key_hex);
638252726Srpaulo	else if (argc > 2)
639252726Srpaulo		snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
640252726Srpaulo			 ssid_hex, argv[1], argv[2]);
641252726Srpaulo	else
642252726Srpaulo		snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
643252726Srpaulo			 ssid_hex, argv[1]);
644252726Srpaulo	return wpa_ctrl_command(ctrl, buf);
645252726Srpaulo}
646214503Srpaulo#endif /* CONFIG_WPS */
647214503Srpaulo
648214503Srpaulo
649252726Srpaulostatic int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
650252726Srpaulo					     char *argv[])
651252726Srpaulo{
652252726Srpaulo	char buf[300];
653252726Srpaulo	int res;
654252726Srpaulo
655252726Srpaulo	if (argc < 2) {
656252726Srpaulo		printf("Invalid 'disassoc_imminent' command - two arguments "
657252726Srpaulo		       "(STA addr and Disassociation Timer) are needed\n");
658252726Srpaulo		return -1;
659252726Srpaulo	}
660252726Srpaulo
661252726Srpaulo	res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
662252726Srpaulo			  argv[0], argv[1]);
663281806Srpaulo	if (os_snprintf_error(sizeof(buf), res))
664252726Srpaulo		return -1;
665252726Srpaulo	return wpa_ctrl_command(ctrl, buf);
666252726Srpaulo}
667252726Srpaulo
668252726Srpaulo
669252726Srpaulostatic int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
670252726Srpaulo					char *argv[])
671252726Srpaulo{
672252726Srpaulo	char buf[300];
673252726Srpaulo	int res;
674252726Srpaulo
675281806Srpaulo	if (argc < 3) {
676281806Srpaulo		printf("Invalid 'ess_disassoc' command - three arguments (STA "
677281806Srpaulo		       "addr, disassoc timer, and URL) are needed\n");
678252726Srpaulo		return -1;
679252726Srpaulo	}
680252726Srpaulo
681281806Srpaulo	res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
682281806Srpaulo			  argv[0], argv[1], argv[2]);
683281806Srpaulo	if (os_snprintf_error(sizeof(buf), res))
684252726Srpaulo		return -1;
685252726Srpaulo	return wpa_ctrl_command(ctrl, buf);
686252726Srpaulo}
687252726Srpaulo
688252726Srpaulo
689281806Srpaulostatic int hostapd_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc,
690281806Srpaulo				      char *argv[])
691281806Srpaulo{
692281806Srpaulo	char buf[2000], *tmp;
693281806Srpaulo	int res, i, total;
694281806Srpaulo
695281806Srpaulo	if (argc < 1) {
696281806Srpaulo		printf("Invalid 'bss_tm_req' command - at least one argument (STA addr) is needed\n");
697281806Srpaulo		return -1;
698281806Srpaulo	}
699281806Srpaulo
700281806Srpaulo	res = os_snprintf(buf, sizeof(buf), "BSS_TM_REQ %s", argv[0]);
701281806Srpaulo	if (os_snprintf_error(sizeof(buf), res))
702281806Srpaulo		return -1;
703281806Srpaulo
704281806Srpaulo	total = res;
705281806Srpaulo	for (i = 1; i < argc; i++) {
706281806Srpaulo		tmp = &buf[total];
707281806Srpaulo		res = os_snprintf(tmp, sizeof(buf) - total, " %s", argv[i]);
708281806Srpaulo		if (os_snprintf_error(sizeof(buf) - total, res))
709281806Srpaulo			return -1;
710281806Srpaulo		total += res;
711281806Srpaulo	}
712281806Srpaulo	return wpa_ctrl_command(ctrl, buf);
713281806Srpaulo}
714281806Srpaulo
715281806Srpaulo
716252726Srpaulostatic int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
717252726Srpaulo				      char *argv[])
718252726Srpaulo{
719252726Srpaulo	return wpa_ctrl_command(ctrl, "GET_CONFIG");
720252726Srpaulo}
721252726Srpaulo
722252726Srpaulo
723346981Scystatic int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, const char *cmd,
724346981Scy				char *addr, size_t addr_len, int print)
725214503Srpaulo{
726214503Srpaulo	char buf[4096], *pos;
727214503Srpaulo	size_t len;
728214503Srpaulo	int ret;
729214503Srpaulo
730214503Srpaulo	if (ctrl_conn == NULL) {
731214503Srpaulo		printf("Not connected to hostapd - command dropped.\n");
732214503Srpaulo		return -1;
733214503Srpaulo	}
734214503Srpaulo	len = sizeof(buf) - 1;
735214503Srpaulo	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
736214503Srpaulo			       hostapd_cli_msg_cb);
737214503Srpaulo	if (ret == -2) {
738214503Srpaulo		printf("'%s' command timed out.\n", cmd);
739214503Srpaulo		return -2;
740214503Srpaulo	} else if (ret < 0) {
741214503Srpaulo		printf("'%s' command failed.\n", cmd);
742214503Srpaulo		return -1;
743214503Srpaulo	}
744214503Srpaulo
745214503Srpaulo	buf[len] = '\0';
746214503Srpaulo	if (memcmp(buf, "FAIL", 4) == 0)
747214503Srpaulo		return -1;
748346981Scy	if (print)
749346981Scy		printf("%s", buf);
750214503Srpaulo
751214503Srpaulo	pos = buf;
752214503Srpaulo	while (*pos != '\0' && *pos != '\n')
753214503Srpaulo		pos++;
754214503Srpaulo	*pos = '\0';
755214503Srpaulo	os_strlcpy(addr, buf, addr_len);
756214503Srpaulo	return 0;
757214503Srpaulo}
758214503Srpaulo
759214503Srpaulo
760214503Srpaulostatic int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
761214503Srpaulo				   char *argv[])
762214503Srpaulo{
763214503Srpaulo	char addr[32], cmd[64];
764214503Srpaulo
765346981Scy	if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 1))
766214503Srpaulo		return 0;
767214503Srpaulo	do {
768214503Srpaulo		snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
769346981Scy	} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 1) == 0);
770214503Srpaulo
771214503Srpaulo	return -1;
772214503Srpaulo}
773214503Srpaulo
774214503Srpaulo
775346981Scystatic int hostapd_cli_cmd_list_sta(struct wpa_ctrl *ctrl, int argc,
776346981Scy				    char *argv[])
777346981Scy{
778346981Scy	char addr[32], cmd[64];
779346981Scy
780346981Scy	if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0))
781346981Scy		return 0;
782346981Scy	do {
783346981Scy		if (os_strcmp(addr, "") != 0)
784346981Scy			printf("%s\n", addr);
785346981Scy		os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
786346981Scy	} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0);
787346981Scy
788346981Scy	return 0;
789346981Scy}
790346981Scy
791346981Scy
792214503Srpaulostatic int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
793214503Srpaulo{
794337817Scy	print_help(stdout, argc > 0 ? argv[0] : NULL);
795214503Srpaulo	return 0;
796214503Srpaulo}
797214503Srpaulo
798214503Srpaulo
799337817Scystatic char ** hostapd_cli_complete_help(const char *str, int pos)
800337817Scy{
801337817Scy	int arg = get_cmd_arg_num(str, pos);
802337817Scy	char **res = NULL;
803337817Scy
804337817Scy	switch (arg) {
805337817Scy	case 1:
806337817Scy		res = list_cmd_list();
807337817Scy		break;
808337817Scy	}
809337817Scy
810337817Scy	return res;
811337817Scy}
812337817Scy
813337817Scy
814214503Srpaulostatic int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
815214503Srpaulo				   char *argv[])
816214503Srpaulo{
817337817Scy	printf("%s\n\n%s\n", hostapd_cli_version, cli_full_license);
818214503Srpaulo	return 0;
819214503Srpaulo}
820214503Srpaulo
821214503Srpaulo
822281806Srpaulostatic int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl,
823281806Srpaulo					   int argc, char *argv[])
824281806Srpaulo{
825281806Srpaulo	char buf[200];
826281806Srpaulo	int res;
827281806Srpaulo
828281806Srpaulo	if (argc != 1) {
829281806Srpaulo		printf("Invalid 'set_qos_map_set' command - "
830281806Srpaulo		       "one argument (comma delimited QoS map set) "
831281806Srpaulo		       "is needed\n");
832281806Srpaulo		return -1;
833281806Srpaulo	}
834281806Srpaulo
835281806Srpaulo	res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
836281806Srpaulo	if (os_snprintf_error(sizeof(buf), res))
837281806Srpaulo		return -1;
838281806Srpaulo	return wpa_ctrl_command(ctrl, buf);
839281806Srpaulo}
840281806Srpaulo
841281806Srpaulo
842281806Srpaulostatic int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
843281806Srpaulo					     int argc, char *argv[])
844281806Srpaulo{
845281806Srpaulo	char buf[50];
846281806Srpaulo	int res;
847281806Srpaulo
848281806Srpaulo	if (argc != 1) {
849281806Srpaulo		printf("Invalid 'send_qos_map_conf' command - "
850281806Srpaulo		       "one argument (STA addr) is needed\n");
851281806Srpaulo		return -1;
852281806Srpaulo	}
853281806Srpaulo
854281806Srpaulo	res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
855281806Srpaulo	if (os_snprintf_error(sizeof(buf), res))
856281806Srpaulo		return -1;
857281806Srpaulo	return wpa_ctrl_command(ctrl, buf);
858281806Srpaulo}
859281806Srpaulo
860281806Srpaulo
861281806Srpaulostatic int hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc,
862281806Srpaulo					  char *argv[])
863281806Srpaulo{
864281806Srpaulo	char buf[300];
865281806Srpaulo	int res;
866281806Srpaulo
867281806Srpaulo	if (argc < 2) {
868281806Srpaulo		printf("Invalid 'hs20_wnm_notif' command - two arguments (STA "
869281806Srpaulo		       "addr and URL) are needed\n");
870281806Srpaulo		return -1;
871281806Srpaulo	}
872281806Srpaulo
873281806Srpaulo	res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s",
874281806Srpaulo			  argv[0], argv[1]);
875281806Srpaulo	if (os_snprintf_error(sizeof(buf), res))
876281806Srpaulo		return -1;
877281806Srpaulo	return wpa_ctrl_command(ctrl, buf);
878281806Srpaulo}
879281806Srpaulo
880281806Srpaulo
881281806Srpaulostatic int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc,
882281806Srpaulo					   char *argv[])
883281806Srpaulo{
884281806Srpaulo	char buf[300];
885281806Srpaulo	int res;
886281806Srpaulo
887281806Srpaulo	if (argc < 3) {
888281806Srpaulo		printf("Invalid 'hs20_deauth_req' command - at least three arguments (STA addr, Code, Re-auth Delay) are needed\n");
889281806Srpaulo		return -1;
890281806Srpaulo	}
891281806Srpaulo
892281806Srpaulo	if (argc > 3)
893281806Srpaulo		res = os_snprintf(buf, sizeof(buf),
894281806Srpaulo				  "HS20_DEAUTH_REQ %s %s %s %s",
895281806Srpaulo				  argv[0], argv[1], argv[2], argv[3]);
896281806Srpaulo	else
897281806Srpaulo		res = os_snprintf(buf, sizeof(buf),
898281806Srpaulo				  "HS20_DEAUTH_REQ %s %s %s",
899281806Srpaulo				  argv[0], argv[1], argv[2]);
900281806Srpaulo	if (os_snprintf_error(sizeof(buf), res))
901281806Srpaulo		return -1;
902281806Srpaulo	return wpa_ctrl_command(ctrl, buf);
903281806Srpaulo}
904281806Srpaulo
905281806Srpaulo
906214503Srpaulostatic int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
907214503Srpaulo{
908214503Srpaulo	hostapd_cli_quit = 1;
909252726Srpaulo	if (interactive)
910252726Srpaulo		eloop_terminate();
911214503Srpaulo	return 0;
912214503Srpaulo}
913214503Srpaulo
914214503Srpaulo
915214503Srpaulostatic int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
916214503Srpaulo{
917214503Srpaulo	char cmd[256];
918214503Srpaulo	if (argc != 1) {
919214503Srpaulo		printf("Invalid LEVEL command: needs one argument (debug "
920214503Srpaulo		       "level)\n");
921214503Srpaulo		return 0;
922214503Srpaulo	}
923214503Srpaulo	snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
924214503Srpaulo	return wpa_ctrl_command(ctrl, cmd);
925214503Srpaulo}
926214503Srpaulo
927214503Srpaulo
928346981Scystatic void update_stations(struct wpa_ctrl *ctrl)
929346981Scy{
930346981Scy	char addr[32], cmd[64];
931346981Scy
932346981Scy	if (!ctrl || !interactive)
933346981Scy		return;
934346981Scy
935346981Scy	cli_txt_list_flush(&stations);
936346981Scy
937346981Scy	if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0))
938346981Scy		return;
939346981Scy	do {
940346981Scy		if (os_strcmp(addr, "") != 0)
941346981Scy			cli_txt_list_add(&stations, addr);
942346981Scy		os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
943346981Scy	} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0);
944346981Scy}
945346981Scy
946346981Scy
947337817Scystatic void hostapd_cli_get_interfaces(struct wpa_ctrl *ctrl,
948337817Scy				       struct dl_list *interfaces)
949337817Scy{
950337817Scy	struct dirent *dent;
951337817Scy	DIR *dir;
952337817Scy
953337817Scy	if (!ctrl || !interfaces)
954337817Scy		return;
955337817Scy	dir = opendir(ctrl_iface_dir);
956337817Scy	if (dir == NULL)
957337817Scy		return;
958337817Scy
959337817Scy	while ((dent = readdir(dir))) {
960337817Scy		if (strcmp(dent->d_name, ".") == 0 ||
961337817Scy		    strcmp(dent->d_name, "..") == 0)
962337817Scy			continue;
963337817Scy		cli_txt_list_add(interfaces, dent->d_name);
964337817Scy	}
965337817Scy	closedir(dir);
966337817Scy}
967337817Scy
968337817Scy
969214503Srpaulostatic void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
970214503Srpaulo{
971214503Srpaulo	struct dirent *dent;
972214503Srpaulo	DIR *dir;
973214503Srpaulo
974214503Srpaulo	dir = opendir(ctrl_iface_dir);
975214503Srpaulo	if (dir == NULL) {
976214503Srpaulo		printf("Control interface directory '%s' could not be "
977214503Srpaulo		       "openned.\n", ctrl_iface_dir);
978214503Srpaulo		return;
979214503Srpaulo	}
980214503Srpaulo
981214503Srpaulo	printf("Available interfaces:\n");
982214503Srpaulo	while ((dent = readdir(dir))) {
983214503Srpaulo		if (strcmp(dent->d_name, ".") == 0 ||
984214503Srpaulo		    strcmp(dent->d_name, "..") == 0)
985214503Srpaulo			continue;
986214503Srpaulo		printf("%s\n", dent->d_name);
987214503Srpaulo	}
988214503Srpaulo	closedir(dir);
989214503Srpaulo}
990214503Srpaulo
991214503Srpaulo
992214503Srpaulostatic int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
993214503Srpaulo				     char *argv[])
994214503Srpaulo{
995214503Srpaulo	if (argc < 1) {
996214503Srpaulo		hostapd_cli_list_interfaces(ctrl);
997214503Srpaulo		return 0;
998214503Srpaulo	}
999346981Scy	if (hostapd_cli_reconnect(argv[0]) != 0) {
1000214503Srpaulo		printf("Could not connect to interface '%s' - re-trying\n",
1001214503Srpaulo			ctrl_ifname);
1002214503Srpaulo	}
1003214503Srpaulo	return 0;
1004214503Srpaulo}
1005214503Srpaulo
1006214503Srpaulo
1007337817Scystatic char ** hostapd_complete_interface(const char *str, int pos)
1008337817Scy{
1009337817Scy	int arg = get_cmd_arg_num(str, pos);
1010337817Scy	char **res = NULL;
1011337817Scy	DEFINE_DL_LIST(interfaces);
1012337817Scy
1013337817Scy	switch (arg) {
1014337817Scy	case 1:
1015337817Scy		hostapd_cli_get_interfaces(ctrl_conn, &interfaces);
1016337817Scy		res = cli_txt_list_array(&interfaces);
1017337817Scy		cli_txt_list_flush(&interfaces);
1018337817Scy		break;
1019337817Scy	}
1020337817Scy
1021337817Scy	return res;
1022337817Scy}
1023337817Scy
1024337817Scy
1025252726Srpaulostatic int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
1026252726Srpaulo{
1027346981Scy	char cmd[2048];
1028252726Srpaulo	int res;
1029252726Srpaulo
1030252726Srpaulo	if (argc != 2) {
1031252726Srpaulo		printf("Invalid SET command: needs two arguments (variable "
1032252726Srpaulo		       "name and value)\n");
1033252726Srpaulo		return -1;
1034252726Srpaulo	}
1035252726Srpaulo
1036252726Srpaulo	res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
1037281806Srpaulo	if (os_snprintf_error(sizeof(cmd), res)) {
1038252726Srpaulo		printf("Too long SET command.\n");
1039252726Srpaulo		return -1;
1040252726Srpaulo	}
1041252726Srpaulo	return wpa_ctrl_command(ctrl, cmd);
1042252726Srpaulo}
1043252726Srpaulo
1044252726Srpaulo
1045346981Scystatic char ** hostapd_complete_set(const char *str, int pos)
1046346981Scy{
1047346981Scy	int arg = get_cmd_arg_num(str, pos);
1048346981Scy	const char *fields[] = {
1049346981Scy#ifdef CONFIG_WPS_TESTING
1050346981Scy		"wps_version_number", "wps_testing_dummy_cred",
1051346981Scy		"wps_corrupt_pkhash",
1052346981Scy#endif /* CONFIG_WPS_TESTING */
1053346981Scy#ifdef CONFIG_INTERWORKING
1054346981Scy		"gas_frag_limit",
1055346981Scy#endif /* CONFIG_INTERWORKING */
1056346981Scy#ifdef CONFIG_TESTING_OPTIONS
1057346981Scy		"ext_mgmt_frame_handling", "ext_eapol_frame_io",
1058346981Scy#endif /* CONFIG_TESTING_OPTIONS */
1059346981Scy#ifdef CONFIG_MBO
1060346981Scy		"mbo_assoc_disallow",
1061346981Scy#endif /* CONFIG_MBO */
1062346981Scy		"deny_mac_file", "accept_mac_file",
1063346981Scy	};
1064346981Scy	int i, num_fields = ARRAY_SIZE(fields);
1065346981Scy
1066346981Scy	if (arg == 1) {
1067346981Scy		char **res;
1068346981Scy
1069346981Scy		res = os_calloc(num_fields + 1, sizeof(char *));
1070346981Scy		if (!res)
1071346981Scy			return NULL;
1072346981Scy		for (i = 0; i < num_fields; i++) {
1073346981Scy			res[i] = os_strdup(fields[i]);
1074346981Scy			if (!res[i])
1075346981Scy				return res;
1076346981Scy		}
1077346981Scy		return res;
1078346981Scy	}
1079346981Scy	return NULL;
1080346981Scy}
1081346981Scy
1082346981Scy
1083252726Srpaulostatic int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
1084252726Srpaulo{
1085252726Srpaulo	char cmd[256];
1086252726Srpaulo	int res;
1087252726Srpaulo
1088252726Srpaulo	if (argc != 1) {
1089252726Srpaulo		printf("Invalid GET command: needs one argument (variable "
1090252726Srpaulo		       "name)\n");
1091252726Srpaulo		return -1;
1092252726Srpaulo	}
1093252726Srpaulo
1094252726Srpaulo	res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
1095281806Srpaulo	if (os_snprintf_error(sizeof(cmd), res)) {
1096252726Srpaulo		printf("Too long GET command.\n");
1097252726Srpaulo		return -1;
1098252726Srpaulo	}
1099252726Srpaulo	return wpa_ctrl_command(ctrl, cmd);
1100252726Srpaulo}
1101252726Srpaulo
1102252726Srpaulo
1103346981Scystatic char ** hostapd_complete_get(const char *str, int pos)
1104346981Scy{
1105346981Scy	int arg = get_cmd_arg_num(str, pos);
1106346981Scy	const char *fields[] = {
1107346981Scy		"version", "tls_library",
1108346981Scy	};
1109346981Scy	int i, num_fields = ARRAY_SIZE(fields);
1110346981Scy
1111346981Scy	if (arg == 1) {
1112346981Scy		char **res;
1113346981Scy
1114346981Scy		res = os_calloc(num_fields + 1, sizeof(char *));
1115346981Scy		if (!res)
1116346981Scy			return NULL;
1117346981Scy		for (i = 0; i < num_fields; i++) {
1118346981Scy			res[i] = os_strdup(fields[i]);
1119346981Scy			if (!res[i])
1120346981Scy				return res;
1121346981Scy		}
1122346981Scy		return res;
1123346981Scy	}
1124346981Scy	return NULL;
1125346981Scy}
1126346981Scy
1127346981Scy
1128289549Srpaulo#ifdef CONFIG_FST
1129289549Srpaulostatic int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[])
1130289549Srpaulo{
1131289549Srpaulo	char cmd[256];
1132289549Srpaulo	int res;
1133289549Srpaulo	int i;
1134289549Srpaulo	int total;
1135289549Srpaulo
1136289549Srpaulo	if (argc <= 0) {
1137289549Srpaulo		printf("FST command: parameters are required.\n");
1138289549Srpaulo		return -1;
1139289549Srpaulo	}
1140289549Srpaulo
1141289549Srpaulo	total = os_snprintf(cmd, sizeof(cmd), "FST-MANAGER");
1142289549Srpaulo
1143289549Srpaulo	for (i = 0; i < argc; i++) {
1144289549Srpaulo		res = os_snprintf(cmd + total, sizeof(cmd) - total, " %s",
1145289549Srpaulo				  argv[i]);
1146289549Srpaulo		if (os_snprintf_error(sizeof(cmd) - total, res)) {
1147289549Srpaulo			printf("Too long fst command.\n");
1148289549Srpaulo			return -1;
1149289549Srpaulo		}
1150289549Srpaulo		total += res;
1151289549Srpaulo	}
1152289549Srpaulo	return wpa_ctrl_command(ctrl, cmd);
1153289549Srpaulo}
1154289549Srpaulo#endif /* CONFIG_FST */
1155289549Srpaulo
1156289549Srpaulo
1157281806Srpaulostatic int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
1158281806Srpaulo				       int argc, char *argv[])
1159281806Srpaulo{
1160281806Srpaulo	char cmd[256];
1161281806Srpaulo	int res;
1162281806Srpaulo	int i;
1163281806Srpaulo	char *tmp;
1164281806Srpaulo	int total;
1165281806Srpaulo
1166281806Srpaulo	if (argc < 2) {
1167281806Srpaulo		printf("Invalid chan_switch command: needs at least two "
1168281806Srpaulo		       "arguments (count and freq)\n"
1169281806Srpaulo		       "usage: <cs_count> <freq> [sec_channel_offset=] "
1170281806Srpaulo		       "[center_freq1=] [center_freq2=] [bandwidth=] "
1171281806Srpaulo		       "[blocktx] [ht|vht]\n");
1172281806Srpaulo		return -1;
1173281806Srpaulo	}
1174281806Srpaulo
1175281806Srpaulo	res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
1176281806Srpaulo			  argv[0], argv[1]);
1177281806Srpaulo	if (os_snprintf_error(sizeof(cmd), res)) {
1178281806Srpaulo		printf("Too long CHAN_SWITCH command.\n");
1179281806Srpaulo		return -1;
1180281806Srpaulo	}
1181281806Srpaulo
1182281806Srpaulo	total = res;
1183281806Srpaulo	for (i = 2; i < argc; i++) {
1184281806Srpaulo		tmp = cmd + total;
1185281806Srpaulo		res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
1186281806Srpaulo		if (os_snprintf_error(sizeof(cmd) - total, res)) {
1187281806Srpaulo			printf("Too long CHAN_SWITCH command.\n");
1188281806Srpaulo			return -1;
1189281806Srpaulo		}
1190281806Srpaulo		total += res;
1191281806Srpaulo	}
1192281806Srpaulo	return wpa_ctrl_command(ctrl, cmd);
1193281806Srpaulo}
1194281806Srpaulo
1195281806Srpaulo
1196281806Srpaulostatic int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc,
1197281806Srpaulo				      char *argv[])
1198281806Srpaulo{
1199281806Srpaulo	return wpa_ctrl_command(ctrl, "ENABLE");
1200281806Srpaulo}
1201281806Srpaulo
1202281806Srpaulo
1203281806Srpaulostatic int hostapd_cli_cmd_reload(struct wpa_ctrl *ctrl, int argc,
1204281806Srpaulo				      char *argv[])
1205281806Srpaulo{
1206281806Srpaulo	return wpa_ctrl_command(ctrl, "RELOAD");
1207281806Srpaulo}
1208281806Srpaulo
1209281806Srpaulo
1210281806Srpaulostatic int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc,
1211281806Srpaulo				      char *argv[])
1212281806Srpaulo{
1213281806Srpaulo	return wpa_ctrl_command(ctrl, "DISABLE");
1214281806Srpaulo}
1215281806Srpaulo
1216281806Srpaulo
1217351611Scystatic int hostapd_cli_cmd_update_beacon(struct wpa_ctrl *ctrl, int argc,
1218351611Scy				      char *argv[])
1219351611Scy{
1220351611Scy	return wpa_ctrl_command(ctrl, "UPDATE_BEACON");
1221351611Scy}
1222351611Scy
1223351611Scy
1224281806Srpaulostatic int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
1225281806Srpaulo{
1226281806Srpaulo	char cmd[256];
1227281806Srpaulo	int res;
1228281806Srpaulo
1229281806Srpaulo	if (argc < 2 || argc > 3) {
1230281806Srpaulo		printf("Invalid vendor command\n"
1231281806Srpaulo		       "usage: <vendor id> <command id> [<hex formatted command argument>]\n");
1232281806Srpaulo		return -1;
1233281806Srpaulo	}
1234281806Srpaulo
1235281806Srpaulo	res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
1236281806Srpaulo			  argc == 3 ? argv[2] : "");
1237281806Srpaulo	if (os_snprintf_error(sizeof(cmd), res)) {
1238281806Srpaulo		printf("Too long VENDOR command.\n");
1239281806Srpaulo		return -1;
1240281806Srpaulo	}
1241281806Srpaulo	return wpa_ctrl_command(ctrl, cmd);
1242281806Srpaulo}
1243281806Srpaulo
1244281806Srpaulo
1245281806Srpaulostatic int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc,
1246281806Srpaulo				     char *argv[])
1247281806Srpaulo{
1248281806Srpaulo	return wpa_ctrl_command(ctrl, "ERP_FLUSH");
1249281806Srpaulo}
1250281806Srpaulo
1251281806Srpaulo
1252289549Srpaulostatic int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc,
1253289549Srpaulo				     char *argv[])
1254289549Srpaulo{
1255289549Srpaulo	char cmd[256];
1256289549Srpaulo	int res;
1257289549Srpaulo
1258289549Srpaulo	res = os_snprintf(cmd, sizeof(cmd), "LOG_LEVEL%s%s%s%s",
1259289549Srpaulo			  argc >= 1 ? " " : "",
1260289549Srpaulo			  argc >= 1 ? argv[0] : "",
1261289549Srpaulo			  argc == 2 ? " " : "",
1262289549Srpaulo			  argc == 2 ? argv[1] : "");
1263289549Srpaulo	if (os_snprintf_error(sizeof(cmd), res)) {
1264289549Srpaulo		printf("Too long option\n");
1265289549Srpaulo		return -1;
1266289549Srpaulo	}
1267289549Srpaulo	return wpa_ctrl_command(ctrl, cmd);
1268289549Srpaulo}
1269289549Srpaulo
1270289549Srpaulo
1271337817Scystatic int hostapd_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
1272337817Scy{
1273337817Scy	if (argc == 0)
1274337817Scy		return -1;
1275337817Scy	return hostapd_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]);
1276337817Scy}
1277337817Scy
1278337817Scy
1279337817Scystatic int hostapd_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
1280337817Scy{
1281337817Scy	return wpa_ctrl_command(ctrl, "PMKSA");
1282337817Scy}
1283337817Scy
1284337817Scy
1285337817Scystatic int hostapd_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc,
1286337817Scy				       char *argv[])
1287337817Scy{
1288337817Scy	return wpa_ctrl_command(ctrl, "PMKSA_FLUSH");
1289337817Scy}
1290337817Scy
1291337817Scy
1292337817Scystatic int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc,
1293337817Scy					char *argv[])
1294337817Scy{
1295337817Scy	char cmd[2048];
1296337817Scy	int res;
1297337817Scy
1298346981Scy	if (argc < 3 || argc > 6) {
1299346981Scy		printf("Invalid set_neighbor command: needs 3-6 arguments\n");
1300337817Scy		return -1;
1301337817Scy	}
1302337817Scy
1303346981Scy	res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s %s",
1304337817Scy			  argv[0], argv[1], argv[2], argc >= 4 ? argv[3] : "",
1305346981Scy			  argc >= 5 ? argv[4] : "", argc == 6 ? argv[5] : "");
1306337817Scy	if (os_snprintf_error(sizeof(cmd), res)) {
1307337817Scy		printf("Too long SET_NEIGHBOR command.\n");
1308337817Scy		return -1;
1309337817Scy	}
1310337817Scy	return wpa_ctrl_command(ctrl, cmd);
1311337817Scy}
1312337817Scy
1313337817Scy
1314337817Scystatic int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc,
1315337817Scy					   char *argv[])
1316337817Scy{
1317337817Scy	char cmd[400];
1318337817Scy	int res;
1319337817Scy
1320337817Scy	if (argc != 2) {
1321337817Scy		printf("Invalid remove_neighbor command: needs 2 arguments\n");
1322337817Scy		return -1;
1323337817Scy	}
1324337817Scy
1325337817Scy	res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NEIGHBOR %s %s",
1326337817Scy			  argv[0], argv[1]);
1327337817Scy	if (os_snprintf_error(sizeof(cmd), res)) {
1328337817Scy		printf("Too long REMOVE_NEIGHBOR command.\n");
1329337817Scy		return -1;
1330337817Scy	}
1331337817Scy	return wpa_ctrl_command(ctrl, cmd);
1332337817Scy}
1333337817Scy
1334337817Scy
1335337817Scystatic int hostapd_cli_cmd_req_lci(struct wpa_ctrl *ctrl, int argc,
1336337817Scy				   char *argv[])
1337337817Scy{
1338337817Scy	char cmd[256];
1339337817Scy	int res;
1340337817Scy
1341337817Scy	if (argc != 1) {
1342337817Scy		printf("Invalid req_lci command - requires destination address\n");
1343337817Scy		return -1;
1344337817Scy	}
1345337817Scy
1346337817Scy	res = os_snprintf(cmd, sizeof(cmd), "REQ_LCI %s", argv[0]);
1347337817Scy	if (os_snprintf_error(sizeof(cmd), res)) {
1348337817Scy		printf("Too long REQ_LCI command.\n");
1349337817Scy		return -1;
1350337817Scy	}
1351337817Scy	return wpa_ctrl_command(ctrl, cmd);
1352337817Scy}
1353337817Scy
1354337817Scy
1355337817Scystatic int hostapd_cli_cmd_req_range(struct wpa_ctrl *ctrl, int argc,
1356337817Scy				     char *argv[])
1357337817Scy{
1358337817Scy	if (argc < 4) {
1359337817Scy		printf("Invalid req_range command: needs at least 4 arguments - dest address, randomization interval, min AP count, and 1 to 16 AP addresses\n");
1360337817Scy		return -1;
1361337817Scy	}
1362337817Scy
1363337817Scy	return hostapd_cli_cmd(ctrl, "REQ_RANGE", 4, argc, argv);
1364337817Scy}
1365337817Scy
1366337817Scy
1367337817Scystatic int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
1368337817Scy					char *argv[])
1369337817Scy{
1370337817Scy	return wpa_ctrl_command(ctrl, "DRIVER_FLAGS");
1371337817Scy}
1372337817Scy
1373337817Scy
1374346981Scy#ifdef CONFIG_DPP
1375346981Scy
1376346981Scystatic int hostapd_cli_cmd_dpp_qr_code(struct wpa_ctrl *ctrl, int argc,
1377346981Scy				       char *argv[])
1378346981Scy{
1379346981Scy	return hostapd_cli_cmd(ctrl, "DPP_QR_CODE", 1, argc, argv);
1380346981Scy}
1381346981Scy
1382346981Scy
1383346981Scystatic int hostapd_cli_cmd_dpp_bootstrap_gen(struct wpa_ctrl *ctrl, int argc,
1384346981Scy					     char *argv[])
1385346981Scy{
1386346981Scy	return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_GEN", 1, argc, argv);
1387346981Scy}
1388346981Scy
1389346981Scy
1390346981Scystatic int hostapd_cli_cmd_dpp_bootstrap_remove(struct wpa_ctrl *ctrl, int argc,
1391346981Scy						char *argv[])
1392346981Scy{
1393346981Scy	return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_REMOVE", 1, argc, argv);
1394346981Scy}
1395346981Scy
1396346981Scy
1397346981Scystatic int hostapd_cli_cmd_dpp_bootstrap_get_uri(struct wpa_ctrl *ctrl,
1398346981Scy						 int argc, char *argv[])
1399346981Scy{
1400346981Scy	return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_GET_URI", 1, argc, argv);
1401346981Scy}
1402346981Scy
1403346981Scy
1404346981Scystatic int hostapd_cli_cmd_dpp_bootstrap_info(struct wpa_ctrl *ctrl, int argc,
1405346981Scy					      char *argv[])
1406346981Scy{
1407346981Scy	return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_INFO", 1, argc, argv);
1408346981Scy}
1409346981Scy
1410346981Scy
1411346981Scystatic int hostapd_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc,
1412346981Scy					 char *argv[])
1413346981Scy{
1414346981Scy	return hostapd_cli_cmd(ctrl, "DPP_AUTH_INIT", 1, argc, argv);
1415346981Scy}
1416346981Scy
1417346981Scy
1418346981Scystatic int hostapd_cli_cmd_dpp_listen(struct wpa_ctrl *ctrl, int argc,
1419346981Scy				      char *argv[])
1420346981Scy{
1421346981Scy	return hostapd_cli_cmd(ctrl, "DPP_LISTEN", 1, argc, argv);
1422346981Scy}
1423346981Scy
1424346981Scy
1425346981Scystatic int hostapd_cli_cmd_dpp_stop_listen(struct wpa_ctrl *ctrl, int argc,
1426346981Scy				       char *argv[])
1427346981Scy{
1428346981Scy	return wpa_ctrl_command(ctrl, "DPP_STOP_LISTEN");
1429346981Scy}
1430346981Scy
1431346981Scy
1432346981Scystatic int hostapd_cli_cmd_dpp_configurator_add(struct wpa_ctrl *ctrl, int argc,
1433346981Scy						char *argv[])
1434346981Scy{
1435346981Scy	return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_ADD", 0, argc, argv);
1436346981Scy}
1437346981Scy
1438346981Scy
1439346981Scystatic int hostapd_cli_cmd_dpp_configurator_remove(struct wpa_ctrl *ctrl,
1440346981Scy						   int argc, char *argv[])
1441346981Scy{
1442346981Scy	return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_REMOVE", 1, argc, argv);
1443346981Scy}
1444346981Scy
1445346981Scy
1446346981Scystatic int hostapd_cli_cmd_dpp_configurator_get_key(struct wpa_ctrl *ctrl,
1447346981Scy						    int argc, char *argv[])
1448346981Scy{
1449346981Scy	return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_GET_KEY", 1, argc, argv);
1450346981Scy}
1451346981Scy
1452346981Scy
1453346981Scystatic int hostapd_cli_cmd_dpp_configurator_sign(struct wpa_ctrl *ctrl,
1454346981Scy						 int argc, char *argv[])
1455346981Scy{
1456346981Scy       return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_SIGN", 1, argc, argv);
1457346981Scy}
1458346981Scy
1459346981Scy
1460346981Scystatic int hostapd_cli_cmd_dpp_pkex_add(struct wpa_ctrl *ctrl, int argc,
1461346981Scy					char *argv[])
1462346981Scy{
1463346981Scy	return hostapd_cli_cmd(ctrl, "DPP_PKEX_ADD", 1, argc, argv);
1464346981Scy}
1465346981Scy
1466346981Scy
1467346981Scystatic int hostapd_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc,
1468346981Scy					   char *argv[])
1469346981Scy{
1470346981Scy	return hostapd_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv);
1471346981Scy}
1472346981Scy
1473346981Scy#endif /* CONFIG_DPP */
1474346981Scy
1475346981Scy
1476346981Scystatic int hostapd_cli_cmd_accept_macacl(struct wpa_ctrl *ctrl, int argc,
1477346981Scy					 char *argv[])
1478346981Scy{
1479346981Scy	return hostapd_cli_cmd(ctrl, "ACCEPT_ACL", 1, argc, argv);
1480346981Scy}
1481346981Scy
1482346981Scy
1483346981Scystatic int hostapd_cli_cmd_deny_macacl(struct wpa_ctrl *ctrl, int argc,
1484346981Scy				       char *argv[])
1485346981Scy{
1486346981Scy	return hostapd_cli_cmd(ctrl, "DENY_ACL", 1, argc, argv);
1487346981Scy}
1488346981Scy
1489346981Scy
1490346981Scystatic int hostapd_cli_cmd_poll_sta(struct wpa_ctrl *ctrl, int argc,
1491346981Scy				    char *argv[])
1492346981Scy{
1493346981Scy	return hostapd_cli_cmd(ctrl, "POLL_STA", 1, argc, argv);
1494346981Scy}
1495346981Scy
1496346981Scy
1497346981Scystatic int hostapd_cli_cmd_req_beacon(struct wpa_ctrl *ctrl, int argc,
1498346981Scy				      char *argv[])
1499346981Scy{
1500346981Scy	return hostapd_cli_cmd(ctrl, "REQ_BEACON", 2, argc, argv);
1501346981Scy}
1502346981Scy
1503346981Scy
1504346981Scystatic int hostapd_cli_cmd_reload_wpa_psk(struct wpa_ctrl *ctrl, int argc,
1505346981Scy					  char *argv[])
1506346981Scy{
1507346981Scy	return wpa_ctrl_command(ctrl, "RELOAD_WPA_PSK");
1508346981Scy}
1509346981Scy
1510346981Scy
1511214503Srpaulostruct hostapd_cli_cmd {
1512214503Srpaulo	const char *cmd;
1513214503Srpaulo	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
1514337817Scy	char ** (*completion)(const char *str, int pos);
1515337817Scy	const char *usage;
1516214503Srpaulo};
1517214503Srpaulo
1518289549Srpaulostatic const struct hostapd_cli_cmd hostapd_cli_commands[] = {
1519337817Scy	{ "ping", hostapd_cli_cmd_ping, NULL,
1520337817Scy	  "= pings hostapd" },
1521337817Scy	{ "mib", hostapd_cli_cmd_mib, NULL,
1522337817Scy	  "= get MIB variables (dot1x, dot11, radius)" },
1523346981Scy	{ "relog", hostapd_cli_cmd_relog, NULL,
1524346981Scy	  "= reload/truncate debug log output file" },
1525346981Scy	{ "status", hostapd_cli_cmd_status, NULL,
1526346981Scy	  "= show interface status info" },
1527346981Scy	{ "sta", hostapd_cli_cmd_sta, hostapd_complete_stations,
1528337817Scy	  "<addr> = get MIB variables for one station" },
1529337817Scy	{ "all_sta", hostapd_cli_cmd_all_sta, NULL,
1530337817Scy	   "= get MIB variables for all stations" },
1531346981Scy	{ "list_sta", hostapd_cli_cmd_list_sta, NULL,
1532346981Scy	   "= list all stations" },
1533337817Scy	{ "new_sta", hostapd_cli_cmd_new_sta, NULL,
1534337817Scy	  "<addr> = add a new station" },
1535337817Scy	{ "deauthenticate", hostapd_cli_cmd_deauthenticate,
1536346981Scy	  hostapd_complete_stations,
1537337817Scy	  "<addr> = deauthenticate a station" },
1538337817Scy	{ "disassociate", hostapd_cli_cmd_disassociate,
1539346981Scy	  hostapd_complete_stations,
1540337817Scy	  "<addr> = disassociate a station" },
1541337817Scy#ifdef CONFIG_TAXONOMY
1542346981Scy	{ "signature", hostapd_cli_cmd_signature, hostapd_complete_stations,
1543337817Scy	  "<addr> = get taxonomy signature for a station" },
1544337817Scy#endif /* CONFIG_TAXONOMY */
1545214503Srpaulo#ifdef CONFIG_IEEE80211W
1546346981Scy	{ "sa_query", hostapd_cli_cmd_sa_query, hostapd_complete_stations,
1547337817Scy	  "<addr> = send SA Query to a station" },
1548214503Srpaulo#endif /* CONFIG_IEEE80211W */
1549214503Srpaulo#ifdef CONFIG_WPS
1550337817Scy	{ "wps_pin", hostapd_cli_cmd_wps_pin, NULL,
1551337817Scy	  "<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" },
1552337817Scy	{ "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL,
1553337817Scy	  "<PIN> = verify PIN checksum" },
1554337817Scy	{ "wps_pbc", hostapd_cli_cmd_wps_pbc, NULL,
1555337817Scy	  "= indicate button pushed to initiate PBC" },
1556337817Scy	{ "wps_cancel", hostapd_cli_cmd_wps_cancel, NULL,
1557337817Scy	  "= cancel the pending WPS operation" },
1558252726Srpaulo#ifdef CONFIG_WPS_NFC
1559337817Scy	{ "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read, NULL,
1560337817Scy	  "<hexdump> = report read NFC tag with WPS data" },
1561337817Scy	{ "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token, NULL,
1562337817Scy	  "<WPS/NDEF> = build NFC configuration token" },
1563337817Scy	{ "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token, NULL,
1564337817Scy	  "<WPS/NDEF/enable/disable> = manager NFC password token" },
1565337817Scy	{ "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel, NULL,
1566337817Scy	  NULL },
1567252726Srpaulo#endif /* CONFIG_WPS_NFC */
1568337817Scy	{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin, NULL,
1569337817Scy	  "<cmd> [params..] = enable/disable AP PIN" },
1570337817Scy	{ "wps_config", hostapd_cli_cmd_wps_config, NULL,
1571337817Scy	  "<SSID> <auth> <encr> <key> = configure AP" },
1572337817Scy	{ "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL,
1573337817Scy	  "= show current WPS status" },
1574214503Srpaulo#endif /* CONFIG_WPS */
1575346981Scy	{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL,
1576346981Scy	  "= send Disassociation Imminent notification" },
1577346981Scy	{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL,
1578346981Scy	  "= send ESS Dissassociation Imminent notification" },
1579346981Scy	{ "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL,
1580346981Scy	  "= send BSS Transition Management Request" },
1581337817Scy	{ "get_config", hostapd_cli_cmd_get_config, NULL,
1582337817Scy	  "= show current configuration" },
1583337817Scy	{ "help", hostapd_cli_cmd_help, hostapd_cli_complete_help,
1584337817Scy	  "= show this usage help" },
1585337817Scy	{ "interface", hostapd_cli_cmd_interface, hostapd_complete_interface,
1586337817Scy	  "[ifname] = show interfaces/select interface" },
1587289549Srpaulo#ifdef CONFIG_FST
1588346981Scy	{ "fst", hostapd_cli_cmd_fst, NULL,
1589346981Scy	  "<params...> = send FST-MANAGER control interface command" },
1590289549Srpaulo#endif /* CONFIG_FST */
1591346981Scy	{ "raw", hostapd_cli_cmd_raw, NULL,
1592346981Scy	  "<params..> = send unprocessed command" },
1593337817Scy	{ "level", hostapd_cli_cmd_level, NULL,
1594337817Scy	  "<debug level> = change debug level" },
1595337817Scy	{ "license", hostapd_cli_cmd_license, NULL,
1596337817Scy	  "= show full hostapd_cli license" },
1597337817Scy	{ "quit", hostapd_cli_cmd_quit, NULL,
1598337817Scy	  "= exit hostapd_cli" },
1599346981Scy	{ "set", hostapd_cli_cmd_set, hostapd_complete_set,
1600346981Scy	  "<name> <value> = set runtime variables" },
1601346981Scy	{ "get", hostapd_cli_cmd_get, hostapd_complete_get,
1602346981Scy	  "<name> = get runtime info" },
1603346981Scy	{ "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL,
1604346981Scy	  "<arg,arg,...> = set QoS Map set element" },
1605346981Scy	{ "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf,
1606346981Scy	  hostapd_complete_stations,
1607346981Scy	  "<addr> = send QoS Map Configure frame" },
1608346981Scy	{ "chan_switch", hostapd_cli_cmd_chan_switch, NULL,
1609346981Scy	  "<cs_count> <freq> [sec_channel_offset=] [center_freq1=]\n"
1610346981Scy	  "  [center_freq2=] [bandwidth=] [blocktx] [ht|vht]\n"
1611346981Scy	  "  = initiate channel switch announcement" },
1612346981Scy	{ "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL,
1613346981Scy	  "<addr> <url>\n"
1614346981Scy	  "  = send WNM-Notification Subscription Remediation Request" },
1615346981Scy	{ "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL,
1616346981Scy	  "<addr> <code (0/1)> <Re-auth-Delay(sec)> [url]\n"
1617346981Scy	  "  = send WNM-Notification imminent deauthentication indication" },
1618346981Scy	{ "vendor", hostapd_cli_cmd_vendor, NULL,
1619346981Scy	  "<vendor id> <sub command id> [<hex formatted data>]\n"
1620346981Scy	  "  = send vendor driver command" },
1621346981Scy	{ "enable", hostapd_cli_cmd_enable, NULL,
1622346981Scy	  "= enable hostapd on current interface" },
1623346981Scy	{ "reload", hostapd_cli_cmd_reload, NULL,
1624346981Scy	  "= reload configuration for current interface" },
1625346981Scy	{ "disable", hostapd_cli_cmd_disable, NULL,
1626346981Scy	  "= disable hostapd on current interface" },
1627351611Scy	{ "update_beacon", hostapd_cli_cmd_update_beacon, NULL,
1628351611Scy	  "= update Beacon frame contents\n"},
1629346981Scy	{ "erp_flush", hostapd_cli_cmd_erp_flush, NULL,
1630346981Scy	  "= drop all ERP keys"},
1631346981Scy	{ "log_level", hostapd_cli_cmd_log_level, NULL,
1632346981Scy	  "[level] = show/change log verbosity level" },
1633346981Scy	{ "pmksa", hostapd_cli_cmd_pmksa, NULL,
1634346981Scy	  " = show PMKSA cache entries" },
1635346981Scy	{ "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL,
1636346981Scy	  " = flush PMKSA cache" },
1637346981Scy	{ "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL,
1638346981Scy	  "<addr> <ssid=> <nr=> [lci=] [civic=] [stat]\n"
1639346981Scy	  "  = add AP to neighbor database" },
1640346981Scy	{ "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL,
1641346981Scy	  "<addr> <ssid=> = remove AP from neighbor database" },
1642346981Scy	{ "req_lci", hostapd_cli_cmd_req_lci, hostapd_complete_stations,
1643346981Scy	  "<addr> = send LCI request to a station"},
1644346981Scy	{ "req_range", hostapd_cli_cmd_req_range, NULL,
1645346981Scy	  " = send FTM range request"},
1646346981Scy	{ "driver_flags", hostapd_cli_cmd_driver_flags, NULL,
1647346981Scy	  " = show supported driver flags"},
1648346981Scy#ifdef CONFIG_DPP
1649346981Scy	{ "dpp_qr_code", hostapd_cli_cmd_dpp_qr_code, NULL,
1650346981Scy	  "report a scanned DPP URI from a QR Code" },
1651346981Scy	{ "dpp_bootstrap_gen", hostapd_cli_cmd_dpp_bootstrap_gen, NULL,
1652346981Scy	  "type=<qrcode> [chan=..] [mac=..] [info=..] [curve=..] [key=..] = generate DPP bootstrap information" },
1653346981Scy	{ "dpp_bootstrap_remove", hostapd_cli_cmd_dpp_bootstrap_remove, NULL,
1654346981Scy	  "*|<id> = remove DPP bootstrap information" },
1655346981Scy	{ "dpp_bootstrap_get_uri", hostapd_cli_cmd_dpp_bootstrap_get_uri, NULL,
1656346981Scy	  "<id> = get DPP bootstrap URI" },
1657346981Scy	{ "dpp_bootstrap_info", hostapd_cli_cmd_dpp_bootstrap_info, NULL,
1658346981Scy	  "<id> = show DPP bootstrap information" },
1659346981Scy	{ "dpp_auth_init", hostapd_cli_cmd_dpp_auth_init, NULL,
1660346981Scy	  "peer=<id> [own=<id>] = initiate DPP bootstrapping" },
1661346981Scy	{ "dpp_listen", hostapd_cli_cmd_dpp_listen, NULL,
1662346981Scy	  "<freq in MHz> = start DPP listen" },
1663346981Scy	{ "dpp_stop_listen", hostapd_cli_cmd_dpp_stop_listen, NULL,
1664346981Scy	  "= stop DPP listen" },
1665346981Scy	{ "dpp_configurator_add", hostapd_cli_cmd_dpp_configurator_add, NULL,
1666346981Scy	  "[curve=..] [key=..] = add DPP configurator" },
1667346981Scy	{ "dpp_configurator_remove", hostapd_cli_cmd_dpp_configurator_remove,
1668346981Scy	  NULL,
1669346981Scy	  "*|<id> = remove DPP configurator" },
1670346981Scy	{ "dpp_configurator_get_key", hostapd_cli_cmd_dpp_configurator_get_key,
1671346981Scy	  NULL,
1672346981Scy	  "<id> = Get DPP configurator's private key" },
1673346981Scy	{ "dpp_configurator_sign", hostapd_cli_cmd_dpp_configurator_sign, NULL,
1674346981Scy	  "conf=<role> configurator=<id> = generate self DPP configuration" },
1675346981Scy	{ "dpp_pkex_add", hostapd_cli_cmd_dpp_pkex_add, NULL,
1676346981Scy	  "add PKEX code" },
1677346981Scy	{ "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL,
1678346981Scy	  "*|<id> = remove DPP pkex information" },
1679346981Scy#endif /* CONFIG_DPP */
1680346981Scy	{ "accept_acl", hostapd_cli_cmd_accept_macacl, NULL,
1681346981Scy	  "=Add/Delete/Show/Clear accept MAC ACL" },
1682346981Scy	{ "deny_acl", hostapd_cli_cmd_deny_macacl, NULL,
1683346981Scy	  "=Add/Delete/Show/Clear deny MAC ACL" },
1684346981Scy	{ "poll_sta", hostapd_cli_cmd_poll_sta, hostapd_complete_stations,
1685346981Scy	  "<addr> = poll a STA to check connectivity with a QoS null frame" },
1686346981Scy	{ "req_beacon", hostapd_cli_cmd_req_beacon, NULL,
1687346981Scy	  "<addr> [req_mode=] <measurement request hexdump>  = send a Beacon report request to a station" },
1688346981Scy	{ "reload_wpa_psk", hostapd_cli_cmd_reload_wpa_psk, NULL,
1689346981Scy	  "= reload wpa_psk_file only" },
1690337817Scy	{ NULL, NULL, NULL, NULL }
1691214503Srpaulo};
1692214503Srpaulo
1693214503Srpaulo
1694337817Scy/*
1695337817Scy * Prints command usage, lines are padded with the specified string.
1696337817Scy */
1697337817Scystatic void print_cmd_help(FILE *stream, const struct hostapd_cli_cmd *cmd,
1698337817Scy			   const char *pad)
1699337817Scy{
1700337817Scy	char c;
1701337817Scy	size_t n;
1702337817Scy
1703337817Scy	if (cmd->usage == NULL)
1704337817Scy		return;
1705337817Scy	fprintf(stream, "%s%s ", pad, cmd->cmd);
1706337817Scy	for (n = 0; (c = cmd->usage[n]); n++) {
1707337817Scy		fprintf(stream, "%c", c);
1708337817Scy		if (c == '\n')
1709337817Scy			fprintf(stream, "%s", pad);
1710337817Scy	}
1711337817Scy	fprintf(stream, "\n");
1712337817Scy}
1713337817Scy
1714337817Scy
1715337817Scystatic void print_help(FILE *stream, const char *cmd)
1716337817Scy{
1717337817Scy	int n;
1718337817Scy
1719337817Scy	fprintf(stream, "commands:\n");
1720337817Scy	for (n = 0; hostapd_cli_commands[n].cmd; n++) {
1721337817Scy		if (cmd == NULL || str_starts(hostapd_cli_commands[n].cmd, cmd))
1722337817Scy			print_cmd_help(stream, &hostapd_cli_commands[n], "  ");
1723337817Scy	}
1724337817Scy}
1725337817Scy
1726337817Scy
1727214503Srpaulostatic void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
1728214503Srpaulo{
1729289549Srpaulo	const struct hostapd_cli_cmd *cmd, *match = NULL;
1730214503Srpaulo	int count;
1731214503Srpaulo
1732214503Srpaulo	count = 0;
1733214503Srpaulo	cmd = hostapd_cli_commands;
1734214503Srpaulo	while (cmd->cmd) {
1735214503Srpaulo		if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
1736214503Srpaulo			match = cmd;
1737252726Srpaulo			if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1738252726Srpaulo				/* we have an exact match */
1739252726Srpaulo				count = 1;
1740252726Srpaulo				break;
1741252726Srpaulo			}
1742214503Srpaulo			count++;
1743214503Srpaulo		}
1744214503Srpaulo		cmd++;
1745214503Srpaulo	}
1746214503Srpaulo
1747214503Srpaulo	if (count > 1) {
1748214503Srpaulo		printf("Ambiguous command '%s'; possible commands:", argv[0]);
1749214503Srpaulo		cmd = hostapd_cli_commands;
1750214503Srpaulo		while (cmd->cmd) {
1751214503Srpaulo			if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
1752214503Srpaulo			    0) {
1753214503Srpaulo				printf(" %s", cmd->cmd);
1754214503Srpaulo			}
1755214503Srpaulo			cmd++;
1756214503Srpaulo		}
1757214503Srpaulo		printf("\n");
1758214503Srpaulo	} else if (count == 0) {
1759214503Srpaulo		printf("Unknown command '%s'\n", argv[0]);
1760214503Srpaulo	} else {
1761214503Srpaulo		match->handler(ctrl, argc - 1, &argv[1]);
1762214503Srpaulo	}
1763214503Srpaulo}
1764214503Srpaulo
1765214503Srpaulo
1766337817Scystatic void cli_event(const char *str)
1767337817Scy{
1768337817Scy	const char *start, *s;
1769337817Scy
1770337817Scy	start = os_strchr(str, '>');
1771337817Scy	if (start == NULL)
1772337817Scy		return;
1773337817Scy
1774337817Scy	start++;
1775337817Scy
1776337817Scy	if (str_starts(start, AP_STA_CONNECTED)) {
1777337817Scy		s = os_strchr(start, ' ');
1778337817Scy		if (s == NULL)
1779337817Scy			return;
1780337817Scy		cli_txt_list_add(&stations, s + 1);
1781337817Scy		return;
1782337817Scy	}
1783337817Scy
1784337817Scy	if (str_starts(start, AP_STA_DISCONNECTED)) {
1785337817Scy		s = os_strchr(start, ' ');
1786337817Scy		if (s == NULL)
1787337817Scy			return;
1788337817Scy		cli_txt_list_del_addr(&stations, s + 1);
1789337817Scy		return;
1790337817Scy	}
1791337817Scy}
1792337817Scy
1793337817Scy
1794214503Srpaulostatic void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
1795214503Srpaulo				     int action_monitor)
1796214503Srpaulo{
1797214503Srpaulo	int first = 1;
1798214503Srpaulo	if (ctrl_conn == NULL)
1799214503Srpaulo		return;
1800214503Srpaulo	while (wpa_ctrl_pending(ctrl)) {
1801346981Scy		char buf[4096];
1802214503Srpaulo		size_t len = sizeof(buf) - 1;
1803214503Srpaulo		if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
1804214503Srpaulo			buf[len] = '\0';
1805214503Srpaulo			if (action_monitor)
1806214503Srpaulo				hostapd_cli_action_process(buf, len);
1807214503Srpaulo			else {
1808337817Scy				cli_event(buf);
1809214503Srpaulo				if (in_read && first)
1810214503Srpaulo					printf("\n");
1811214503Srpaulo				first = 0;
1812214503Srpaulo				printf("%s\n", buf);
1813214503Srpaulo			}
1814214503Srpaulo		} else {
1815214503Srpaulo			printf("Could not read pending message.\n");
1816214503Srpaulo			break;
1817214503Srpaulo		}
1818214503Srpaulo	}
1819214503Srpaulo}
1820214503Srpaulo
1821214503Srpaulo
1822337817Scystatic void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx)
1823214503Srpaulo{
1824337817Scy	hostapd_cli_recv_pending(ctrl_conn, 0, 0);
1825214503Srpaulo}
1826214503Srpaulo
1827214503Srpaulo
1828252726Srpaulostatic void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
1829214503Srpaulo{
1830214503Srpaulo	if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
1831214503Srpaulo		printf("Connection to hostapd lost - trying to reconnect\n");
1832214503Srpaulo		hostapd_cli_close_connection();
1833214503Srpaulo	}
1834346981Scy	if (!ctrl_conn && hostapd_cli_reconnect(ctrl_ifname) == 0)
1835346981Scy		printf("Connection to hostapd re-established\n");
1836214503Srpaulo	if (ctrl_conn)
1837214503Srpaulo		hostapd_cli_recv_pending(ctrl_conn, 1, 0);
1838252726Srpaulo	eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1839214503Srpaulo}
1840214503Srpaulo
1841214503Srpaulo
1842252726Srpaulostatic void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
1843252726Srpaulo{
1844252726Srpaulo	eloop_terminate();
1845252726Srpaulo}
1846252726Srpaulo
1847252726Srpaulo
1848252726Srpaulostatic void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
1849252726Srpaulo{
1850252726Srpaulo	char *argv[max_args];
1851252726Srpaulo	int argc;
1852252726Srpaulo	argc = tokenize_cmd(cmd, argv);
1853252726Srpaulo	if (argc)
1854252726Srpaulo		wpa_request(ctrl_conn, argc, argv);
1855252726Srpaulo}
1856252726Srpaulo
1857252726Srpaulo
1858252726Srpaulostatic void hostapd_cli_edit_eof_cb(void *ctx)
1859252726Srpaulo{
1860252726Srpaulo	eloop_terminate();
1861252726Srpaulo}
1862252726Srpaulo
1863252726Srpaulo
1864337817Scystatic char ** list_cmd_list(void)
1865337817Scy{
1866337817Scy	char **res;
1867337817Scy	int i, count;
1868337817Scy
1869337817Scy	count = ARRAY_SIZE(hostapd_cli_commands);
1870337817Scy	res = os_calloc(count + 1, sizeof(char *));
1871337817Scy	if (res == NULL)
1872337817Scy		return NULL;
1873337817Scy
1874337817Scy	for (i = 0; hostapd_cli_commands[i].cmd; i++) {
1875337817Scy		res[i] = os_strdup(hostapd_cli_commands[i].cmd);
1876337817Scy		if (res[i] == NULL)
1877337817Scy			break;
1878337817Scy	}
1879337817Scy
1880337817Scy	return res;
1881337817Scy}
1882337817Scy
1883337817Scy
1884337817Scystatic char ** hostapd_cli_cmd_completion(const char *cmd, const char *str,
1885337817Scy				      int pos)
1886337817Scy{
1887337817Scy	int i;
1888337817Scy
1889337817Scy	for (i = 0; hostapd_cli_commands[i].cmd; i++) {
1890337817Scy		if (os_strcasecmp(hostapd_cli_commands[i].cmd, cmd) != 0)
1891337817Scy			continue;
1892337817Scy		if (hostapd_cli_commands[i].completion)
1893337817Scy			return hostapd_cli_commands[i].completion(str, pos);
1894337817Scy		if (!hostapd_cli_commands[i].usage)
1895337817Scy			return NULL;
1896337817Scy		edit_clear_line();
1897337817Scy		printf("\r%s\n", hostapd_cli_commands[i].usage);
1898337817Scy		edit_redraw();
1899337817Scy		break;
1900337817Scy	}
1901337817Scy
1902337817Scy	return NULL;
1903337817Scy}
1904337817Scy
1905337817Scy
1906337817Scystatic char ** hostapd_cli_edit_completion_cb(void *ctx, const char *str,
1907337817Scy					      int pos)
1908337817Scy{
1909337817Scy	char **res;
1910337817Scy	const char *end;
1911337817Scy	char *cmd;
1912337817Scy
1913337817Scy	end = os_strchr(str, ' ');
1914337817Scy	if (end == NULL || str + pos < end)
1915337817Scy		return list_cmd_list();
1916337817Scy
1917337817Scy	cmd = os_malloc(pos + 1);
1918337817Scy	if (cmd == NULL)
1919337817Scy		return NULL;
1920337817Scy	os_memcpy(cmd, str, pos);
1921337817Scy	cmd[end - str] = '\0';
1922337817Scy	res = hostapd_cli_cmd_completion(cmd, str, pos);
1923337817Scy	os_free(cmd);
1924337817Scy	return res;
1925337817Scy}
1926337817Scy
1927337817Scy
1928252726Srpaulostatic void hostapd_cli_interactive(void)
1929252726Srpaulo{
1930346981Scy	char *hfile = NULL;
1931346981Scy	char *home;
1932346981Scy
1933252726Srpaulo	printf("\nInteractive mode\n\n");
1934252726Srpaulo
1935346981Scy#ifdef CONFIG_HOSTAPD_CLI_HISTORY_DIR
1936346981Scy	home = CONFIG_HOSTAPD_CLI_HISTORY_DIR;
1937346981Scy#else /* CONFIG_HOSTAPD_CLI_HISTORY_DIR */
1938346981Scy	home = getenv("HOME");
1939346981Scy#endif /* CONFIG_HOSTAPD_CLI_HISTORY_DIR */
1940346981Scy	if (home) {
1941346981Scy		const char *fname = ".hostapd_cli_history";
1942346981Scy		int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
1943346981Scy		hfile = os_malloc(hfile_len);
1944346981Scy		if (hfile)
1945346981Scy			os_snprintf(hfile, hfile_len, "%s/%s", home, fname);
1946346981Scy	}
1947346981Scy
1948252726Srpaulo	eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
1949252726Srpaulo	edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
1950346981Scy		  hostapd_cli_edit_completion_cb, NULL, hfile, NULL);
1951252726Srpaulo	eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1952252726Srpaulo
1953252726Srpaulo	eloop_run();
1954252726Srpaulo
1955337817Scy	cli_txt_list_flush(&stations);
1956346981Scy	edit_deinit(hfile, NULL);
1957346981Scy	os_free(hfile);
1958252726Srpaulo	eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
1959252726Srpaulo}
1960252726Srpaulo
1961252726Srpaulo
1962252726Srpaulostatic void hostapd_cli_cleanup(void)
1963252726Srpaulo{
1964252726Srpaulo	hostapd_cli_close_connection();
1965252726Srpaulo	if (pid_file)
1966252726Srpaulo		os_daemonize_terminate(pid_file);
1967252726Srpaulo
1968252726Srpaulo	os_program_deinit();
1969252726Srpaulo}
1970252726Srpaulo
1971252726Srpaulo
1972214503Srpaulostatic void hostapd_cli_action(struct wpa_ctrl *ctrl)
1973214503Srpaulo{
1974214503Srpaulo	fd_set rfds;
1975214503Srpaulo	int fd, res;
1976214503Srpaulo	struct timeval tv;
1977214503Srpaulo	char buf[256];
1978214503Srpaulo	size_t len;
1979214503Srpaulo
1980214503Srpaulo	fd = wpa_ctrl_get_fd(ctrl);
1981214503Srpaulo
1982214503Srpaulo	while (!hostapd_cli_quit) {
1983214503Srpaulo		FD_ZERO(&rfds);
1984214503Srpaulo		FD_SET(fd, &rfds);
1985214503Srpaulo		tv.tv_sec = ping_interval;
1986214503Srpaulo		tv.tv_usec = 0;
1987214503Srpaulo		res = select(fd + 1, &rfds, NULL, NULL, &tv);
1988214503Srpaulo		if (res < 0 && errno != EINTR) {
1989214503Srpaulo			perror("select");
1990214503Srpaulo			break;
1991214503Srpaulo		}
1992214503Srpaulo
1993214503Srpaulo		if (FD_ISSET(fd, &rfds))
1994214503Srpaulo			hostapd_cli_recv_pending(ctrl, 0, 1);
1995214503Srpaulo		else {
1996214503Srpaulo			len = sizeof(buf) - 1;
1997214503Srpaulo			if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1998214503Srpaulo					     hostapd_cli_action_process) < 0 ||
1999214503Srpaulo			    len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
2000214503Srpaulo				printf("hostapd did not reply to PING "
2001214503Srpaulo				       "command - exiting\n");
2002214503Srpaulo				break;
2003214503Srpaulo			}
2004214503Srpaulo		}
2005214503Srpaulo	}
2006214503Srpaulo}
2007214503Srpaulo
2008214503Srpaulo
2009214503Srpauloint main(int argc, char *argv[])
2010214503Srpaulo{
2011214503Srpaulo	int warning_displayed = 0;
2012214503Srpaulo	int c;
2013214503Srpaulo	int daemonize = 0;
2014214503Srpaulo
2015214503Srpaulo	if (os_program_init())
2016214503Srpaulo		return -1;
2017214503Srpaulo
2018214503Srpaulo	for (;;) {
2019289549Srpaulo		c = getopt(argc, argv, "a:BhG:i:p:P:s:v");
2020214503Srpaulo		if (c < 0)
2021214503Srpaulo			break;
2022214503Srpaulo		switch (c) {
2023214503Srpaulo		case 'a':
2024214503Srpaulo			action_file = optarg;
2025214503Srpaulo			break;
2026214503Srpaulo		case 'B':
2027214503Srpaulo			daemonize = 1;
2028214503Srpaulo			break;
2029214503Srpaulo		case 'G':
2030214503Srpaulo			ping_interval = atoi(optarg);
2031214503Srpaulo			break;
2032214503Srpaulo		case 'h':
2033214503Srpaulo			usage();
2034214503Srpaulo			return 0;
2035214503Srpaulo		case 'v':
2036214503Srpaulo			printf("%s\n", hostapd_cli_version);
2037214503Srpaulo			return 0;
2038214503Srpaulo		case 'i':
2039214503Srpaulo			os_free(ctrl_ifname);
2040214503Srpaulo			ctrl_ifname = os_strdup(optarg);
2041214503Srpaulo			break;
2042214503Srpaulo		case 'p':
2043214503Srpaulo			ctrl_iface_dir = optarg;
2044214503Srpaulo			break;
2045289549Srpaulo		case 'P':
2046289549Srpaulo			pid_file = optarg;
2047289549Srpaulo			break;
2048289549Srpaulo		case 's':
2049289549Srpaulo			client_socket_dir = optarg;
2050289549Srpaulo			break;
2051214503Srpaulo		default:
2052214503Srpaulo			usage();
2053214503Srpaulo			return -1;
2054214503Srpaulo		}
2055214503Srpaulo	}
2056214503Srpaulo
2057214503Srpaulo	interactive = (argc == optind) && (action_file == NULL);
2058214503Srpaulo
2059214503Srpaulo	if (interactive) {
2060337817Scy		printf("%s\n\n%s\n\n", hostapd_cli_version, cli_license);
2061214503Srpaulo	}
2062214503Srpaulo
2063252726Srpaulo	if (eloop_init())
2064252726Srpaulo		return -1;
2065252726Srpaulo
2066214503Srpaulo	for (;;) {
2067214503Srpaulo		if (ctrl_ifname == NULL) {
2068214503Srpaulo			struct dirent *dent;
2069214503Srpaulo			DIR *dir = opendir(ctrl_iface_dir);
2070214503Srpaulo			if (dir) {
2071214503Srpaulo				while ((dent = readdir(dir))) {
2072214503Srpaulo					if (os_strcmp(dent->d_name, ".") == 0
2073214503Srpaulo					    ||
2074214503Srpaulo					    os_strcmp(dent->d_name, "..") == 0)
2075214503Srpaulo						continue;
2076214503Srpaulo					printf("Selected interface '%s'\n",
2077214503Srpaulo					       dent->d_name);
2078214503Srpaulo					ctrl_ifname = os_strdup(dent->d_name);
2079214503Srpaulo					break;
2080214503Srpaulo				}
2081214503Srpaulo				closedir(dir);
2082214503Srpaulo			}
2083214503Srpaulo		}
2084346981Scy		hostapd_cli_reconnect(ctrl_ifname);
2085214503Srpaulo		if (ctrl_conn) {
2086214503Srpaulo			if (warning_displayed)
2087214503Srpaulo				printf("Connection established.\n");
2088214503Srpaulo			break;
2089214503Srpaulo		}
2090214503Srpaulo
2091214503Srpaulo		if (!interactive) {
2092214503Srpaulo			perror("Failed to connect to hostapd - "
2093214503Srpaulo			       "wpa_ctrl_open");
2094214503Srpaulo			return -1;
2095214503Srpaulo		}
2096214503Srpaulo
2097214503Srpaulo		if (!warning_displayed) {
2098214503Srpaulo			printf("Could not connect to hostapd - re-trying\n");
2099214503Srpaulo			warning_displayed = 1;
2100214503Srpaulo		}
2101214503Srpaulo		os_sleep(1, 0);
2102214503Srpaulo		continue;
2103214503Srpaulo	}
2104214503Srpaulo
2105346981Scy	if (action_file && !hostapd_cli_attached)
2106346981Scy		return -1;
2107337817Scy	if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
2108214503Srpaulo		return -1;
2109214503Srpaulo
2110214503Srpaulo	if (interactive)
2111214503Srpaulo		hostapd_cli_interactive();
2112214503Srpaulo	else if (action_file)
2113214503Srpaulo		hostapd_cli_action(ctrl_conn);
2114214503Srpaulo	else
2115214503Srpaulo		wpa_request(ctrl_conn, argc - optind, &argv[optind]);
2116214503Srpaulo
2117337817Scy	unregister_event_handler(ctrl_conn);
2118214503Srpaulo	os_free(ctrl_ifname);
2119252726Srpaulo	eloop_destroy();
2120214503Srpaulo	hostapd_cli_cleanup();
2121214503Srpaulo	return 0;
2122214503Srpaulo}
2123337817Scy
2124337817Scy#else /* CONFIG_NO_CTRL_IFACE */
2125337817Scy
2126337817Scyint main(int argc, char *argv[])
2127337817Scy{
2128337817Scy	return -1;
2129337817Scy}
2130337817Scy
2131337817Scy#endif /* CONFIG_NO_CTRL_IFACE */
2132