wpa_cli.c revision 413dde71f7bc166de54229f337c24b61f4d909fd
1/*
2 * WPA Supplicant - command line interface for wpa_supplicant daemon
3 * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "includes.h"
10
11#ifdef CONFIG_CTRL_IFACE
12
13#ifdef CONFIG_CTRL_IFACE_UNIX
14#include <dirent.h>
15#endif /* CONFIG_CTRL_IFACE_UNIX */
16
17#include "common/wpa_ctrl.h"
18#include "utils/common.h"
19#include "utils/eloop.h"
20#include "utils/edit.h"
21#include "utils/list.h"
22#include "common/version.h"
23#include "common/ieee802_11_defs.h"
24#ifdef ANDROID
25#include <cutils/properties.h>
26#endif /* ANDROID */
27
28
29static const char *wpa_cli_version =
30"wpa_cli v" VERSION_STR "\n"
31"Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> and contributors";
32
33
34static const char *wpa_cli_license =
35"This software may be distributed under the terms of the BSD license.\n"
36"See README for more details.\n";
37
38static const char *wpa_cli_full_license =
39"This software may be distributed under the terms of the BSD license.\n"
40"\n"
41"Redistribution and use in source and binary forms, with or without\n"
42"modification, are permitted provided that the following conditions are\n"
43"met:\n"
44"\n"
45"1. Redistributions of source code must retain the above copyright\n"
46"   notice, this list of conditions and the following disclaimer.\n"
47"\n"
48"2. Redistributions in binary form must reproduce the above copyright\n"
49"   notice, this list of conditions and the following disclaimer in the\n"
50"   documentation and/or other materials provided with the distribution.\n"
51"\n"
52"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
53"   names of its contributors may be used to endorse or promote products\n"
54"   derived from this software without specific prior written permission.\n"
55"\n"
56"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
57"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
58"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
59"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
60"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
61"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
62"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
63"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
64"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
65"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
66"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
67"\n";
68
69static struct wpa_ctrl *ctrl_conn;
70static struct wpa_ctrl *mon_conn;
71static int wpa_cli_quit = 0;
72static int wpa_cli_attached = 0;
73static int wpa_cli_connected = -1;
74static int wpa_cli_last_id = 0;
75#ifndef CONFIG_CTRL_IFACE_DIR
76#define CONFIG_CTRL_IFACE_DIR "/var/run/wpa_supplicant"
77#endif /* CONFIG_CTRL_IFACE_DIR */
78static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
79static char *ctrl_ifname = NULL;
80static const char *pid_file = NULL;
81static const char *action_file = NULL;
82static int ping_interval = 5;
83static int interactive = 0;
84static char *ifname_prefix = NULL;
85
86struct cli_txt_entry {
87	struct dl_list list;
88	char *txt;
89};
90
91static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */
92static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */
93static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */
94static DEFINE_DL_LIST(ifnames); /* struct cli_txt_entry */
95
96
97static void print_help(const char *cmd);
98static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx);
99static void wpa_cli_close_connection(void);
100static char * wpa_cli_get_default_ifname(void);
101static char ** wpa_list_cmd_list(void);
102
103
104static void usage(void)
105{
106	printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] "
107	       "[-a<action file>] \\\n"
108	       "        [-P<pid file>] [-g<global ctrl>] [-G<ping interval>]  "
109	       "[command..]\n"
110	       "  -h = help (show this usage text)\n"
111	       "  -v = shown version information\n"
112	       "  -a = run in daemon mode executing the action file based on "
113	       "events from\n"
114	       "       wpa_supplicant\n"
115	       "  -B = run a daemon in the background\n"
116	       "  default path: " CONFIG_CTRL_IFACE_DIR "\n"
117	       "  default interface: first interface found in socket path\n");
118	print_help(NULL);
119}
120
121
122static void cli_txt_list_free(struct cli_txt_entry *e)
123{
124	dl_list_del(&e->list);
125	os_free(e->txt);
126	os_free(e);
127}
128
129
130static void cli_txt_list_flush(struct dl_list *list)
131{
132	struct cli_txt_entry *e;
133	while ((e = dl_list_first(list, struct cli_txt_entry, list)))
134		cli_txt_list_free(e);
135}
136
137
138static struct cli_txt_entry * cli_txt_list_get(struct dl_list *txt_list,
139					       const char *txt)
140{
141	struct cli_txt_entry *e;
142	dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
143		if (os_strcmp(e->txt, txt) == 0)
144			return e;
145	}
146	return NULL;
147}
148
149
150static void cli_txt_list_del(struct dl_list *txt_list, const char *txt)
151{
152	struct cli_txt_entry *e;
153	e = cli_txt_list_get(txt_list, txt);
154	if (e)
155		cli_txt_list_free(e);
156}
157
158
159static void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt)
160{
161	u8 addr[ETH_ALEN];
162	char buf[18];
163	if (hwaddr_aton(txt, addr) < 0)
164		return;
165	os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
166	cli_txt_list_del(txt_list, buf);
167}
168
169
170#ifdef CONFIG_P2P
171static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt)
172{
173	const char *end;
174	char *buf;
175	end = os_strchr(txt, ' ');
176	if (end == NULL)
177		end = txt + os_strlen(txt);
178	buf = dup_binstr(txt, end - txt);
179	if (buf == NULL)
180		return;
181	cli_txt_list_del(txt_list, buf);
182	os_free(buf);
183}
184#endif /* CONFIG_P2P */
185
186
187static int cli_txt_list_add(struct dl_list *txt_list, const char *txt)
188{
189	struct cli_txt_entry *e;
190	e = cli_txt_list_get(txt_list, txt);
191	if (e)
192		return 0;
193	e = os_zalloc(sizeof(*e));
194	if (e == NULL)
195		return -1;
196	e->txt = os_strdup(txt);
197	if (e->txt == NULL) {
198		os_free(e);
199		return -1;
200	}
201	dl_list_add(txt_list, &e->list);
202	return 0;
203}
204
205
206#ifdef CONFIG_P2P
207static int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt)
208{
209	u8 addr[ETH_ALEN];
210	char buf[18];
211	if (hwaddr_aton(txt, addr) < 0)
212		return -1;
213	os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
214	return cli_txt_list_add(txt_list, buf);
215}
216
217
218static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt)
219{
220	const char *end;
221	char *buf;
222	int ret;
223	end = os_strchr(txt, ' ');
224	if (end == NULL)
225		end = txt + os_strlen(txt);
226	buf = dup_binstr(txt, end - txt);
227	if (buf == NULL)
228		return -1;
229	ret = cli_txt_list_add(txt_list, buf);
230	os_free(buf);
231	return ret;
232}
233#endif /* CONFIG_P2P */
234
235
236static char ** cli_txt_list_array(struct dl_list *txt_list)
237{
238	unsigned int i, count = dl_list_len(txt_list);
239	char **res;
240	struct cli_txt_entry *e;
241
242	res = os_calloc(count + 1, sizeof(char *));
243	if (res == NULL)
244		return NULL;
245
246	i = 0;
247	dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
248		res[i] = os_strdup(e->txt);
249		if (res[i] == NULL)
250			break;
251		i++;
252	}
253
254	return res;
255}
256
257
258static int get_cmd_arg_num(const char *str, int pos)
259{
260	int arg = 0, i;
261
262	for (i = 0; i <= pos; i++) {
263		if (str[i] != ' ') {
264			arg++;
265			while (i <= pos && str[i] != ' ')
266				i++;
267		}
268	}
269
270	if (arg > 0)
271		arg--;
272	return arg;
273}
274
275
276static int str_starts(const char *src, const char *match)
277{
278	return os_strncmp(src, match, os_strlen(match)) == 0;
279}
280
281
282static int wpa_cli_show_event(const char *event)
283{
284	const char *start;
285
286	start = os_strchr(event, '>');
287	if (start == NULL)
288		return 1;
289
290	start++;
291	/*
292	 * Skip BSS added/removed events since they can be relatively frequent
293	 * and are likely of not much use for an interactive user.
294	 */
295	if (str_starts(start, WPA_EVENT_BSS_ADDED) ||
296	    str_starts(start, WPA_EVENT_BSS_REMOVED))
297		return 0;
298
299	return 1;
300}
301
302
303static int wpa_cli_open_connection(const char *ifname, int attach)
304{
305#if defined(CONFIG_CTRL_IFACE_UDP) || defined(CONFIG_CTRL_IFACE_NAMED_PIPE)
306	ctrl_conn = wpa_ctrl_open(ifname);
307	if (ctrl_conn == NULL)
308		return -1;
309
310	if (attach && interactive)
311		mon_conn = wpa_ctrl_open(ifname);
312	else
313		mon_conn = NULL;
314#else /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
315	char *cfile = NULL;
316	int flen, res;
317
318	if (ifname == NULL)
319		return -1;
320
321#ifdef ANDROID
322	if (access(ctrl_iface_dir, F_OK) < 0) {
323		cfile = os_strdup(ifname);
324		if (cfile == NULL)
325			return -1;
326	}
327#endif /* ANDROID */
328
329	if (cfile == NULL) {
330		flen = os_strlen(ctrl_iface_dir) + os_strlen(ifname) + 2;
331		cfile = os_malloc(flen);
332		if (cfile == NULL)
333			return -1;
334		res = os_snprintf(cfile, flen, "%s/%s", ctrl_iface_dir,
335				  ifname);
336		if (res < 0 || res >= flen) {
337			os_free(cfile);
338			return -1;
339		}
340	}
341
342	ctrl_conn = wpa_ctrl_open(cfile);
343	if (ctrl_conn == NULL) {
344		os_free(cfile);
345		return -1;
346	}
347
348	if (attach && interactive)
349		mon_conn = wpa_ctrl_open(cfile);
350	else
351		mon_conn = NULL;
352	os_free(cfile);
353#endif /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
354
355	if (mon_conn) {
356		if (wpa_ctrl_attach(mon_conn) == 0) {
357			wpa_cli_attached = 1;
358			if (interactive)
359				eloop_register_read_sock(
360					wpa_ctrl_get_fd(mon_conn),
361					wpa_cli_mon_receive, NULL, NULL);
362		} else {
363			printf("Warning: Failed to attach to "
364			       "wpa_supplicant.\n");
365			wpa_cli_close_connection();
366			return -1;
367		}
368	}
369
370	return 0;
371}
372
373
374static void wpa_cli_close_connection(void)
375{
376	if (ctrl_conn == NULL)
377		return;
378
379	if (wpa_cli_attached) {
380		wpa_ctrl_detach(interactive ? mon_conn : ctrl_conn);
381		wpa_cli_attached = 0;
382	}
383	wpa_ctrl_close(ctrl_conn);
384	ctrl_conn = NULL;
385	if (mon_conn) {
386		eloop_unregister_read_sock(wpa_ctrl_get_fd(mon_conn));
387		wpa_ctrl_close(mon_conn);
388		mon_conn = NULL;
389	}
390}
391
392
393static void wpa_cli_msg_cb(char *msg, size_t len)
394{
395	printf("%s\n", msg);
396}
397
398
399static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
400{
401	char buf[4096];
402	size_t len;
403	int ret;
404
405	if (ctrl_conn == NULL) {
406		printf("Not connected to wpa_supplicant - command dropped.\n");
407		return -1;
408	}
409	if (ifname_prefix) {
410		os_snprintf(buf, sizeof(buf), "IFNAME=%s %s",
411			    ifname_prefix, cmd);
412		buf[sizeof(buf) - 1] = '\0';
413		cmd = buf;
414	}
415	len = sizeof(buf) - 1;
416	ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
417			       wpa_cli_msg_cb);
418	if (ret == -2) {
419		printf("'%s' command timed out.\n", cmd);
420		return -2;
421	} else if (ret < 0) {
422		printf("'%s' command failed.\n", cmd);
423		return -1;
424	}
425	if (print) {
426		buf[len] = '\0';
427		printf("%s", buf);
428		if (interactive && len > 0 && buf[len - 1] != '\n')
429			printf("\n");
430	}
431	return 0;
432}
433
434
435static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
436{
437	return _wpa_ctrl_command(ctrl, cmd, 1);
438}
439
440
441static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
442		     char *argv[])
443{
444	int i, res;
445	char *pos, *end;
446
447	pos = buf;
448	end = buf + buflen;
449
450	res = os_snprintf(pos, end - pos, "%s", cmd);
451	if (res < 0 || res >= end - pos)
452		goto fail;
453	pos += res;
454
455	for (i = 0; i < argc; i++) {
456		res = os_snprintf(pos, end - pos, " %s", argv[i]);
457		if (res < 0 || res >= end - pos)
458			goto fail;
459		pos += res;
460	}
461
462	buf[buflen - 1] = '\0';
463	return 0;
464
465fail:
466	printf("Too long command\n");
467	return -1;
468}
469
470
471static int wpa_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd, int min_args,
472		       int argc, char *argv[])
473{
474	char buf[4096];
475	if (argc < min_args) {
476		printf("Invalid %s command - at least %d argument%s "
477		       "required.\n", cmd, min_args,
478		       min_args > 1 ? "s are" : " is");
479		return -1;
480	}
481	if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0)
482		return -1;
483	return wpa_ctrl_command(ctrl, buf);
484}
485
486
487static int wpa_cli_cmd_ifname(struct wpa_ctrl *ctrl, int argc, char *argv[])
488{
489	return wpa_ctrl_command(ctrl, "IFNAME");
490}
491
492
493static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
494{
495	if (argc > 0 && os_strcmp(argv[0], "verbose") == 0)
496		return wpa_ctrl_command(ctrl, "STATUS-VERBOSE");
497	if (argc > 0 && os_strcmp(argv[0], "wps") == 0)
498		return wpa_ctrl_command(ctrl, "STATUS-WPS");
499	if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
500		return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
501	return wpa_ctrl_command(ctrl, "STATUS");
502}
503
504
505static int wpa_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
506{
507	return wpa_ctrl_command(ctrl, "PING");
508}
509
510
511static int wpa_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
512{
513	return wpa_ctrl_command(ctrl, "RELOG");
514}
515
516
517static int wpa_cli_cmd_note(struct wpa_ctrl *ctrl, int argc, char *argv[])
518{
519	return wpa_cli_cmd(ctrl, "NOTE", 1, argc, argv);
520}
521
522
523static int wpa_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
524{
525	return wpa_ctrl_command(ctrl, "MIB");
526}
527
528
529static int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
530{
531	return wpa_ctrl_command(ctrl, "PMKSA");
532}
533
534
535static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
536{
537	print_help(argc > 0 ? argv[0] : NULL);
538	return 0;
539}
540
541
542static char ** wpa_cli_complete_help(const char *str, int pos)
543{
544	int arg = get_cmd_arg_num(str, pos);
545	char **res = NULL;
546
547	switch (arg) {
548	case 1:
549		res = wpa_list_cmd_list();
550		break;
551	}
552
553	return res;
554}
555
556
557static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[])
558{
559	printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license);
560	return 0;
561}
562
563
564static int wpa_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
565{
566	wpa_cli_quit = 1;
567	if (interactive)
568		eloop_terminate();
569	return 0;
570}
571
572
573static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
574{
575	char cmd[256];
576	int res;
577
578	if (argc == 1) {
579		res = os_snprintf(cmd, sizeof(cmd), "SET %s ", argv[0]);
580		if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
581			printf("Too long SET command.\n");
582			return -1;
583		}
584		return wpa_ctrl_command(ctrl, cmd);
585	}
586
587	return wpa_cli_cmd(ctrl, "SET", 2, argc, argv);
588}
589
590
591static char ** wpa_cli_complete_set(const char *str, int pos)
592{
593	int arg = get_cmd_arg_num(str, pos);
594	const char *fields[] = {
595		/* runtime values */
596		"EAPOL::heldPeriod", "EAPOL::authPeriod", "EAPOL::startPeriod",
597		"EAPOL::maxStart", "dot11RSNAConfigPMKLifetime",
598		"dot11RSNAConfigPMKReauthThreshold", "dot11RSNAConfigSATimeout",
599		"wps_fragment_size", "wps_version_number", "ampdu",
600		"tdls_testing", "tdls_disabled", "pno", "radio_disabled",
601		"uapsd", "ps", "wifi_display", "bssid_filter", "disallow_aps",
602		"no_keep_alive",
603		/* global configuration parameters */
604		"eapol_version", "ap_scan", "disable_scan_offload",
605		"fast_reauth", "opensc_engine_path", "pkcs11_engine_path",
606		"pkcs11_module_path", "pcsc_reader", "pcsc_pin",
607		"driver_param", "dot11RSNAConfigPMKLifetime",
608		"dot11RSNAConfigPMKReauthThreshold",
609		"dot11RSNAConfigSATimeout",
610		"update_config", "load_dynamic_eap", "uuid", "device_name",
611		"manufacturer", "model_name", "model_number", "serial_number",
612		"device_type", "os_version", "config_methods",
613		"wps_cred_processing", "wps_vendor_ext_m1", "sec_device_type",
614		"p2p_listen_reg_class", "p2p_listen_channel",
615		"p2p_oper_reg_class", "p2p_oper_channel",
616		"p2p_go_intent", "p2p_ssid_postfix", "persistent_reconnect",
617		"p2p_intra_bss", "p2p_group_idle", "p2p_pref_chan",
618		"p2p_no_go_freq",
619		"p2p_go_ht40", "p2p_disabled", "p2p_no_group_iface",
620		"p2p_go_vht",
621		"p2p_ignore_shared_freq", "country", "bss_max_count",
622		"bss_expiration_age", "bss_expiration_scan_count",
623		"filter_ssids", "filter_rssi", "max_num_sta",
624		"disassoc_low_ack", "hs20", "interworking", "hessid",
625		"access_network_type", "pbc_in_m1", "autoscan",
626		"wps_nfc_dev_pw_id", "wps_nfc_dh_pubkey", "wps_nfc_dh_privkey",
627		"wps_nfc_dev_pw", "ext_password_backend",
628		"p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
629		"sae_groups", "dtim_period", "beacon_int", "ap_vendor_elements",
630		"ignore_old_scan_res", "freq_list", "external_sim",
631		"tdls_external_control"
632	};
633	int i, num_fields = ARRAY_SIZE(fields);
634
635	if (arg == 1) {
636		char **res = os_calloc(num_fields + 1, sizeof(char *));
637		if (res == NULL)
638			return NULL;
639		for (i = 0; i < num_fields; i++) {
640			res[i] = os_strdup(fields[i]);
641			if (res[i] == NULL)
642				return res;
643		}
644		return res;
645	}
646
647	if (arg > 1 && os_strncasecmp(str, "set bssid_filter ", 17) == 0)
648		return cli_txt_list_array(&bsses);
649
650	return NULL;
651}
652
653
654static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
655{
656	return wpa_cli_cmd(ctrl, "GET", 1, argc, argv);
657}
658
659
660static int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[])
661{
662	return wpa_ctrl_command(ctrl, "LOGOFF");
663}
664
665
666static int wpa_cli_cmd_logon(struct wpa_ctrl *ctrl, int argc, char *argv[])
667{
668	return wpa_ctrl_command(ctrl, "LOGON");
669}
670
671
672static int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc,
673				   char *argv[])
674{
675	return wpa_ctrl_command(ctrl, "REASSOCIATE");
676}
677
678
679static int wpa_cli_cmd_reattach(struct wpa_ctrl *ctrl, int argc, char *argv[])
680{
681	return wpa_ctrl_command(ctrl, "REATTACH");
682}
683
684
685static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc,
686				       char *argv[])
687{
688	return wpa_cli_cmd(ctrl, "PREAUTH", 1, argc, argv);
689}
690
691
692static int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
693{
694	return wpa_cli_cmd(ctrl, "AP_SCAN", 1, argc, argv);
695}
696
697
698static int wpa_cli_cmd_scan_interval(struct wpa_ctrl *ctrl, int argc,
699				     char *argv[])
700{
701	return wpa_cli_cmd(ctrl, "SCAN_INTERVAL", 1, argc, argv);
702}
703
704
705static int wpa_cli_cmd_bss_expire_age(struct wpa_ctrl *ctrl, int argc,
706				      char *argv[])
707{
708	return wpa_cli_cmd(ctrl, "BSS_EXPIRE_AGE", 1, argc, argv);
709}
710
711
712static int wpa_cli_cmd_bss_expire_count(struct wpa_ctrl *ctrl, int argc,
713				        char *argv[])
714{
715	return wpa_cli_cmd(ctrl, "BSS_EXPIRE_COUNT", 1, argc, argv);
716}
717
718
719static int wpa_cli_cmd_bss_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
720{
721	char cmd[256];
722	int res;
723
724	if (argc < 1)
725		res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH 0");
726	else
727		res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH %s", argv[0]);
728	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
729		printf("Too long BSS_FLUSH command.\n");
730		return -1;
731	}
732	return wpa_ctrl_command(ctrl, cmd);
733}
734
735
736static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc,
737				char *argv[])
738{
739	return wpa_cli_cmd(ctrl, "STKSTART", 1, argc, argv);
740}
741
742
743static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[])
744{
745	return wpa_cli_cmd(ctrl, "FT_DS", 1, argc, argv);
746}
747
748
749static int wpa_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[])
750{
751	return wpa_cli_cmd(ctrl, "WPS_PBC", 0, argc, argv);
752}
753
754
755static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
756{
757	if (argc == 0) {
758		printf("Invalid WPS_PIN command: need one or two arguments:\n"
759		       "- BSSID: use 'any' to select any\n"
760		       "- PIN: optional, used only with devices that have no "
761		       "display\n");
762		return -1;
763	}
764
765	return wpa_cli_cmd(ctrl, "WPS_PIN", 1, argc, argv);
766}
767
768
769static int wpa_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
770				     char *argv[])
771{
772	return wpa_cli_cmd(ctrl, "WPS_CHECK_PIN", 1, argc, argv);
773}
774
775
776static int wpa_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
777				  char *argv[])
778{
779	return wpa_ctrl_command(ctrl, "WPS_CANCEL");
780}
781
782
783#ifdef CONFIG_WPS_NFC
784
785static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[])
786{
787	return wpa_cli_cmd(ctrl, "WPS_NFC", 0, argc, argv);
788}
789
790
791static int wpa_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl, int argc,
792					    char *argv[])
793{
794	return wpa_cli_cmd(ctrl, "WPS_NFC_CONFIG_TOKEN", 1, argc, argv);
795}
796
797
798static int wpa_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, int argc,
799				     char *argv[])
800{
801	return wpa_cli_cmd(ctrl, "WPS_NFC_TOKEN", 1, argc, argv);
802}
803
804
805static int wpa_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
806					char *argv[])
807{
808	int ret;
809	char *buf;
810	size_t buflen;
811
812	if (argc != 1) {
813		printf("Invalid 'wps_nfc_tag_read' command - one argument "
814		       "is required.\n");
815		return -1;
816	}
817
818	buflen = 18 + os_strlen(argv[0]);
819	buf = os_malloc(buflen);
820	if (buf == NULL)
821		return -1;
822	os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
823
824	ret = wpa_ctrl_command(ctrl, buf);
825	os_free(buf);
826
827	return ret;
828}
829
830
831static int wpa_cli_cmd_nfc_get_handover_req(struct wpa_ctrl *ctrl, int argc,
832					    char *argv[])
833{
834	return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_REQ", 2, argc, argv);
835}
836
837
838static int wpa_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl, int argc,
839					    char *argv[])
840{
841	return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_SEL", 2, argc, argv);
842}
843
844
845static int wpa_cli_cmd_nfc_report_handover(struct wpa_ctrl *ctrl, int argc,
846					   char *argv[])
847{
848	return wpa_cli_cmd(ctrl, "NFC_REPORT_HANDOVER", 4, argc, argv);
849}
850
851#endif /* CONFIG_WPS_NFC */
852
853
854static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
855{
856	char cmd[256];
857	int res;
858
859	if (argc == 2)
860		res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s",
861				  argv[0], argv[1]);
862	else if (argc == 5 || argc == 6) {
863		char ssid_hex[2 * 32 + 1];
864		char key_hex[2 * 64 + 1];
865		int i;
866
867		ssid_hex[0] = '\0';
868		for (i = 0; i < 32; i++) {
869			if (argv[2][i] == '\0')
870				break;
871			os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]);
872		}
873
874		key_hex[0] = '\0';
875		if (argc == 6) {
876			for (i = 0; i < 64; i++) {
877				if (argv[5][i] == '\0')
878					break;
879				os_snprintf(&key_hex[i * 2], 3, "%02x",
880					    argv[5][i]);
881			}
882		}
883
884		res = os_snprintf(cmd, sizeof(cmd),
885				  "WPS_REG %s %s %s %s %s %s",
886				  argv[0], argv[1], ssid_hex, argv[3], argv[4],
887				  key_hex);
888	} else {
889		printf("Invalid WPS_REG command: need two arguments:\n"
890		       "- BSSID of the target AP\n"
891		       "- AP PIN\n");
892		printf("Alternatively, six arguments can be used to "
893		       "reconfigure the AP:\n"
894		       "- BSSID of the target AP\n"
895		       "- AP PIN\n"
896		       "- new SSID\n"
897		       "- new auth (OPEN, WPAPSK, WPA2PSK)\n"
898		       "- new encr (NONE, WEP, TKIP, CCMP)\n"
899		       "- new key\n");
900		return -1;
901	}
902
903	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
904		printf("Too long WPS_REG command.\n");
905		return -1;
906	}
907	return wpa_ctrl_command(ctrl, cmd);
908}
909
910
911static int wpa_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
912				  char *argv[])
913{
914	return wpa_cli_cmd(ctrl, "WPS_AP_PIN", 1, argc, argv);
915}
916
917
918static int wpa_cli_cmd_wps_er_start(struct wpa_ctrl *ctrl, int argc,
919				    char *argv[])
920{
921	return wpa_cli_cmd(ctrl, "WPS_ER_START", 0, argc, argv);
922}
923
924
925static int wpa_cli_cmd_wps_er_stop(struct wpa_ctrl *ctrl, int argc,
926				   char *argv[])
927{
928	return wpa_ctrl_command(ctrl, "WPS_ER_STOP");
929
930}
931
932
933static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc,
934				  char *argv[])
935{
936	if (argc < 2) {
937		printf("Invalid WPS_ER_PIN command: need at least two "
938		       "arguments:\n"
939		       "- UUID: use 'any' to select any\n"
940		       "- PIN: Enrollee PIN\n"
941		       "optional: - Enrollee MAC address\n");
942		return -1;
943	}
944
945	return wpa_cli_cmd(ctrl, "WPS_ER_PIN", 2, argc, argv);
946}
947
948
949static int wpa_cli_cmd_wps_er_pbc(struct wpa_ctrl *ctrl, int argc,
950				  char *argv[])
951{
952	return wpa_cli_cmd(ctrl, "WPS_ER_PBC", 1, argc, argv);
953}
954
955
956static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc,
957				    char *argv[])
958{
959	if (argc != 2) {
960		printf("Invalid WPS_ER_LEARN command: need two arguments:\n"
961		       "- UUID: specify which AP to use\n"
962		       "- PIN: AP PIN\n");
963		return -1;
964	}
965
966	return wpa_cli_cmd(ctrl, "WPS_ER_LEARN", 2, argc, argv);
967}
968
969
970static int wpa_cli_cmd_wps_er_set_config(struct wpa_ctrl *ctrl, int argc,
971					 char *argv[])
972{
973	if (argc != 2) {
974		printf("Invalid WPS_ER_SET_CONFIG command: need two "
975		       "arguments:\n"
976		       "- UUID: specify which AP to use\n"
977		       "- Network configuration id\n");
978		return -1;
979	}
980
981	return wpa_cli_cmd(ctrl, "WPS_ER_SET_CONFIG", 2, argc, argv);
982}
983
984
985static int wpa_cli_cmd_wps_er_config(struct wpa_ctrl *ctrl, int argc,
986				     char *argv[])
987{
988	char cmd[256];
989	int res;
990
991	if (argc == 5 || argc == 6) {
992		char ssid_hex[2 * 32 + 1];
993		char key_hex[2 * 64 + 1];
994		int i;
995
996		ssid_hex[0] = '\0';
997		for (i = 0; i < 32; i++) {
998			if (argv[2][i] == '\0')
999				break;
1000			os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]);
1001		}
1002
1003		key_hex[0] = '\0';
1004		if (argc == 6) {
1005			for (i = 0; i < 64; i++) {
1006				if (argv[5][i] == '\0')
1007					break;
1008				os_snprintf(&key_hex[i * 2], 3, "%02x",
1009					    argv[5][i]);
1010			}
1011		}
1012
1013		res = os_snprintf(cmd, sizeof(cmd),
1014				  "WPS_ER_CONFIG %s %s %s %s %s %s",
1015				  argv[0], argv[1], ssid_hex, argv[3], argv[4],
1016				  key_hex);
1017	} else {
1018		printf("Invalid WPS_ER_CONFIG command: need six arguments:\n"
1019		       "- AP UUID\n"
1020		       "- AP PIN\n"
1021		       "- new SSID\n"
1022		       "- new auth (OPEN, WPAPSK, WPA2PSK)\n"
1023		       "- new encr (NONE, WEP, TKIP, CCMP)\n"
1024		       "- new key\n");
1025		return -1;
1026	}
1027
1028	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
1029		printf("Too long WPS_ER_CONFIG command.\n");
1030		return -1;
1031	}
1032	return wpa_ctrl_command(ctrl, cmd);
1033}
1034
1035
1036#ifdef CONFIG_WPS_NFC
1037static int wpa_cli_cmd_wps_er_nfc_config_token(struct wpa_ctrl *ctrl, int argc,
1038					       char *argv[])
1039{
1040	if (argc != 2) {
1041		printf("Invalid WPS_ER_NFC_CONFIG_TOKEN command: need two "
1042		       "arguments:\n"
1043		       "- WPS/NDEF: token format\n"
1044		       "- UUID: specify which AP to use\n");
1045		return -1;
1046	}
1047
1048	return wpa_cli_cmd(ctrl, "WPS_ER_NFC_CONFIG_TOKEN", 2, argc, argv);
1049}
1050#endif /* CONFIG_WPS_NFC */
1051
1052
1053static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[])
1054{
1055	return wpa_cli_cmd(ctrl, "IBSS_RSN", 1, argc, argv);
1056}
1057
1058
1059static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
1060{
1061	return wpa_cli_cmd(ctrl, "LEVEL", 1, argc, argv);
1062}
1063
1064
1065static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[])
1066{
1067	char cmd[256], *pos, *end;
1068	int i, ret;
1069
1070	if (argc < 2) {
1071		printf("Invalid IDENTITY command: needs two arguments "
1072		       "(network id and identity)\n");
1073		return -1;
1074	}
1075
1076	end = cmd + sizeof(cmd);
1077	pos = cmd;
1078	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s",
1079			  argv[0], argv[1]);
1080	if (ret < 0 || ret >= end - pos) {
1081		printf("Too long IDENTITY command.\n");
1082		return -1;
1083	}
1084	pos += ret;
1085	for (i = 2; i < argc; i++) {
1086		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
1087		if (ret < 0 || ret >= end - pos) {
1088			printf("Too long IDENTITY command.\n");
1089			return -1;
1090		}
1091		pos += ret;
1092	}
1093
1094	return wpa_ctrl_command(ctrl, cmd);
1095}
1096
1097
1098static int wpa_cli_cmd_password(struct wpa_ctrl *ctrl, int argc, char *argv[])
1099{
1100	char cmd[256], *pos, *end;
1101	int i, ret;
1102
1103	if (argc < 2) {
1104		printf("Invalid PASSWORD command: needs two arguments "
1105		       "(network id and password)\n");
1106		return -1;
1107	}
1108
1109	end = cmd + sizeof(cmd);
1110	pos = cmd;
1111	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s",
1112			  argv[0], argv[1]);
1113	if (ret < 0 || ret >= end - pos) {
1114		printf("Too long PASSWORD command.\n");
1115		return -1;
1116	}
1117	pos += ret;
1118	for (i = 2; i < argc; i++) {
1119		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
1120		if (ret < 0 || ret >= end - pos) {
1121			printf("Too long PASSWORD command.\n");
1122			return -1;
1123		}
1124		pos += ret;
1125	}
1126
1127	return wpa_ctrl_command(ctrl, cmd);
1128}
1129
1130
1131static int wpa_cli_cmd_new_password(struct wpa_ctrl *ctrl, int argc,
1132				    char *argv[])
1133{
1134	char cmd[256], *pos, *end;
1135	int i, ret;
1136
1137	if (argc < 2) {
1138		printf("Invalid NEW_PASSWORD command: needs two arguments "
1139		       "(network id and password)\n");
1140		return -1;
1141	}
1142
1143	end = cmd + sizeof(cmd);
1144	pos = cmd;
1145	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s",
1146			  argv[0], argv[1]);
1147	if (ret < 0 || ret >= end - pos) {
1148		printf("Too long NEW_PASSWORD command.\n");
1149		return -1;
1150	}
1151	pos += ret;
1152	for (i = 2; i < argc; i++) {
1153		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
1154		if (ret < 0 || ret >= end - pos) {
1155			printf("Too long NEW_PASSWORD command.\n");
1156			return -1;
1157		}
1158		pos += ret;
1159	}
1160
1161	return wpa_ctrl_command(ctrl, cmd);
1162}
1163
1164
1165static int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
1166{
1167	char cmd[256], *pos, *end;
1168	int i, ret;
1169
1170	if (argc < 2) {
1171		printf("Invalid PIN command: needs two arguments "
1172		       "(network id and pin)\n");
1173		return -1;
1174	}
1175
1176	end = cmd + sizeof(cmd);
1177	pos = cmd;
1178	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s",
1179			  argv[0], argv[1]);
1180	if (ret < 0 || ret >= end - pos) {
1181		printf("Too long PIN command.\n");
1182		return -1;
1183	}
1184	pos += ret;
1185	for (i = 2; i < argc; i++) {
1186		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
1187		if (ret < 0 || ret >= end - pos) {
1188			printf("Too long PIN command.\n");
1189			return -1;
1190		}
1191		pos += ret;
1192	}
1193	return wpa_ctrl_command(ctrl, cmd);
1194}
1195
1196
1197static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[])
1198{
1199	char cmd[256], *pos, *end;
1200	int i, ret;
1201
1202	if (argc < 2) {
1203		printf("Invalid OTP command: needs two arguments (network "
1204		       "id and password)\n");
1205		return -1;
1206	}
1207
1208	end = cmd + sizeof(cmd);
1209	pos = cmd;
1210	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s",
1211			  argv[0], argv[1]);
1212	if (ret < 0 || ret >= end - pos) {
1213		printf("Too long OTP command.\n");
1214		return -1;
1215	}
1216	pos += ret;
1217	for (i = 2; i < argc; i++) {
1218		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
1219		if (ret < 0 || ret >= end - pos) {
1220			printf("Too long OTP command.\n");
1221			return -1;
1222		}
1223		pos += ret;
1224	}
1225
1226	return wpa_ctrl_command(ctrl, cmd);
1227}
1228
1229
1230static int wpa_cli_cmd_sim(struct wpa_ctrl *ctrl, int argc, char *argv[])
1231{
1232	char cmd[256], *pos, *end;
1233	int i, ret;
1234
1235	if (argc < 2) {
1236		printf("Invalid SIM command: needs two arguments "
1237		       "(network id and SIM operation response)\n");
1238		return -1;
1239	}
1240
1241	end = cmd + sizeof(cmd);
1242	pos = cmd;
1243	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "SIM-%s:%s",
1244			  argv[0], argv[1]);
1245	if (ret < 0 || ret >= end - pos) {
1246		printf("Too long SIM command.\n");
1247		return -1;
1248	}
1249	pos += ret;
1250	for (i = 2; i < argc; i++) {
1251		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
1252		if (ret < 0 || ret >= end - pos) {
1253			printf("Too long SIM command.\n");
1254			return -1;
1255		}
1256		pos += ret;
1257	}
1258	return wpa_ctrl_command(ctrl, cmd);
1259}
1260
1261
1262static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
1263				  char *argv[])
1264{
1265	char cmd[256], *pos, *end;
1266	int i, ret;
1267
1268	if (argc < 2) {
1269		printf("Invalid PASSPHRASE command: needs two arguments "
1270		       "(network id and passphrase)\n");
1271		return -1;
1272	}
1273
1274	end = cmd + sizeof(cmd);
1275	pos = cmd;
1276	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s",
1277			  argv[0], argv[1]);
1278	if (ret < 0 || ret >= end - pos) {
1279		printf("Too long PASSPHRASE command.\n");
1280		return -1;
1281	}
1282	pos += ret;
1283	for (i = 2; i < argc; i++) {
1284		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
1285		if (ret < 0 || ret >= end - pos) {
1286			printf("Too long PASSPHRASE command.\n");
1287			return -1;
1288		}
1289		pos += ret;
1290	}
1291
1292	return wpa_ctrl_command(ctrl, cmd);
1293}
1294
1295
1296static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[])
1297{
1298	if (argc < 2) {
1299		printf("Invalid BSSID command: needs two arguments (network "
1300		       "id and BSSID)\n");
1301		return -1;
1302	}
1303
1304	return wpa_cli_cmd(ctrl, "BSSID", 2, argc, argv);
1305}
1306
1307
1308static int wpa_cli_cmd_blacklist(struct wpa_ctrl *ctrl, int argc, char *argv[])
1309{
1310	return wpa_cli_cmd(ctrl, "BLACKLIST", 0, argc, argv);
1311}
1312
1313
1314static int wpa_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
1315{
1316	return wpa_cli_cmd(ctrl, "LOG_LEVEL", 0, argc, argv);
1317}
1318
1319
1320static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc,
1321				     char *argv[])
1322{
1323	return wpa_ctrl_command(ctrl, "LIST_NETWORKS");
1324}
1325
1326
1327static int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc,
1328				      char *argv[])
1329{
1330	return wpa_cli_cmd(ctrl, "SELECT_NETWORK", 1, argc, argv);
1331}
1332
1333
1334static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc,
1335				      char *argv[])
1336{
1337	return wpa_cli_cmd(ctrl, "ENABLE_NETWORK", 1, argc, argv);
1338}
1339
1340
1341static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc,
1342				       char *argv[])
1343{
1344	return wpa_cli_cmd(ctrl, "DISABLE_NETWORK", 1, argc, argv);
1345}
1346
1347
1348static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc,
1349				   char *argv[])
1350{
1351	return wpa_ctrl_command(ctrl, "ADD_NETWORK");
1352}
1353
1354
1355static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc,
1356				      char *argv[])
1357{
1358	return wpa_cli_cmd(ctrl, "REMOVE_NETWORK", 1, argc, argv);
1359}
1360
1361
1362static void wpa_cli_show_network_variables(void)
1363{
1364	printf("set_network variables:\n"
1365	       "  ssid (network name, SSID)\n"
1366	       "  psk (WPA passphrase or pre-shared key)\n"
1367	       "  key_mgmt (key management protocol)\n"
1368	       "  identity (EAP identity)\n"
1369	       "  password (EAP password)\n"
1370	       "  ...\n"
1371	       "\n"
1372	       "Note: Values are entered in the same format as the "
1373	       "configuration file is using,\n"
1374	       "i.e., strings values need to be inside double quotation "
1375	       "marks.\n"
1376	       "For example: set_network 1 ssid \"network name\"\n"
1377	       "\n"
1378	       "Please see wpa_supplicant.conf documentation for full list "
1379	       "of\navailable variables.\n");
1380}
1381
1382
1383static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc,
1384				   char *argv[])
1385{
1386	if (argc == 0) {
1387		wpa_cli_show_network_variables();
1388		return 0;
1389	}
1390
1391	if (argc < 3) {
1392		printf("Invalid SET_NETWORK command: needs three arguments\n"
1393		       "(network id, variable name, and value)\n");
1394		return -1;
1395	}
1396
1397	return wpa_cli_cmd(ctrl, "SET_NETWORK", 3, argc, argv);
1398}
1399
1400
1401static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
1402				   char *argv[])
1403{
1404	if (argc == 0) {
1405		wpa_cli_show_network_variables();
1406		return 0;
1407	}
1408
1409	if (argc != 2) {
1410		printf("Invalid GET_NETWORK command: needs two arguments\n"
1411		       "(network id and variable name)\n");
1412		return -1;
1413	}
1414
1415	return wpa_cli_cmd(ctrl, "GET_NETWORK", 2, argc, argv);
1416}
1417
1418
1419static int wpa_cli_cmd_list_creds(struct wpa_ctrl *ctrl, int argc,
1420				  char *argv[])
1421{
1422	return wpa_ctrl_command(ctrl, "LIST_CREDS");
1423}
1424
1425
1426static int wpa_cli_cmd_add_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
1427{
1428	return wpa_ctrl_command(ctrl, "ADD_CRED");
1429}
1430
1431
1432static int wpa_cli_cmd_remove_cred(struct wpa_ctrl *ctrl, int argc,
1433				   char *argv[])
1434{
1435	return wpa_cli_cmd(ctrl, "REMOVE_CRED", 1, argc, argv);
1436}
1437
1438
1439static int wpa_cli_cmd_set_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
1440{
1441	if (argc != 3) {
1442		printf("Invalid SET_CRED command: needs three arguments\n"
1443		       "(cred id, variable name, and value)\n");
1444		return -1;
1445	}
1446
1447	return wpa_cli_cmd(ctrl, "SET_CRED", 3, argc, argv);
1448}
1449
1450
1451static int wpa_cli_cmd_get_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
1452{
1453	if (argc != 2) {
1454		printf("Invalid GET_CRED command: needs two arguments\n"
1455		       "(cred id, variable name)\n");
1456		return -1;
1457	}
1458
1459	return wpa_cli_cmd(ctrl, "GET_CRED", 2, argc, argv);
1460}
1461
1462
1463static int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc,
1464				  char *argv[])
1465{
1466	return wpa_ctrl_command(ctrl, "DISCONNECT");
1467}
1468
1469
1470static int wpa_cli_cmd_reconnect(struct wpa_ctrl *ctrl, int argc,
1471				  char *argv[])
1472{
1473	return wpa_ctrl_command(ctrl, "RECONNECT");
1474}
1475
1476
1477static int wpa_cli_cmd_save_config(struct wpa_ctrl *ctrl, int argc,
1478				   char *argv[])
1479{
1480	return wpa_ctrl_command(ctrl, "SAVE_CONFIG");
1481}
1482
1483
1484static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
1485{
1486	return wpa_cli_cmd(ctrl, "SCAN", 0, argc, argv);
1487}
1488
1489
1490static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc,
1491				    char *argv[])
1492{
1493	return wpa_ctrl_command(ctrl, "SCAN_RESULTS");
1494}
1495
1496
1497static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
1498{
1499	return wpa_cli_cmd(ctrl, "BSS", 1, argc, argv);
1500}
1501
1502
1503static char ** wpa_cli_complete_bss(const char *str, int pos)
1504{
1505	int arg = get_cmd_arg_num(str, pos);
1506	char **res = NULL;
1507
1508	switch (arg) {
1509	case 1:
1510		res = cli_txt_list_array(&bsses);
1511		break;
1512	}
1513
1514	return res;
1515}
1516
1517
1518static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
1519				      char *argv[])
1520{
1521	if (argc < 1 || argc > 2) {
1522		printf("Invalid GET_CAPABILITY command: need either one or "
1523		       "two arguments\n");
1524		return -1;
1525	}
1526
1527	if ((argc == 2) && os_strcmp(argv[1], "strict") != 0) {
1528		printf("Invalid GET_CAPABILITY command: second argument, "
1529		       "if any, must be 'strict'\n");
1530		return -1;
1531	}
1532
1533	return wpa_cli_cmd(ctrl, "GET_CAPABILITY", 1, argc, argv);
1534}
1535
1536
1537static int wpa_cli_list_interfaces(struct wpa_ctrl *ctrl)
1538{
1539	printf("Available interfaces:\n");
1540	return wpa_ctrl_command(ctrl, "INTERFACES");
1541}
1542
1543
1544static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[])
1545{
1546	if (argc < 1) {
1547		wpa_cli_list_interfaces(ctrl);
1548		return 0;
1549	}
1550
1551	wpa_cli_close_connection();
1552	os_free(ctrl_ifname);
1553	ctrl_ifname = os_strdup(argv[0]);
1554
1555	if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
1556		printf("Connected to interface '%s.\n", ctrl_ifname);
1557	} else {
1558		printf("Could not connect to interface '%s' - re-trying\n",
1559		       ctrl_ifname);
1560	}
1561	return 0;
1562}
1563
1564
1565static int wpa_cli_cmd_reconfigure(struct wpa_ctrl *ctrl, int argc,
1566				   char *argv[])
1567{
1568	return wpa_ctrl_command(ctrl, "RECONFIGURE");
1569}
1570
1571
1572static int wpa_cli_cmd_terminate(struct wpa_ctrl *ctrl, int argc,
1573				 char *argv[])
1574{
1575	return wpa_ctrl_command(ctrl, "TERMINATE");
1576}
1577
1578
1579static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc,
1580				     char *argv[])
1581{
1582	char cmd[256];
1583	int res;
1584
1585	if (argc < 1) {
1586		printf("Invalid INTERFACE_ADD command: needs at least one "
1587		       "argument (interface name)\n"
1588		       "All arguments: ifname confname driver ctrl_interface "
1589		       "driver_param bridge_name\n");
1590		return -1;
1591	}
1592
1593	/*
1594	 * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
1595	 * <driver_param>TAB<bridge_name>
1596	 */
1597	res = os_snprintf(cmd, sizeof(cmd),
1598			  "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s",
1599			  argv[0],
1600			  argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "",
1601			  argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "",
1602			  argc > 5 ? argv[5] : "");
1603	if (res < 0 || (size_t) res >= sizeof(cmd))
1604		return -1;
1605	cmd[sizeof(cmd) - 1] = '\0';
1606	return wpa_ctrl_command(ctrl, cmd);
1607}
1608
1609
1610static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc,
1611					char *argv[])
1612{
1613	return wpa_cli_cmd(ctrl, "INTERFACE_REMOVE", 1, argc, argv);
1614}
1615
1616
1617static int wpa_cli_cmd_interface_list(struct wpa_ctrl *ctrl, int argc,
1618				      char *argv[])
1619{
1620	return wpa_ctrl_command(ctrl, "INTERFACE_LIST");
1621}
1622
1623
1624#ifdef CONFIG_AP
1625static int wpa_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
1626{
1627	return wpa_cli_cmd(ctrl, "STA", 1, argc, argv);
1628}
1629
1630
1631static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
1632				char *addr, size_t addr_len)
1633{
1634	char buf[4096], *pos;
1635	size_t len;
1636	int ret;
1637
1638	if (ctrl_conn == NULL) {
1639		printf("Not connected to hostapd - command dropped.\n");
1640		return -1;
1641	}
1642	len = sizeof(buf) - 1;
1643	ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
1644			       wpa_cli_msg_cb);
1645	if (ret == -2) {
1646		printf("'%s' command timed out.\n", cmd);
1647		return -2;
1648	} else if (ret < 0) {
1649		printf("'%s' command failed.\n", cmd);
1650		return -1;
1651	}
1652
1653	buf[len] = '\0';
1654	if (os_memcmp(buf, "FAIL", 4) == 0)
1655		return -1;
1656	printf("%s", buf);
1657
1658	pos = buf;
1659	while (*pos != '\0' && *pos != '\n')
1660		pos++;
1661	*pos = '\0';
1662	os_strlcpy(addr, buf, addr_len);
1663	return 0;
1664}
1665
1666
1667static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
1668{
1669	char addr[32], cmd[64];
1670
1671	if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
1672		return 0;
1673	do {
1674		os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
1675	} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
1676
1677	return -1;
1678}
1679
1680
1681static int wpa_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
1682				      char *argv[])
1683{
1684	return wpa_cli_cmd(ctrl, "DEAUTHENTICATE", 1, argc, argv);
1685}
1686
1687
1688static int wpa_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
1689				    char *argv[])
1690{
1691	return wpa_cli_cmd(ctrl, "DISASSOCIATE", 1, argc, argv);
1692}
1693
1694static int wpa_cli_cmd_chanswitch(struct wpa_ctrl *ctrl, int argc,
1695				    char *argv[])
1696{
1697	return wpa_cli_cmd(ctrl, "CHAN_SWITCH", 2, argc, argv);
1698}
1699
1700#endif /* CONFIG_AP */
1701
1702
1703static int wpa_cli_cmd_suspend(struct wpa_ctrl *ctrl, int argc, char *argv[])
1704{
1705	return wpa_ctrl_command(ctrl, "SUSPEND");
1706}
1707
1708
1709static int wpa_cli_cmd_resume(struct wpa_ctrl *ctrl, int argc, char *argv[])
1710{
1711	return wpa_ctrl_command(ctrl, "RESUME");
1712}
1713
1714
1715#ifdef CONFIG_TESTING_OPTIONS
1716static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[])
1717{
1718	return wpa_ctrl_command(ctrl, "DROP_SA");
1719}
1720#endif /* CONFIG_TESTING_OPTIONS */
1721
1722
1723static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
1724{
1725	return wpa_cli_cmd(ctrl, "ROAM", 1, argc, argv);
1726}
1727
1728
1729#ifdef CONFIG_P2P
1730
1731static int wpa_cli_cmd_p2p_find(struct wpa_ctrl *ctrl, int argc, char *argv[])
1732{
1733	return wpa_cli_cmd(ctrl, "P2P_FIND", 0, argc, argv);
1734}
1735
1736
1737static char ** wpa_cli_complete_p2p_find(const char *str, int pos)
1738{
1739	char **res = NULL;
1740	int arg = get_cmd_arg_num(str, pos);
1741
1742	res = os_calloc(6, sizeof(char *));
1743	if (res == NULL)
1744		return NULL;
1745	res[0] = os_strdup("type=social");
1746	if (res[0] == NULL) {
1747		os_free(res);
1748		return NULL;
1749	}
1750	res[1] = os_strdup("type=progressive");
1751	if (res[1] == NULL)
1752		return res;
1753	res[2] = os_strdup("delay=");
1754	if (res[2] == NULL)
1755		return res;
1756	res[3] = os_strdup("dev_id=");
1757	if (res[3] == NULL)
1758		return res;
1759	if (arg == 1)
1760		res[4] = os_strdup("[timeout]");
1761
1762	return res;
1763}
1764
1765
1766static int wpa_cli_cmd_p2p_stop_find(struct wpa_ctrl *ctrl, int argc,
1767				     char *argv[])
1768{
1769	return wpa_ctrl_command(ctrl, "P2P_STOP_FIND");
1770}
1771
1772
1773static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc,
1774				   char *argv[])
1775{
1776	return wpa_cli_cmd(ctrl, "P2P_CONNECT", 2, argc, argv);
1777}
1778
1779
1780static char ** wpa_cli_complete_p2p_connect(const char *str, int pos)
1781{
1782	int arg = get_cmd_arg_num(str, pos);
1783	char **res = NULL;
1784
1785	switch (arg) {
1786	case 1:
1787		res = cli_txt_list_array(&p2p_peers);
1788		break;
1789	}
1790
1791	return res;
1792}
1793
1794
1795static int wpa_cli_cmd_p2p_listen(struct wpa_ctrl *ctrl, int argc,
1796				  char *argv[])
1797{
1798	return wpa_cli_cmd(ctrl, "P2P_LISTEN", 0, argc, argv);
1799}
1800
1801
1802static int wpa_cli_cmd_p2p_group_remove(struct wpa_ctrl *ctrl, int argc,
1803					char *argv[])
1804{
1805	return wpa_cli_cmd(ctrl, "P2P_GROUP_REMOVE", 1, argc, argv);
1806}
1807
1808
1809static char ** wpa_cli_complete_p2p_group_remove(const char *str, int pos)
1810{
1811	int arg = get_cmd_arg_num(str, pos);
1812	char **res = NULL;
1813
1814	switch (arg) {
1815	case 1:
1816		res = cli_txt_list_array(&p2p_groups);
1817		break;
1818	}
1819
1820	return res;
1821}
1822
1823
1824static int wpa_cli_cmd_p2p_group_add(struct wpa_ctrl *ctrl, int argc,
1825					char *argv[])
1826{
1827	return wpa_cli_cmd(ctrl, "P2P_GROUP_ADD", 0, argc, argv);
1828}
1829
1830
1831static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc,
1832				     char *argv[])
1833{
1834	if (argc != 2 && argc != 3) {
1835		printf("Invalid P2P_PROV_DISC command: needs at least "
1836		       "two arguments, address and config method\n"
1837		       "(display, keypad, or pbc) and an optional join\n");
1838		return -1;
1839	}
1840
1841	return wpa_cli_cmd(ctrl, "P2P_PROV_DISC", 2, argc, argv);
1842}
1843
1844
1845static int wpa_cli_cmd_p2p_get_passphrase(struct wpa_ctrl *ctrl, int argc,
1846					  char *argv[])
1847{
1848	return wpa_ctrl_command(ctrl, "P2P_GET_PASSPHRASE");
1849}
1850
1851
1852static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc,
1853					 char *argv[])
1854{
1855	char cmd[4096];
1856
1857	if (argc != 2 && argc != 4) {
1858		printf("Invalid P2P_SERV_DISC_REQ command: needs two "
1859		       "arguments (address and TLVs) or four arguments "
1860		       "(address, \"upnp\", version, search target "
1861		       "(SSDP ST:)\n");
1862		return -1;
1863	}
1864
1865	if (write_cmd(cmd, sizeof(cmd), "P2P_SERV_DISC_REQ", argc, argv) < 0)
1866		return -1;
1867	return wpa_ctrl_command(ctrl, cmd);
1868}
1869
1870
1871static int wpa_cli_cmd_p2p_serv_disc_cancel_req(struct wpa_ctrl *ctrl,
1872						int argc, char *argv[])
1873{
1874	return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_CANCEL_REQ", 1, argc, argv);
1875}
1876
1877
1878static int wpa_cli_cmd_p2p_serv_disc_resp(struct wpa_ctrl *ctrl, int argc,
1879					  char *argv[])
1880{
1881	char cmd[4096];
1882	int res;
1883
1884	if (argc != 4) {
1885		printf("Invalid P2P_SERV_DISC_RESP command: needs four "
1886		       "arguments (freq, address, dialog token, and TLVs)\n");
1887		return -1;
1888	}
1889
1890	res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_RESP %s %s %s %s",
1891			  argv[0], argv[1], argv[2], argv[3]);
1892	if (res < 0 || (size_t) res >= sizeof(cmd))
1893		return -1;
1894	cmd[sizeof(cmd) - 1] = '\0';
1895	return wpa_ctrl_command(ctrl, cmd);
1896}
1897
1898
1899static int wpa_cli_cmd_p2p_service_update(struct wpa_ctrl *ctrl, int argc,
1900					  char *argv[])
1901{
1902	return wpa_ctrl_command(ctrl, "P2P_SERVICE_UPDATE");
1903}
1904
1905
1906static int wpa_cli_cmd_p2p_serv_disc_external(struct wpa_ctrl *ctrl,
1907					      int argc, char *argv[])
1908{
1909	return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_EXTERNAL", 1, argc, argv);
1910}
1911
1912
1913static int wpa_cli_cmd_p2p_service_flush(struct wpa_ctrl *ctrl, int argc,
1914					 char *argv[])
1915{
1916	return wpa_ctrl_command(ctrl, "P2P_SERVICE_FLUSH");
1917}
1918
1919
1920static int wpa_cli_cmd_p2p_service_add(struct wpa_ctrl *ctrl, int argc,
1921				       char *argv[])
1922{
1923	char cmd[4096];
1924	int res;
1925
1926	if (argc != 3 && argc != 4) {
1927		printf("Invalid P2P_SERVICE_ADD command: needs three or four "
1928		       "arguments\n");
1929		return -1;
1930	}
1931
1932	if (argc == 4)
1933		res = os_snprintf(cmd, sizeof(cmd),
1934				  "P2P_SERVICE_ADD %s %s %s %s",
1935				  argv[0], argv[1], argv[2], argv[3]);
1936	else
1937		res = os_snprintf(cmd, sizeof(cmd),
1938				  "P2P_SERVICE_ADD %s %s %s",
1939				  argv[0], argv[1], argv[2]);
1940	if (res < 0 || (size_t) res >= sizeof(cmd))
1941		return -1;
1942	cmd[sizeof(cmd) - 1] = '\0';
1943	return wpa_ctrl_command(ctrl, cmd);
1944}
1945
1946
1947static int wpa_cli_cmd_p2p_service_del(struct wpa_ctrl *ctrl, int argc,
1948				       char *argv[])
1949{
1950	char cmd[4096];
1951	int res;
1952
1953	if (argc != 2 && argc != 3) {
1954		printf("Invalid P2P_SERVICE_DEL command: needs two or three "
1955		       "arguments\n");
1956		return -1;
1957	}
1958
1959	if (argc == 3)
1960		res = os_snprintf(cmd, sizeof(cmd),
1961				  "P2P_SERVICE_DEL %s %s %s",
1962				  argv[0], argv[1], argv[2]);
1963	else
1964		res = os_snprintf(cmd, sizeof(cmd),
1965				  "P2P_SERVICE_DEL %s %s",
1966				  argv[0], argv[1]);
1967	if (res < 0 || (size_t) res >= sizeof(cmd))
1968		return -1;
1969	cmd[sizeof(cmd) - 1] = '\0';
1970	return wpa_ctrl_command(ctrl, cmd);
1971}
1972
1973
1974static int wpa_cli_cmd_p2p_reject(struct wpa_ctrl *ctrl,
1975				  int argc, char *argv[])
1976{
1977	return wpa_cli_cmd(ctrl, "P2P_REJECT", 1, argc, argv);
1978}
1979
1980
1981static int wpa_cli_cmd_p2p_invite(struct wpa_ctrl *ctrl,
1982				  int argc, char *argv[])
1983{
1984	return wpa_cli_cmd(ctrl, "P2P_INVITE", 1, argc, argv);
1985}
1986
1987
1988static int wpa_cli_cmd_p2p_peer(struct wpa_ctrl *ctrl, int argc, char *argv[])
1989{
1990	return wpa_cli_cmd(ctrl, "P2P_PEER", 1, argc, argv);
1991}
1992
1993
1994static char ** wpa_cli_complete_p2p_peer(const char *str, int pos)
1995{
1996	int arg = get_cmd_arg_num(str, pos);
1997	char **res = NULL;
1998
1999	switch (arg) {
2000	case 1:
2001		res = cli_txt_list_array(&p2p_peers);
2002		break;
2003	}
2004
2005	return res;
2006}
2007
2008
2009static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, char *cmd,
2010				     char *addr, size_t addr_len,
2011				     int discovered)
2012{
2013	char buf[4096], *pos;
2014	size_t len;
2015	int ret;
2016
2017	if (ctrl_conn == NULL)
2018		return -1;
2019	len = sizeof(buf) - 1;
2020	ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
2021			       wpa_cli_msg_cb);
2022	if (ret == -2) {
2023		printf("'%s' command timed out.\n", cmd);
2024		return -2;
2025	} else if (ret < 0) {
2026		printf("'%s' command failed.\n", cmd);
2027		return -1;
2028	}
2029
2030	buf[len] = '\0';
2031	if (os_memcmp(buf, "FAIL", 4) == 0)
2032		return -1;
2033
2034	pos = buf;
2035	while (*pos != '\0' && *pos != '\n')
2036		pos++;
2037	*pos++ = '\0';
2038	os_strlcpy(addr, buf, addr_len);
2039	if (!discovered || os_strstr(pos, "[PROBE_REQ_ONLY]") == NULL)
2040		printf("%s\n", addr);
2041	return 0;
2042}
2043
2044
2045static int wpa_cli_cmd_p2p_peers(struct wpa_ctrl *ctrl, int argc, char *argv[])
2046{
2047	char addr[32], cmd[64];
2048	int discovered;
2049
2050	discovered = argc > 0 && os_strcmp(argv[0], "discovered") == 0;
2051
2052	if (wpa_ctrl_command_p2p_peer(ctrl, "P2P_PEER FIRST",
2053				      addr, sizeof(addr), discovered))
2054		return -1;
2055	do {
2056		os_snprintf(cmd, sizeof(cmd), "P2P_PEER NEXT-%s", addr);
2057	} while (wpa_ctrl_command_p2p_peer(ctrl, cmd, addr, sizeof(addr),
2058			 discovered) == 0);
2059
2060	return 0;
2061}
2062
2063
2064static int wpa_cli_cmd_p2p_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
2065{
2066	return wpa_cli_cmd(ctrl, "P2P_SET", 2, argc, argv);
2067}
2068
2069
2070static char ** wpa_cli_complete_p2p_set(const char *str, int pos)
2071{
2072	int arg = get_cmd_arg_num(str, pos);
2073	const char *fields[] = {
2074		"discoverability",
2075		"managed",
2076		"listen_channel",
2077		"ssid_postfix",
2078		"noa",
2079		"ps",
2080		"oppps",
2081		"ctwindow",
2082		"disabled",
2083		"conc_pref",
2084		"force_long_sd",
2085		"peer_filter",
2086		"cross_connect",
2087		"go_apsd",
2088		"client_apsd",
2089		"disallow_freq",
2090		"disc_int",
2091		"per_sta_psk",
2092	};
2093	int i, num_fields = ARRAY_SIZE(fields);
2094
2095	if (arg == 1) {
2096		char **res = os_calloc(num_fields + 1, sizeof(char *));
2097		if (res == NULL)
2098			return NULL;
2099		for (i = 0; i < num_fields; i++) {
2100			res[i] = os_strdup(fields[i]);
2101			if (res[i] == NULL)
2102				return res;
2103		}
2104		return res;
2105	}
2106
2107	if (arg == 2 && os_strncasecmp(str, "p2p_set peer_filter ", 20) == 0)
2108		return cli_txt_list_array(&p2p_peers);
2109
2110	return NULL;
2111}
2112
2113
2114static int wpa_cli_cmd_p2p_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
2115{
2116	return wpa_ctrl_command(ctrl, "P2P_FLUSH");
2117}
2118
2119
2120static int wpa_cli_cmd_p2p_cancel(struct wpa_ctrl *ctrl, int argc,
2121				  char *argv[])
2122{
2123	return wpa_ctrl_command(ctrl, "P2P_CANCEL");
2124}
2125
2126
2127static int wpa_cli_cmd_p2p_unauthorize(struct wpa_ctrl *ctrl, int argc,
2128				       char *argv[])
2129{
2130	return wpa_cli_cmd(ctrl, "P2P_UNAUTHORIZE", 1, argc, argv);
2131}
2132
2133
2134static int wpa_cli_cmd_p2p_presence_req(struct wpa_ctrl *ctrl, int argc,
2135					char *argv[])
2136{
2137	if (argc != 0 && argc != 2 && argc != 4) {
2138		printf("Invalid P2P_PRESENCE_REQ command: needs two arguments "
2139		       "(preferred duration, interval; in microsecods).\n"
2140		       "Optional second pair can be used to provide "
2141		       "acceptable values.\n");
2142		return -1;
2143	}
2144
2145	return wpa_cli_cmd(ctrl, "P2P_PRESENCE_REQ", 0, argc, argv);
2146}
2147
2148
2149static int wpa_cli_cmd_p2p_ext_listen(struct wpa_ctrl *ctrl, int argc,
2150				      char *argv[])
2151{
2152	if (argc != 0 && argc != 2) {
2153		printf("Invalid P2P_EXT_LISTEN command: needs two arguments "
2154		       "(availability period, availability interval; in "
2155		       "millisecods).\n"
2156		       "Extended Listen Timing can be cancelled with this "
2157		       "command when used without parameters.\n");
2158		return -1;
2159	}
2160
2161	return wpa_cli_cmd(ctrl, "P2P_EXT_LISTEN", 0, argc, argv);
2162}
2163
2164
2165static int wpa_cli_cmd_p2p_remove_client(struct wpa_ctrl *ctrl, int argc,
2166					 char *argv[])
2167{
2168	return wpa_cli_cmd(ctrl, "P2P_REMOVE_CLIENT", 1, argc, argv);
2169}
2170
2171#endif /* CONFIG_P2P */
2172
2173#ifdef CONFIG_WIFI_DISPLAY
2174
2175static int wpa_cli_cmd_wfd_subelem_set(struct wpa_ctrl *ctrl, int argc,
2176				       char *argv[])
2177{
2178	char cmd[100];
2179	int res;
2180
2181	if (argc != 1 && argc != 2) {
2182		printf("Invalid WFD_SUBELEM_SET command: needs one or two "
2183		       "arguments (subelem, hexdump)\n");
2184		return -1;
2185	}
2186
2187	res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_SET %s %s",
2188			  argv[0], argc > 1 ? argv[1] : "");
2189	if (res < 0 || (size_t) res >= sizeof(cmd))
2190		return -1;
2191	cmd[sizeof(cmd) - 1] = '\0';
2192	return wpa_ctrl_command(ctrl, cmd);
2193}
2194
2195
2196static int wpa_cli_cmd_wfd_subelem_get(struct wpa_ctrl *ctrl, int argc,
2197				       char *argv[])
2198{
2199	char cmd[100];
2200	int res;
2201
2202	if (argc != 1) {
2203		printf("Invalid WFD_SUBELEM_GET command: needs one "
2204		       "argument (subelem)\n");
2205		return -1;
2206	}
2207
2208	res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_GET %s",
2209			  argv[0]);
2210	if (res < 0 || (size_t) res >= sizeof(cmd))
2211		return -1;
2212	cmd[sizeof(cmd) - 1] = '\0';
2213	return wpa_ctrl_command(ctrl, cmd);
2214}
2215#endif /* CONFIG_WIFI_DISPLAY */
2216
2217
2218#ifdef CONFIG_INTERWORKING
2219static int wpa_cli_cmd_fetch_anqp(struct wpa_ctrl *ctrl, int argc,
2220				  char *argv[])
2221{
2222	return wpa_ctrl_command(ctrl, "FETCH_ANQP");
2223}
2224
2225
2226static int wpa_cli_cmd_stop_fetch_anqp(struct wpa_ctrl *ctrl, int argc,
2227				       char *argv[])
2228{
2229	return wpa_ctrl_command(ctrl, "STOP_FETCH_ANQP");
2230}
2231
2232
2233static int wpa_cli_cmd_interworking_select(struct wpa_ctrl *ctrl, int argc,
2234					   char *argv[])
2235{
2236	return wpa_cli_cmd(ctrl, "INTERWORKING_SELECT", 0, argc, argv);
2237}
2238
2239
2240static int wpa_cli_cmd_interworking_connect(struct wpa_ctrl *ctrl, int argc,
2241					    char *argv[])
2242{
2243	return wpa_cli_cmd(ctrl, "INTERWORKING_CONNECT", 1, argc, argv);
2244}
2245
2246
2247static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
2248{
2249	return wpa_cli_cmd(ctrl, "ANQP_GET", 2, argc, argv);
2250}
2251
2252
2253static int wpa_cli_cmd_gas_request(struct wpa_ctrl *ctrl, int argc,
2254				   char *argv[])
2255{
2256	return wpa_cli_cmd(ctrl, "GAS_REQUEST", 2, argc, argv);
2257}
2258
2259
2260static int wpa_cli_cmd_gas_response_get(struct wpa_ctrl *ctrl, int argc,
2261					char *argv[])
2262{
2263	return wpa_cli_cmd(ctrl, "GAS_RESPONSE_GET", 2, argc, argv);
2264}
2265#endif /* CONFIG_INTERWORKING */
2266
2267
2268#ifdef CONFIG_HS20
2269
2270static int wpa_cli_cmd_hs20_anqp_get(struct wpa_ctrl *ctrl, int argc,
2271				     char *argv[])
2272{
2273	return wpa_cli_cmd(ctrl, "HS20_ANQP_GET", 2, argc, argv);
2274}
2275
2276
2277static int wpa_cli_cmd_get_nai_home_realm_list(struct wpa_ctrl *ctrl, int argc,
2278					       char *argv[])
2279{
2280	char cmd[512];
2281
2282	if (argc == 0) {
2283		printf("Command needs one or two arguments (dst mac addr and "
2284		       "optional home realm)\n");
2285		return -1;
2286	}
2287
2288	if (write_cmd(cmd, sizeof(cmd), "HS20_GET_NAI_HOME_REALM_LIST",
2289		      argc, argv) < 0)
2290		return -1;
2291
2292	return wpa_ctrl_command(ctrl, cmd);
2293}
2294
2295
2296static int wpa_cli_cmd_hs20_icon_request(struct wpa_ctrl *ctrl, int argc,
2297					 char *argv[])
2298{
2299	char cmd[512];
2300
2301	if (argc < 2) {
2302		printf("Command needs two arguments (dst mac addr and "
2303		       "icon name)\n");
2304		return -1;
2305	}
2306
2307	if (write_cmd(cmd, sizeof(cmd), "HS20_ICON_REQUEST", argc, argv) < 0)
2308		return -1;
2309
2310	return wpa_ctrl_command(ctrl, cmd);
2311}
2312
2313
2314static int wpa_cli_cmd_fetch_osu(struct wpa_ctrl *ctrl, int argc, char *argv[])
2315{
2316	return wpa_ctrl_command(ctrl, "FETCH_OSU");
2317}
2318
2319
2320static int wpa_cli_cmd_cancel_fetch_osu(struct wpa_ctrl *ctrl, int argc,
2321					char *argv[])
2322{
2323	return wpa_ctrl_command(ctrl, "CANCEL_FETCH_OSU");
2324}
2325
2326#endif /* CONFIG_HS20 */
2327
2328
2329static int wpa_cli_cmd_sta_autoconnect(struct wpa_ctrl *ctrl, int argc,
2330				       char *argv[])
2331{
2332	return wpa_cli_cmd(ctrl, "STA_AUTOCONNECT", 1, argc, argv);
2333}
2334
2335
2336static int wpa_cli_cmd_tdls_discover(struct wpa_ctrl *ctrl, int argc,
2337				     char *argv[])
2338{
2339	return wpa_cli_cmd(ctrl, "TDLS_DISCOVER", 1, argc, argv);
2340}
2341
2342
2343static int wpa_cli_cmd_tdls_setup(struct wpa_ctrl *ctrl, int argc,
2344				  char *argv[])
2345{
2346	return wpa_cli_cmd(ctrl, "TDLS_SETUP", 1, argc, argv);
2347}
2348
2349
2350static int wpa_cli_cmd_tdls_teardown(struct wpa_ctrl *ctrl, int argc,
2351				     char *argv[])
2352{
2353	return wpa_cli_cmd(ctrl, "TDLS_TEARDOWN", 1, argc, argv);
2354}
2355
2356
2357static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc,
2358				   char *argv[])
2359{
2360	return wpa_ctrl_command(ctrl, "SIGNAL_POLL");
2361}
2362
2363
2364static int wpa_cli_cmd_pktcnt_poll(struct wpa_ctrl *ctrl, int argc,
2365				   char *argv[])
2366{
2367	return wpa_ctrl_command(ctrl, "PKTCNT_POLL");
2368}
2369
2370
2371static int wpa_cli_cmd_reauthenticate(struct wpa_ctrl *ctrl, int argc,
2372				      char *argv[])
2373{
2374	return wpa_ctrl_command(ctrl, "REAUTHENTICATE");
2375}
2376
2377
2378#ifdef CONFIG_AUTOSCAN
2379
2380static int wpa_cli_cmd_autoscan(struct wpa_ctrl *ctrl, int argc, char *argv[])
2381{
2382	if (argc == 0)
2383		return wpa_ctrl_command(ctrl, "AUTOSCAN ");
2384
2385	return wpa_cli_cmd(ctrl, "AUTOSCAN", 0, argc, argv);
2386}
2387
2388#endif /* CONFIG_AUTOSCAN */
2389
2390
2391#ifdef CONFIG_WNM
2392
2393static int wpa_cli_cmd_wnm_sleep(struct wpa_ctrl *ctrl, int argc, char *argv[])
2394{
2395	return wpa_cli_cmd(ctrl, "WNM_SLEEP", 0, argc, argv);
2396}
2397
2398
2399static int wpa_cli_cmd_wnm_bss_query(struct wpa_ctrl *ctrl, int argc, char *argv[])
2400{
2401	return wpa_cli_cmd(ctrl, "WNM_BSS_QUERY", 1, argc, argv);
2402}
2403
2404#endif /* CONFIG_WNM */
2405
2406
2407static int wpa_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
2408{
2409	if (argc == 0)
2410		return -1;
2411	return wpa_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]);
2412}
2413
2414
2415#ifdef ANDROID
2416static int wpa_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[])
2417{
2418	return wpa_cli_cmd(ctrl, "DRIVER", 1, argc, argv);
2419}
2420#endif /* ANDROID */
2421
2422
2423static int wpa_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
2424{
2425	return wpa_cli_cmd(ctrl, "VENDOR", 1, argc, argv);
2426}
2427
2428
2429static int wpa_cli_cmd_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
2430{
2431	return wpa_ctrl_command(ctrl, "FLUSH");
2432}
2433
2434
2435static int wpa_cli_cmd_radio_work(struct wpa_ctrl *ctrl, int argc, char *argv[])
2436{
2437	return wpa_cli_cmd(ctrl, "RADIO_WORK", 1, argc, argv);
2438}
2439
2440
2441enum wpa_cli_cmd_flags {
2442	cli_cmd_flag_none		= 0x00,
2443	cli_cmd_flag_sensitive		= 0x01
2444};
2445
2446struct wpa_cli_cmd {
2447	const char *cmd;
2448	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
2449	char ** (*completion)(const char *str, int pos);
2450	enum wpa_cli_cmd_flags flags;
2451	const char *usage;
2452};
2453
2454static struct wpa_cli_cmd wpa_cli_commands[] = {
2455	{ "status", wpa_cli_cmd_status, NULL,
2456	  cli_cmd_flag_none,
2457	  "[verbose] = get current WPA/EAPOL/EAP status" },
2458	{ "ifname", wpa_cli_cmd_ifname, NULL,
2459	  cli_cmd_flag_none,
2460	  "= get current interface name" },
2461	{ "ping", wpa_cli_cmd_ping, NULL,
2462	  cli_cmd_flag_none,
2463	  "= pings wpa_supplicant" },
2464	{ "relog", wpa_cli_cmd_relog, NULL,
2465	  cli_cmd_flag_none,
2466	  "= re-open log-file (allow rolling logs)" },
2467	{ "note", wpa_cli_cmd_note, NULL,
2468	  cli_cmd_flag_none,
2469	  "<text> = add a note to wpa_supplicant debug log" },
2470	{ "mib", wpa_cli_cmd_mib, NULL,
2471	  cli_cmd_flag_none,
2472	  "= get MIB variables (dot1x, dot11)" },
2473	{ "help", wpa_cli_cmd_help, wpa_cli_complete_help,
2474	  cli_cmd_flag_none,
2475	  "[command] = show usage help" },
2476	{ "interface", wpa_cli_cmd_interface, NULL,
2477	  cli_cmd_flag_none,
2478	  "[ifname] = show interfaces/select interface" },
2479	{ "level", wpa_cli_cmd_level, NULL,
2480	  cli_cmd_flag_none,
2481	  "<debug level> = change debug level" },
2482	{ "license", wpa_cli_cmd_license, NULL,
2483	  cli_cmd_flag_none,
2484	  "= show full wpa_cli license" },
2485	{ "quit", wpa_cli_cmd_quit, NULL,
2486	  cli_cmd_flag_none,
2487	  "= exit wpa_cli" },
2488	{ "set", wpa_cli_cmd_set, wpa_cli_complete_set,
2489	  cli_cmd_flag_none,
2490	  "= set variables (shows list of variables when run without "
2491	  "arguments)" },
2492	{ "get", wpa_cli_cmd_get, NULL,
2493	  cli_cmd_flag_none,
2494	  "<name> = get information" },
2495	{ "logon", wpa_cli_cmd_logon, NULL,
2496	  cli_cmd_flag_none,
2497	  "= IEEE 802.1X EAPOL state machine logon" },
2498	{ "logoff", wpa_cli_cmd_logoff, NULL,
2499	  cli_cmd_flag_none,
2500	  "= IEEE 802.1X EAPOL state machine logoff" },
2501	{ "pmksa", wpa_cli_cmd_pmksa, NULL,
2502	  cli_cmd_flag_none,
2503	  "= show PMKSA cache" },
2504	{ "reassociate", wpa_cli_cmd_reassociate, NULL,
2505	  cli_cmd_flag_none,
2506	  "= force reassociation" },
2507	{ "reattach", wpa_cli_cmd_reattach, NULL,
2508	  cli_cmd_flag_none,
2509	  "= force reassociation back to the same BSS" },
2510	{ "preauthenticate", wpa_cli_cmd_preauthenticate, wpa_cli_complete_bss,
2511	  cli_cmd_flag_none,
2512	  "<BSSID> = force preauthentication" },
2513	{ "identity", wpa_cli_cmd_identity, NULL,
2514	  cli_cmd_flag_none,
2515	  "<network id> <identity> = configure identity for an SSID" },
2516	{ "password", wpa_cli_cmd_password, NULL,
2517	  cli_cmd_flag_sensitive,
2518	  "<network id> <password> = configure password for an SSID" },
2519	{ "new_password", wpa_cli_cmd_new_password, NULL,
2520	  cli_cmd_flag_sensitive,
2521	  "<network id> <password> = change password for an SSID" },
2522	{ "pin", wpa_cli_cmd_pin, NULL,
2523	  cli_cmd_flag_sensitive,
2524	  "<network id> <pin> = configure pin for an SSID" },
2525	{ "otp", wpa_cli_cmd_otp, NULL,
2526	  cli_cmd_flag_sensitive,
2527	  "<network id> <password> = configure one-time-password for an SSID"
2528	},
2529	{ "passphrase", wpa_cli_cmd_passphrase, NULL,
2530	  cli_cmd_flag_sensitive,
2531	  "<network id> <passphrase> = configure private key passphrase\n"
2532	  "  for an SSID" },
2533	{ "sim", wpa_cli_cmd_sim, NULL,
2534	  cli_cmd_flag_sensitive,
2535	  "<network id> <pin> = report SIM operation result" },
2536	{ "bssid", wpa_cli_cmd_bssid, NULL,
2537	  cli_cmd_flag_none,
2538	  "<network id> <BSSID> = set preferred BSSID for an SSID" },
2539	{ "blacklist", wpa_cli_cmd_blacklist, wpa_cli_complete_bss,
2540	  cli_cmd_flag_none,
2541	  "<BSSID> = add a BSSID to the blacklist\n"
2542	  "blacklist clear = clear the blacklist\n"
2543	  "blacklist = display the blacklist" },
2544	{ "log_level", wpa_cli_cmd_log_level, NULL,
2545	  cli_cmd_flag_none,
2546	  "<level> [<timestamp>] = update the log level/timestamp\n"
2547	  "log_level = display the current log level and log options" },
2548	{ "list_networks", wpa_cli_cmd_list_networks, NULL,
2549	  cli_cmd_flag_none,
2550	  "= list configured networks" },
2551	{ "select_network", wpa_cli_cmd_select_network, NULL,
2552	  cli_cmd_flag_none,
2553	  "<network id> = select a network (disable others)" },
2554	{ "enable_network", wpa_cli_cmd_enable_network, NULL,
2555	  cli_cmd_flag_none,
2556	  "<network id> = enable a network" },
2557	{ "disable_network", wpa_cli_cmd_disable_network, NULL,
2558	  cli_cmd_flag_none,
2559	  "<network id> = disable a network" },
2560	{ "add_network", wpa_cli_cmd_add_network, NULL,
2561	  cli_cmd_flag_none,
2562	  "= add a network" },
2563	{ "remove_network", wpa_cli_cmd_remove_network, NULL,
2564	  cli_cmd_flag_none,
2565	  "<network id> = remove a network" },
2566	{ "set_network", wpa_cli_cmd_set_network, NULL,
2567	  cli_cmd_flag_sensitive,
2568	  "<network id> <variable> <value> = set network variables (shows\n"
2569	  "  list of variables when run without arguments)" },
2570	{ "get_network", wpa_cli_cmd_get_network, NULL,
2571	  cli_cmd_flag_none,
2572	  "<network id> <variable> = get network variables" },
2573	{ "list_creds", wpa_cli_cmd_list_creds, NULL,
2574	  cli_cmd_flag_none,
2575	  "= list configured credentials" },
2576	{ "add_cred", wpa_cli_cmd_add_cred, NULL,
2577	  cli_cmd_flag_none,
2578	  "= add a credential" },
2579	{ "remove_cred", wpa_cli_cmd_remove_cred, NULL,
2580	  cli_cmd_flag_none,
2581	  "<cred id> = remove a credential" },
2582	{ "set_cred", wpa_cli_cmd_set_cred, NULL,
2583	  cli_cmd_flag_sensitive,
2584	  "<cred id> <variable> <value> = set credential variables" },
2585	{ "get_cred", wpa_cli_cmd_get_cred, NULL,
2586	  cli_cmd_flag_none,
2587	  "<cred id> <variable> = get credential variables" },
2588	{ "save_config", wpa_cli_cmd_save_config, NULL,
2589	  cli_cmd_flag_none,
2590	  "= save the current configuration" },
2591	{ "disconnect", wpa_cli_cmd_disconnect, NULL,
2592	  cli_cmd_flag_none,
2593	  "= disconnect and wait for reassociate/reconnect command before\n"
2594	  "  connecting" },
2595	{ "reconnect", wpa_cli_cmd_reconnect, NULL,
2596	  cli_cmd_flag_none,
2597	  "= like reassociate, but only takes effect if already disconnected"
2598	},
2599	{ "scan", wpa_cli_cmd_scan, NULL,
2600	  cli_cmd_flag_none,
2601	  "= request new BSS scan" },
2602	{ "scan_results", wpa_cli_cmd_scan_results, NULL,
2603	  cli_cmd_flag_none,
2604	  "= get latest scan results" },
2605	{ "bss", wpa_cli_cmd_bss, wpa_cli_complete_bss,
2606	  cli_cmd_flag_none,
2607	  "<<idx> | <bssid>> = get detailed scan result info" },
2608	{ "get_capability", wpa_cli_cmd_get_capability, NULL,
2609	  cli_cmd_flag_none,
2610	  "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels/freq/modes> "
2611	  "= get capabilies" },
2612	{ "reconfigure", wpa_cli_cmd_reconfigure, NULL,
2613	  cli_cmd_flag_none,
2614	  "= force wpa_supplicant to re-read its configuration file" },
2615	{ "terminate", wpa_cli_cmd_terminate, NULL,
2616	  cli_cmd_flag_none,
2617	  "= terminate wpa_supplicant" },
2618	{ "interface_add", wpa_cli_cmd_interface_add, NULL,
2619	  cli_cmd_flag_none,
2620	  "<ifname> <confname> <driver> <ctrl_interface> <driver_param>\n"
2621	  "  <bridge_name> = adds new interface, all parameters but <ifname>\n"
2622	  "  are optional" },
2623	{ "interface_remove", wpa_cli_cmd_interface_remove, NULL,
2624	  cli_cmd_flag_none,
2625	  "<ifname> = removes the interface" },
2626	{ "interface_list", wpa_cli_cmd_interface_list, NULL,
2627	  cli_cmd_flag_none,
2628	  "= list available interfaces" },
2629	{ "ap_scan", wpa_cli_cmd_ap_scan, NULL,
2630	  cli_cmd_flag_none,
2631	  "<value> = set ap_scan parameter" },
2632	{ "scan_interval", wpa_cli_cmd_scan_interval, NULL,
2633	  cli_cmd_flag_none,
2634	  "<value> = set scan_interval parameter (in seconds)" },
2635	{ "bss_expire_age", wpa_cli_cmd_bss_expire_age, NULL,
2636	  cli_cmd_flag_none,
2637	  "<value> = set BSS expiration age parameter" },
2638	{ "bss_expire_count", wpa_cli_cmd_bss_expire_count, NULL,
2639	  cli_cmd_flag_none,
2640	  "<value> = set BSS expiration scan count parameter" },
2641	{ "bss_flush", wpa_cli_cmd_bss_flush, NULL,
2642	  cli_cmd_flag_none,
2643	  "<value> = set BSS flush age (0 by default)" },
2644	{ "stkstart", wpa_cli_cmd_stkstart, NULL,
2645	  cli_cmd_flag_none,
2646	  "<addr> = request STK negotiation with <addr>" },
2647	{ "ft_ds", wpa_cli_cmd_ft_ds, wpa_cli_complete_bss,
2648	  cli_cmd_flag_none,
2649	  "<addr> = request over-the-DS FT with <addr>" },
2650	{ "wps_pbc", wpa_cli_cmd_wps_pbc, wpa_cli_complete_bss,
2651	  cli_cmd_flag_none,
2652	  "[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" },
2653	{ "wps_pin", wpa_cli_cmd_wps_pin, wpa_cli_complete_bss,
2654	  cli_cmd_flag_sensitive,
2655	  "<BSSID> [PIN] = start WPS PIN method (returns PIN, if not "
2656	  "hardcoded)" },
2657	{ "wps_check_pin", wpa_cli_cmd_wps_check_pin, NULL,
2658	  cli_cmd_flag_sensitive,
2659	  "<PIN> = verify PIN checksum" },
2660	{ "wps_cancel", wpa_cli_cmd_wps_cancel, NULL, cli_cmd_flag_none,
2661	  "Cancels the pending WPS operation" },
2662#ifdef CONFIG_WPS_NFC
2663	{ "wps_nfc", wpa_cli_cmd_wps_nfc, wpa_cli_complete_bss,
2664	  cli_cmd_flag_none,
2665	  "[BSSID] = start Wi-Fi Protected Setup: NFC" },
2666	{ "wps_nfc_config_token", wpa_cli_cmd_wps_nfc_config_token, NULL,
2667	  cli_cmd_flag_none,
2668	  "<WPS|NDEF> = build configuration token" },
2669	{ "wps_nfc_token", wpa_cli_cmd_wps_nfc_token, NULL,
2670	  cli_cmd_flag_none,
2671	  "<WPS|NDEF> = create password token" },
2672	{ "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read, NULL,
2673	  cli_cmd_flag_sensitive,
2674	  "<hexdump of payload> = report read NFC tag with WPS data" },
2675	{ "nfc_get_handover_req", wpa_cli_cmd_nfc_get_handover_req, NULL,
2676	  cli_cmd_flag_none,
2677	  "<NDEF> <WPS> = create NFC handover request" },
2678	{ "nfc_get_handover_sel", wpa_cli_cmd_nfc_get_handover_sel, NULL,
2679	  cli_cmd_flag_none,
2680	  "<NDEF> <WPS> = create NFC handover select" },
2681	{ "nfc_report_handover", wpa_cli_cmd_nfc_report_handover, NULL,
2682	  cli_cmd_flag_none,
2683	  "<role> <type> <hexdump of req> <hexdump of sel> = report completed "
2684	  "NFC handover" },
2685#endif /* CONFIG_WPS_NFC */
2686	{ "wps_reg", wpa_cli_cmd_wps_reg, wpa_cli_complete_bss,
2687	  cli_cmd_flag_sensitive,
2688	  "<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
2689	{ "wps_ap_pin", wpa_cli_cmd_wps_ap_pin, NULL,
2690	  cli_cmd_flag_sensitive,
2691	  "[params..] = enable/disable AP PIN" },
2692	{ "wps_er_start", wpa_cli_cmd_wps_er_start, NULL,
2693	  cli_cmd_flag_none,
2694	  "[IP address] = start Wi-Fi Protected Setup External Registrar" },
2695	{ "wps_er_stop", wpa_cli_cmd_wps_er_stop, NULL,
2696	  cli_cmd_flag_none,
2697	  "= stop Wi-Fi Protected Setup External Registrar" },
2698	{ "wps_er_pin", wpa_cli_cmd_wps_er_pin, NULL,
2699	  cli_cmd_flag_sensitive,
2700	  "<UUID> <PIN> = add an Enrollee PIN to External Registrar" },
2701	{ "wps_er_pbc", wpa_cli_cmd_wps_er_pbc, NULL,
2702	  cli_cmd_flag_none,
2703	  "<UUID> = accept an Enrollee PBC using External Registrar" },
2704	{ "wps_er_learn", wpa_cli_cmd_wps_er_learn, NULL,
2705	  cli_cmd_flag_sensitive,
2706	  "<UUID> <PIN> = learn AP configuration" },
2707	{ "wps_er_set_config", wpa_cli_cmd_wps_er_set_config, NULL,
2708	  cli_cmd_flag_none,
2709	  "<UUID> <network id> = set AP configuration for enrolling" },
2710	{ "wps_er_config", wpa_cli_cmd_wps_er_config, NULL,
2711	  cli_cmd_flag_sensitive,
2712	  "<UUID> <PIN> <SSID> <auth> <encr> <key> = configure AP" },
2713#ifdef CONFIG_WPS_NFC
2714	{ "wps_er_nfc_config_token", wpa_cli_cmd_wps_er_nfc_config_token, NULL,
2715	  cli_cmd_flag_none,
2716	  "<WPS/NDEF> <UUID> = build NFC configuration token" },
2717#endif /* CONFIG_WPS_NFC */
2718	{ "ibss_rsn", wpa_cli_cmd_ibss_rsn, NULL,
2719	  cli_cmd_flag_none,
2720	  "<addr> = request RSN authentication with <addr> in IBSS" },
2721#ifdef CONFIG_AP
2722	{ "sta", wpa_cli_cmd_sta, NULL,
2723	  cli_cmd_flag_none,
2724	  "<addr> = get information about an associated station (AP)" },
2725	{ "all_sta", wpa_cli_cmd_all_sta, NULL,
2726	  cli_cmd_flag_none,
2727	  "= get information about all associated stations (AP)" },
2728	{ "deauthenticate", wpa_cli_cmd_deauthenticate, NULL,
2729	  cli_cmd_flag_none,
2730	  "<addr> = deauthenticate a station" },
2731	{ "disassociate", wpa_cli_cmd_disassociate, NULL,
2732	  cli_cmd_flag_none,
2733	  "<addr> = disassociate a station" },
2734	{ "chan_switch", wpa_cli_cmd_chanswitch, NULL,
2735	  cli_cmd_flag_none,
2736	  "<cs_count> <freq> [sec_channel_offset=] [center_freq1=]"
2737	  " [center_freq2=] [bandwidth=] [blocktx] [ht|vht]"
2738	  " = CSA parameters" },
2739#endif /* CONFIG_AP */
2740	{ "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none,
2741	  "= notification of suspend/hibernate" },
2742	{ "resume", wpa_cli_cmd_resume, NULL, cli_cmd_flag_none,
2743	  "= notification of resume/thaw" },
2744#ifdef CONFIG_TESTING_OPTIONS
2745	{ "drop_sa", wpa_cli_cmd_drop_sa, NULL, cli_cmd_flag_none,
2746	  "= drop SA without deauth/disassoc (test command)" },
2747#endif /* CONFIG_TESTING_OPTIONS */
2748	{ "roam", wpa_cli_cmd_roam, wpa_cli_complete_bss,
2749	  cli_cmd_flag_none,
2750	  "<addr> = roam to the specified BSS" },
2751#ifdef CONFIG_P2P
2752	{ "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find,
2753	  cli_cmd_flag_none,
2754	  "[timeout] [type=*] = find P2P Devices for up-to timeout seconds" },
2755	{ "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, NULL, cli_cmd_flag_none,
2756	  "= stop P2P Devices search" },
2757	{ "p2p_connect", wpa_cli_cmd_p2p_connect, wpa_cli_complete_p2p_connect,
2758	  cli_cmd_flag_none,
2759	  "<addr> <\"pbc\"|PIN> [ht40] = connect to a P2P Device" },
2760	{ "p2p_listen", wpa_cli_cmd_p2p_listen, NULL, cli_cmd_flag_none,
2761	  "[timeout] = listen for P2P Devices for up-to timeout seconds" },
2762	{ "p2p_group_remove", wpa_cli_cmd_p2p_group_remove,
2763	  wpa_cli_complete_p2p_group_remove, cli_cmd_flag_none,
2764	  "<ifname> = remove P2P group interface (terminate group if GO)" },
2765	{ "p2p_group_add", wpa_cli_cmd_p2p_group_add, NULL, cli_cmd_flag_none,
2766	  "[ht40] = add a new P2P group (local end as GO)" },
2767	{ "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc,
2768	  wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
2769	  "<addr> <method> = request provisioning discovery" },
2770	{ "p2p_get_passphrase", wpa_cli_cmd_p2p_get_passphrase, NULL,
2771	  cli_cmd_flag_none,
2772	  "= get the passphrase for a group (GO only)" },
2773	{ "p2p_serv_disc_req", wpa_cli_cmd_p2p_serv_disc_req,
2774	  wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
2775	  "<addr> <TLVs> = schedule service discovery request" },
2776	{ "p2p_serv_disc_cancel_req", wpa_cli_cmd_p2p_serv_disc_cancel_req,
2777	  NULL, cli_cmd_flag_none,
2778	  "<id> = cancel pending service discovery request" },
2779	{ "p2p_serv_disc_resp", wpa_cli_cmd_p2p_serv_disc_resp, NULL,
2780	  cli_cmd_flag_none,
2781	  "<freq> <addr> <dialog token> <TLVs> = service discovery response" },
2782	{ "p2p_service_update", wpa_cli_cmd_p2p_service_update, NULL,
2783	  cli_cmd_flag_none,
2784	  "= indicate change in local services" },
2785	{ "p2p_serv_disc_external", wpa_cli_cmd_p2p_serv_disc_external, NULL,
2786	  cli_cmd_flag_none,
2787	  "<external> = set external processing of service discovery" },
2788	{ "p2p_service_flush", wpa_cli_cmd_p2p_service_flush, NULL,
2789	  cli_cmd_flag_none,
2790	  "= remove all stored service entries" },
2791	{ "p2p_service_add", wpa_cli_cmd_p2p_service_add, NULL,
2792	  cli_cmd_flag_none,
2793	  "<bonjour|upnp> <query|version> <response|service> = add a local "
2794	  "service" },
2795	{ "p2p_service_del", wpa_cli_cmd_p2p_service_del, NULL,
2796	  cli_cmd_flag_none,
2797	  "<bonjour|upnp> <query|version> [|service] = remove a local "
2798	  "service" },
2799	{ "p2p_reject", wpa_cli_cmd_p2p_reject, wpa_cli_complete_p2p_peer,
2800	  cli_cmd_flag_none,
2801	  "<addr> = reject connection attempts from a specific peer" },
2802	{ "p2p_invite", wpa_cli_cmd_p2p_invite, NULL,
2803	  cli_cmd_flag_none,
2804	  "<cmd> [peer=addr] = invite peer" },
2805	{ "p2p_peers", wpa_cli_cmd_p2p_peers, NULL, cli_cmd_flag_none,
2806	  "[discovered] = list known (optionally, only fully discovered) P2P "
2807	  "peers" },
2808	{ "p2p_peer", wpa_cli_cmd_p2p_peer, wpa_cli_complete_p2p_peer,
2809	  cli_cmd_flag_none,
2810	  "<address> = show information about known P2P peer" },
2811	{ "p2p_set", wpa_cli_cmd_p2p_set, wpa_cli_complete_p2p_set,
2812	  cli_cmd_flag_none,
2813	  "<field> <value> = set a P2P parameter" },
2814	{ "p2p_flush", wpa_cli_cmd_p2p_flush, NULL, cli_cmd_flag_none,
2815	  "= flush P2P state" },
2816	{ "p2p_cancel", wpa_cli_cmd_p2p_cancel, NULL, cli_cmd_flag_none,
2817	  "= cancel P2P group formation" },
2818	{ "p2p_unauthorize", wpa_cli_cmd_p2p_unauthorize,
2819	  wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
2820	  "<address> = unauthorize a peer" },
2821	{ "p2p_presence_req", wpa_cli_cmd_p2p_presence_req, NULL,
2822	  cli_cmd_flag_none,
2823	  "[<duration> <interval>] [<duration> <interval>] = request GO "
2824	  "presence" },
2825	{ "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, NULL,
2826	  cli_cmd_flag_none,
2827	  "[<period> <interval>] = set extended listen timing" },
2828	{ "p2p_remove_client", wpa_cli_cmd_p2p_remove_client,
2829	  wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
2830	  "<address|iface=address> = remove a peer from all groups" },
2831#endif /* CONFIG_P2P */
2832#ifdef CONFIG_WIFI_DISPLAY
2833	{ "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL,
2834	  cli_cmd_flag_none,
2835	  "<subelem> [contents] = set Wi-Fi Display subelement" },
2836	{ "wfd_subelem_get", wpa_cli_cmd_wfd_subelem_get, NULL,
2837	  cli_cmd_flag_none,
2838	  "<subelem> = get Wi-Fi Display subelement" },
2839#endif /* CONFIG_WIFI_DISPLAY */
2840#ifdef CONFIG_INTERWORKING
2841	{ "fetch_anqp", wpa_cli_cmd_fetch_anqp, NULL, cli_cmd_flag_none,
2842	  "= fetch ANQP information for all APs" },
2843	{ "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, NULL,
2844	  cli_cmd_flag_none,
2845	  "= stop fetch_anqp operation" },
2846	{ "interworking_select", wpa_cli_cmd_interworking_select, NULL,
2847	  cli_cmd_flag_none,
2848	  "[auto] = perform Interworking network selection" },
2849	{ "interworking_connect", wpa_cli_cmd_interworking_connect,
2850	  wpa_cli_complete_bss, cli_cmd_flag_none,
2851	  "<BSSID> = connect using Interworking credentials" },
2852	{ "anqp_get", wpa_cli_cmd_anqp_get, wpa_cli_complete_bss,
2853	  cli_cmd_flag_none,
2854	  "<addr> <info id>[,<info id>]... = request ANQP information" },
2855	{ "gas_request", wpa_cli_cmd_gas_request, wpa_cli_complete_bss,
2856	  cli_cmd_flag_none,
2857	  "<addr> <AdvProtoID> [QueryReq] = GAS request" },
2858	{ "gas_response_get", wpa_cli_cmd_gas_response_get,
2859	  wpa_cli_complete_bss, cli_cmd_flag_none,
2860	  "<addr> <dialog token> [start,len] = Fetch last GAS response" },
2861#endif /* CONFIG_INTERWORKING */
2862#ifdef CONFIG_HS20
2863	{ "hs20_anqp_get", wpa_cli_cmd_hs20_anqp_get, wpa_cli_complete_bss,
2864	  cli_cmd_flag_none,
2865	  "<addr> <subtype>[,<subtype>]... = request HS 2.0 ANQP information"
2866	},
2867	{ "nai_home_realm_list", wpa_cli_cmd_get_nai_home_realm_list,
2868	  wpa_cli_complete_bss, cli_cmd_flag_none,
2869	  "<addr> <home realm> = get HS20 nai home realm list" },
2870	{ "hs20_icon_request", wpa_cli_cmd_hs20_icon_request,
2871	  wpa_cli_complete_bss, cli_cmd_flag_none,
2872	  "<addr> <icon name> = get Hotspot 2.0 OSU icon" },
2873	{ "fetch_osu", wpa_cli_cmd_fetch_osu, NULL, cli_cmd_flag_none,
2874	  "= fetch OSU provider information from all APs" },
2875	{ "cancel_fetch_osu", wpa_cli_cmd_cancel_fetch_osu, NULL,
2876	  cli_cmd_flag_none,
2877	  "= cancel fetch_osu command" },
2878#endif /* CONFIG_HS20 */
2879	{ "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, NULL,
2880	  cli_cmd_flag_none,
2881	  "<0/1> = disable/enable automatic reconnection" },
2882	{ "tdls_discover", wpa_cli_cmd_tdls_discover, NULL,
2883	  cli_cmd_flag_none,
2884	  "<addr> = request TDLS discovery with <addr>" },
2885	{ "tdls_setup", wpa_cli_cmd_tdls_setup, NULL,
2886	  cli_cmd_flag_none,
2887	  "<addr> = request TDLS setup with <addr>" },
2888	{ "tdls_teardown", wpa_cli_cmd_tdls_teardown, NULL,
2889	  cli_cmd_flag_none,
2890	  "<addr> = tear down TDLS with <addr>" },
2891	{ "signal_poll", wpa_cli_cmd_signal_poll, NULL,
2892	  cli_cmd_flag_none,
2893	  "= get signal parameters" },
2894	{ "pktcnt_poll", wpa_cli_cmd_pktcnt_poll, NULL,
2895	  cli_cmd_flag_none,
2896	  "= get TX/RX packet counters" },
2897	{ "reauthenticate", wpa_cli_cmd_reauthenticate, NULL,
2898	  cli_cmd_flag_none,
2899	  "= trigger IEEE 802.1X/EAPOL reauthentication" },
2900#ifdef CONFIG_AUTOSCAN
2901	{ "autoscan", wpa_cli_cmd_autoscan, NULL, cli_cmd_flag_none,
2902	  "[params] = Set or unset (if none) autoscan parameters" },
2903#endif /* CONFIG_AUTOSCAN */
2904#ifdef CONFIG_WNM
2905	{ "wnm_sleep", wpa_cli_cmd_wnm_sleep, NULL, cli_cmd_flag_none,
2906	  "<enter/exit> [interval=#] = enter/exit WNM-Sleep mode" },
2907	{ "wnm_bss_query", wpa_cli_cmd_wnm_bss_query, NULL, cli_cmd_flag_none,
2908	  "<query reason> = Send BSS Transition Management Query" },
2909#endif /* CONFIG_WNM */
2910	{ "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive,
2911	  "<params..> = Sent unprocessed command" },
2912	{ "flush", wpa_cli_cmd_flush, NULL, cli_cmd_flag_none,
2913	  "= flush wpa_supplicant state" },
2914#ifdef ANDROID
2915	{ "driver", wpa_cli_cmd_driver, NULL, cli_cmd_flag_none,
2916	  "<command> = driver private commands" },
2917#endif /* ANDROID */
2918	{ "radio_work", wpa_cli_cmd_radio_work, NULL, cli_cmd_flag_none,
2919	  "= radio_work <show/add/done>" },
2920	{ "vendor", wpa_cli_cmd_vendor, NULL, cli_cmd_flag_none,
2921	  "<vendor id> <command id> [<hex formatted command argument>] = Send vendor command"
2922	},
2923	{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
2924};
2925
2926
2927/*
2928 * Prints command usage, lines are padded with the specified string.
2929 */
2930static void print_cmd_help(struct wpa_cli_cmd *cmd, const char *pad)
2931{
2932	char c;
2933	size_t n;
2934
2935	printf("%s%s ", pad, cmd->cmd);
2936	for (n = 0; (c = cmd->usage[n]); n++) {
2937		printf("%c", c);
2938		if (c == '\n')
2939			printf("%s", pad);
2940	}
2941	printf("\n");
2942}
2943
2944
2945static void print_help(const char *cmd)
2946{
2947	int n;
2948	printf("commands:\n");
2949	for (n = 0; wpa_cli_commands[n].cmd; n++) {
2950		if (cmd == NULL || str_starts(wpa_cli_commands[n].cmd, cmd))
2951			print_cmd_help(&wpa_cli_commands[n], "  ");
2952	}
2953}
2954
2955
2956static int wpa_cli_edit_filter_history_cb(void *ctx, const char *cmd)
2957{
2958	const char *c, *delim;
2959	int n;
2960	size_t len;
2961
2962	delim = os_strchr(cmd, ' ');
2963	if (delim)
2964		len = delim - cmd;
2965	else
2966		len = os_strlen(cmd);
2967
2968	for (n = 0; (c = wpa_cli_commands[n].cmd); n++) {
2969		if (os_strncasecmp(cmd, c, len) == 0 && len == os_strlen(c))
2970			return (wpa_cli_commands[n].flags &
2971				cli_cmd_flag_sensitive);
2972	}
2973	return 0;
2974}
2975
2976
2977static char ** wpa_list_cmd_list(void)
2978{
2979	char **res;
2980	int i, count;
2981	struct cli_txt_entry *e;
2982
2983	count = ARRAY_SIZE(wpa_cli_commands);
2984	count += dl_list_len(&p2p_groups);
2985	count += dl_list_len(&ifnames);
2986	res = os_calloc(count + 1, sizeof(char *));
2987	if (res == NULL)
2988		return NULL;
2989
2990	for (i = 0; wpa_cli_commands[i].cmd; i++) {
2991		res[i] = os_strdup(wpa_cli_commands[i].cmd);
2992		if (res[i] == NULL)
2993			break;
2994	}
2995
2996	dl_list_for_each(e, &p2p_groups, struct cli_txt_entry, list) {
2997		size_t len = 8 + os_strlen(e->txt);
2998		res[i] = os_malloc(len);
2999		if (res[i] == NULL)
3000			break;
3001		os_snprintf(res[i], len, "ifname=%s", e->txt);
3002		i++;
3003	}
3004
3005	dl_list_for_each(e, &ifnames, struct cli_txt_entry, list) {
3006		res[i] = os_strdup(e->txt);
3007		if (res[i] == NULL)
3008			break;
3009		i++;
3010	}
3011
3012	return res;
3013}
3014
3015
3016static char ** wpa_cli_cmd_completion(const char *cmd, const char *str,
3017				      int pos)
3018{
3019	int i;
3020
3021	for (i = 0; wpa_cli_commands[i].cmd; i++) {
3022		if (os_strcasecmp(wpa_cli_commands[i].cmd, cmd) == 0) {
3023			if (wpa_cli_commands[i].completion)
3024				return wpa_cli_commands[i].completion(str,
3025								      pos);
3026			edit_clear_line();
3027			printf("\r%s\n", wpa_cli_commands[i].usage);
3028			edit_redraw();
3029			break;
3030		}
3031	}
3032
3033	return NULL;
3034}
3035
3036
3037static char ** wpa_cli_edit_completion_cb(void *ctx, const char *str, int pos)
3038{
3039	char **res;
3040	const char *end;
3041	char *cmd;
3042
3043	if (pos > 7 && os_strncasecmp(str, "IFNAME=", 7) == 0) {
3044		end = os_strchr(str, ' ');
3045		if (end && pos > end - str) {
3046			pos -= end - str + 1;
3047			str = end + 1;
3048		}
3049	}
3050
3051	end = os_strchr(str, ' ');
3052	if (end == NULL || str + pos < end)
3053		return wpa_list_cmd_list();
3054
3055	cmd = os_malloc(pos + 1);
3056	if (cmd == NULL)
3057		return NULL;
3058	os_memcpy(cmd, str, pos);
3059	cmd[end - str] = '\0';
3060	res = wpa_cli_cmd_completion(cmd, str, pos);
3061	os_free(cmd);
3062	return res;
3063}
3064
3065
3066static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
3067{
3068	struct wpa_cli_cmd *cmd, *match = NULL;
3069	int count;
3070	int ret = 0;
3071
3072	if (argc > 1 && os_strncasecmp(argv[0], "IFNAME=", 7) == 0) {
3073		ifname_prefix = argv[0] + 7;
3074		argv = &argv[1];
3075		argc--;
3076	} else
3077		ifname_prefix = NULL;
3078
3079	if (argc == 0)
3080		return -1;
3081
3082	count = 0;
3083	cmd = wpa_cli_commands;
3084	while (cmd->cmd) {
3085		if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0)
3086		{
3087			match = cmd;
3088			if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
3089				/* we have an exact match */
3090				count = 1;
3091				break;
3092			}
3093			count++;
3094		}
3095		cmd++;
3096	}
3097
3098	if (count > 1) {
3099		printf("Ambiguous command '%s'; possible commands:", argv[0]);
3100		cmd = wpa_cli_commands;
3101		while (cmd->cmd) {
3102			if (os_strncasecmp(cmd->cmd, argv[0],
3103					   os_strlen(argv[0])) == 0) {
3104				printf(" %s", cmd->cmd);
3105			}
3106			cmd++;
3107		}
3108		printf("\n");
3109		ret = 1;
3110	} else if (count == 0) {
3111		printf("Unknown command '%s'\n", argv[0]);
3112		ret = 1;
3113	} else {
3114		ret = match->handler(ctrl, argc - 1, &argv[1]);
3115	}
3116
3117	return ret;
3118}
3119
3120
3121static int str_match(const char *a, const char *b)
3122{
3123	return os_strncmp(a, b, os_strlen(b)) == 0;
3124}
3125
3126
3127static int wpa_cli_exec(const char *program, const char *arg1,
3128			const char *arg2)
3129{
3130	char *cmd;
3131	size_t len;
3132	int res;
3133	int ret = 0;
3134
3135	len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
3136	cmd = os_malloc(len);
3137	if (cmd == NULL)
3138		return -1;
3139	res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
3140	if (res < 0 || (size_t) res >= len) {
3141		os_free(cmd);
3142		return -1;
3143	}
3144	cmd[len - 1] = '\0';
3145#ifndef _WIN32_WCE
3146	if (system(cmd) < 0)
3147		ret = -1;
3148#endif /* _WIN32_WCE */
3149	os_free(cmd);
3150
3151	return ret;
3152}
3153
3154
3155static void wpa_cli_action_process(const char *msg)
3156{
3157	const char *pos;
3158	char *copy = NULL, *id, *pos2;
3159
3160	pos = msg;
3161	if (*pos == '<') {
3162		/* skip priority */
3163		pos = os_strchr(pos, '>');
3164		if (pos)
3165			pos++;
3166		else
3167			pos = msg;
3168	}
3169
3170	if (str_match(pos, WPA_EVENT_CONNECTED)) {
3171		int new_id = -1;
3172		os_unsetenv("WPA_ID");
3173		os_unsetenv("WPA_ID_STR");
3174		os_unsetenv("WPA_CTRL_DIR");
3175
3176		pos = os_strstr(pos, "[id=");
3177		if (pos)
3178			copy = os_strdup(pos + 4);
3179
3180		if (copy) {
3181			pos2 = id = copy;
3182			while (*pos2 && *pos2 != ' ')
3183				pos2++;
3184			*pos2++ = '\0';
3185			new_id = atoi(id);
3186			os_setenv("WPA_ID", id, 1);
3187			while (*pos2 && *pos2 != '=')
3188				pos2++;
3189			if (*pos2 == '=')
3190				pos2++;
3191			id = pos2;
3192			while (*pos2 && *pos2 != ']')
3193				pos2++;
3194			*pos2 = '\0';
3195			os_setenv("WPA_ID_STR", id, 1);
3196			os_free(copy);
3197		}
3198
3199		os_setenv("WPA_CTRL_DIR", ctrl_iface_dir, 1);
3200
3201		if (wpa_cli_connected <= 0 || new_id != wpa_cli_last_id) {
3202			wpa_cli_connected = 1;
3203			wpa_cli_last_id = new_id;
3204			wpa_cli_exec(action_file, ctrl_ifname, "CONNECTED");
3205		}
3206	} else if (str_match(pos, WPA_EVENT_DISCONNECTED)) {
3207		if (wpa_cli_connected) {
3208			wpa_cli_connected = 0;
3209			wpa_cli_exec(action_file, ctrl_ifname, "DISCONNECTED");
3210		}
3211	} else if (str_match(pos, P2P_EVENT_GROUP_STARTED)) {
3212		wpa_cli_exec(action_file, ctrl_ifname, pos);
3213	} else if (str_match(pos, P2P_EVENT_GROUP_REMOVED)) {
3214		wpa_cli_exec(action_file, ctrl_ifname, pos);
3215	} else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) {
3216		wpa_cli_exec(action_file, ctrl_ifname, pos);
3217	} else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) {
3218		wpa_cli_exec(action_file, ctrl_ifname, pos);
3219	} else if (str_match(pos, P2P_EVENT_GO_NEG_FAILURE)) {
3220		wpa_cli_exec(action_file, ctrl_ifname, pos);
3221	} else if (str_match(pos, WPS_EVENT_SUCCESS)) {
3222		wpa_cli_exec(action_file, ctrl_ifname, pos);
3223	} else if (str_match(pos, WPS_EVENT_FAIL)) {
3224		wpa_cli_exec(action_file, ctrl_ifname, pos);
3225	} else if (str_match(pos, AP_STA_CONNECTED)) {
3226		wpa_cli_exec(action_file, ctrl_ifname, pos);
3227	} else if (str_match(pos, AP_STA_DISCONNECTED)) {
3228		wpa_cli_exec(action_file, ctrl_ifname, pos);
3229	} else if (str_match(pos, ESS_DISASSOC_IMMINENT)) {
3230		wpa_cli_exec(action_file, ctrl_ifname, pos);
3231	} else if (str_match(pos, HS20_SUBSCRIPTION_REMEDIATION)) {
3232		wpa_cli_exec(action_file, ctrl_ifname, pos);
3233	} else if (str_match(pos, HS20_DEAUTH_IMMINENT_NOTICE)) {
3234		wpa_cli_exec(action_file, ctrl_ifname, pos);
3235	} else if (str_match(pos, WPA_EVENT_TERMINATING)) {
3236		printf("wpa_supplicant is terminating - stop monitoring\n");
3237		wpa_cli_quit = 1;
3238	}
3239}
3240
3241
3242#ifndef CONFIG_ANSI_C_EXTRA
3243static void wpa_cli_action_cb(char *msg, size_t len)
3244{
3245	wpa_cli_action_process(msg);
3246}
3247#endif /* CONFIG_ANSI_C_EXTRA */
3248
3249
3250static void wpa_cli_reconnect(void)
3251{
3252	wpa_cli_close_connection();
3253	if (wpa_cli_open_connection(ctrl_ifname, 1) < 0)
3254		return;
3255
3256	if (interactive) {
3257		edit_clear_line();
3258		printf("\rConnection to wpa_supplicant re-established\n");
3259		edit_redraw();
3260	}
3261}
3262
3263
3264static void cli_event(const char *str)
3265{
3266	const char *start, *s;
3267
3268	start = os_strchr(str, '>');
3269	if (start == NULL)
3270		return;
3271
3272	start++;
3273
3274	if (str_starts(start, WPA_EVENT_BSS_ADDED)) {
3275		s = os_strchr(start, ' ');
3276		if (s == NULL)
3277			return;
3278		s = os_strchr(s + 1, ' ');
3279		if (s == NULL)
3280			return;
3281		cli_txt_list_add(&bsses, s + 1);
3282		return;
3283	}
3284
3285	if (str_starts(start, WPA_EVENT_BSS_REMOVED)) {
3286		s = os_strchr(start, ' ');
3287		if (s == NULL)
3288			return;
3289		s = os_strchr(s + 1, ' ');
3290		if (s == NULL)
3291			return;
3292		cli_txt_list_del_addr(&bsses, s + 1);
3293		return;
3294	}
3295
3296#ifdef CONFIG_P2P
3297	if (str_starts(start, P2P_EVENT_DEVICE_FOUND)) {
3298		s = os_strstr(start, " p2p_dev_addr=");
3299		if (s == NULL)
3300			return;
3301		cli_txt_list_add_addr(&p2p_peers, s + 14);
3302		return;
3303	}
3304
3305	if (str_starts(start, P2P_EVENT_DEVICE_LOST)) {
3306		s = os_strstr(start, " p2p_dev_addr=");
3307		if (s == NULL)
3308			return;
3309		cli_txt_list_del_addr(&p2p_peers, s + 14);
3310		return;
3311	}
3312
3313	if (str_starts(start, P2P_EVENT_GROUP_STARTED)) {
3314		s = os_strchr(start, ' ');
3315		if (s == NULL)
3316			return;
3317		cli_txt_list_add_word(&p2p_groups, s + 1);
3318		return;
3319	}
3320
3321	if (str_starts(start, P2P_EVENT_GROUP_REMOVED)) {
3322		s = os_strchr(start, ' ');
3323		if (s == NULL)
3324			return;
3325		cli_txt_list_del_word(&p2p_groups, s + 1);
3326		return;
3327	}
3328#endif /* CONFIG_P2P */
3329}
3330
3331
3332static int check_terminating(const char *msg)
3333{
3334	const char *pos = msg;
3335
3336	if (*pos == '<') {
3337		/* skip priority */
3338		pos = os_strchr(pos, '>');
3339		if (pos)
3340			pos++;
3341		else
3342			pos = msg;
3343	}
3344
3345	if (str_match(pos, WPA_EVENT_TERMINATING) && ctrl_conn) {
3346		edit_clear_line();
3347		printf("\rConnection to wpa_supplicant lost - trying to "
3348		       "reconnect\n");
3349		edit_redraw();
3350		wpa_cli_attached = 0;
3351		wpa_cli_close_connection();
3352		return 1;
3353	}
3354
3355	return 0;
3356}
3357
3358
3359static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor)
3360{
3361	if (ctrl_conn == NULL) {
3362		wpa_cli_reconnect();
3363		return;
3364	}
3365	while (wpa_ctrl_pending(ctrl) > 0) {
3366		char buf[256];
3367		size_t len = sizeof(buf) - 1;
3368		if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
3369			buf[len] = '\0';
3370			if (action_monitor)
3371				wpa_cli_action_process(buf);
3372			else {
3373				cli_event(buf);
3374				if (wpa_cli_show_event(buf)) {
3375					edit_clear_line();
3376					printf("\r%s\n", buf);
3377					edit_redraw();
3378				}
3379
3380				if (interactive && check_terminating(buf) > 0)
3381					return;
3382			}
3383		} else {
3384			printf("Could not read pending message.\n");
3385			break;
3386		}
3387	}
3388
3389	if (wpa_ctrl_pending(ctrl) < 0) {
3390		printf("Connection to wpa_supplicant lost - trying to "
3391		       "reconnect\n");
3392		wpa_cli_reconnect();
3393	}
3394}
3395
3396#define max_args 10
3397
3398static int tokenize_cmd(char *cmd, char *argv[])
3399{
3400	char *pos;
3401	int argc = 0;
3402
3403	pos = cmd;
3404	for (;;) {
3405		while (*pos == ' ')
3406			pos++;
3407		if (*pos == '\0')
3408			break;
3409		argv[argc] = pos;
3410		argc++;
3411		if (argc == max_args)
3412			break;
3413		if (*pos == '"') {
3414			char *pos2 = os_strrchr(pos, '"');
3415			if (pos2)
3416				pos = pos2 + 1;
3417		}
3418		while (*pos != '\0' && *pos != ' ')
3419			pos++;
3420		if (*pos == ' ')
3421			*pos++ = '\0';
3422	}
3423
3424	return argc;
3425}
3426
3427
3428static void wpa_cli_ping(void *eloop_ctx, void *timeout_ctx)
3429{
3430	if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
3431		printf("Connection to wpa_supplicant lost - trying to "
3432		       "reconnect\n");
3433		wpa_cli_close_connection();
3434	}
3435	if (!ctrl_conn)
3436		wpa_cli_reconnect();
3437	eloop_register_timeout(ping_interval, 0, wpa_cli_ping, NULL, NULL);
3438}
3439
3440
3441static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx)
3442{
3443	wpa_cli_recv_pending(mon_conn, 0);
3444}
3445
3446
3447static void wpa_cli_edit_cmd_cb(void *ctx, char *cmd)
3448{
3449	char *argv[max_args];
3450	int argc;
3451	argc = tokenize_cmd(cmd, argv);
3452	if (argc)
3453		wpa_request(ctrl_conn, argc, argv);
3454}
3455
3456
3457static void wpa_cli_edit_eof_cb(void *ctx)
3458{
3459	eloop_terminate();
3460}
3461
3462
3463static int warning_displayed = 0;
3464static char *hfile = NULL;
3465static int edit_started = 0;
3466
3467static void start_edit(void)
3468{
3469	char *home;
3470	char *ps = NULL;
3471
3472#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
3473	ps = wpa_ctrl_get_remote_ifname(ctrl_conn);
3474#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
3475
3476	home = getenv("HOME");
3477	if (home) {
3478		const char *fname = ".wpa_cli_history";
3479		int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
3480		hfile = os_malloc(hfile_len);
3481		if (hfile)
3482			os_snprintf(hfile, hfile_len, "%s/%s", home, fname);
3483	}
3484
3485	if (edit_init(wpa_cli_edit_cmd_cb, wpa_cli_edit_eof_cb,
3486		      wpa_cli_edit_completion_cb, NULL, hfile, ps) < 0) {
3487		eloop_terminate();
3488		return;
3489	}
3490
3491	edit_started = 1;
3492	eloop_register_timeout(ping_interval, 0, wpa_cli_ping, NULL, NULL);
3493}
3494
3495
3496static void update_bssid_list(struct wpa_ctrl *ctrl)
3497{
3498	char buf[4096];
3499	size_t len = sizeof(buf);
3500	int ret;
3501	char *cmd = "BSS RANGE=ALL MASK=0x2";
3502	char *pos, *end;
3503
3504	if (ctrl == NULL)
3505		return;
3506	ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL);
3507	if (ret < 0)
3508		return;
3509	buf[len] = '\0';
3510
3511	pos = buf;
3512	while (pos) {
3513		pos = os_strstr(pos, "bssid=");
3514		if (pos == NULL)
3515			break;
3516		pos += 6;
3517		end = os_strchr(pos, '\n');
3518		if (end == NULL)
3519			break;
3520		*end = '\0';
3521		cli_txt_list_add(&bsses, pos);
3522		pos = end + 1;
3523	}
3524}
3525
3526
3527static void update_ifnames(struct wpa_ctrl *ctrl)
3528{
3529	char buf[4096];
3530	size_t len = sizeof(buf);
3531	int ret;
3532	char *cmd = "INTERFACES";
3533	char *pos, *end;
3534	char txt[200];
3535
3536	cli_txt_list_flush(&ifnames);
3537
3538	if (ctrl == NULL)
3539		return;
3540	ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL);
3541	if (ret < 0)
3542		return;
3543	buf[len] = '\0';
3544
3545	pos = buf;
3546	while (pos) {
3547		end = os_strchr(pos, '\n');
3548		if (end == NULL)
3549			break;
3550		*end = '\0';
3551		ret = os_snprintf(txt, sizeof(txt), "ifname=%s", pos);
3552		if (ret > 0 && ret < (int) sizeof(txt))
3553			cli_txt_list_add(&ifnames, txt);
3554		pos = end + 1;
3555	}
3556}
3557
3558
3559static void try_connection(void *eloop_ctx, void *timeout_ctx)
3560{
3561	if (ctrl_conn)
3562		goto done;
3563
3564	if (ctrl_ifname == NULL)
3565		ctrl_ifname = wpa_cli_get_default_ifname();
3566
3567	if (!wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
3568		if (!warning_displayed) {
3569			printf("Could not connect to wpa_supplicant: "
3570			       "%s - re-trying\n", ctrl_ifname);
3571			warning_displayed = 1;
3572		}
3573		eloop_register_timeout(1, 0, try_connection, NULL, NULL);
3574		return;
3575	}
3576
3577	update_bssid_list(ctrl_conn);
3578
3579	if (warning_displayed)
3580		printf("Connection established.\n");
3581
3582done:
3583	start_edit();
3584}
3585
3586
3587static void wpa_cli_interactive(void)
3588{
3589	printf("\nInteractive mode\n\n");
3590
3591	eloop_register_timeout(0, 0, try_connection, NULL, NULL);
3592	eloop_run();
3593	eloop_cancel_timeout(try_connection, NULL, NULL);
3594
3595	cli_txt_list_flush(&p2p_peers);
3596	cli_txt_list_flush(&p2p_groups);
3597	cli_txt_list_flush(&bsses);
3598	cli_txt_list_flush(&ifnames);
3599	if (edit_started)
3600		edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
3601	os_free(hfile);
3602	eloop_cancel_timeout(wpa_cli_ping, NULL, NULL);
3603	wpa_cli_close_connection();
3604}
3605
3606
3607static void wpa_cli_action(struct wpa_ctrl *ctrl)
3608{
3609#ifdef CONFIG_ANSI_C_EXTRA
3610	/* TODO: ANSI C version(?) */
3611	printf("Action processing not supported in ANSI C build.\n");
3612#else /* CONFIG_ANSI_C_EXTRA */
3613	fd_set rfds;
3614	int fd, res;
3615	struct timeval tv;
3616	char buf[256]; /* note: large enough to fit in unsolicited messages */
3617	size_t len;
3618
3619	fd = wpa_ctrl_get_fd(ctrl);
3620
3621	while (!wpa_cli_quit) {
3622		FD_ZERO(&rfds);
3623		FD_SET(fd, &rfds);
3624		tv.tv_sec = ping_interval;
3625		tv.tv_usec = 0;
3626		res = select(fd + 1, &rfds, NULL, NULL, &tv);
3627		if (res < 0 && errno != EINTR) {
3628			perror("select");
3629			break;
3630		}
3631
3632		if (FD_ISSET(fd, &rfds))
3633			wpa_cli_recv_pending(ctrl, 1);
3634		else {
3635			/* verify that connection is still working */
3636			len = sizeof(buf) - 1;
3637			if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
3638					     wpa_cli_action_cb) < 0 ||
3639			    len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
3640				printf("wpa_supplicant did not reply to PING "
3641				       "command - exiting\n");
3642				break;
3643			}
3644		}
3645	}
3646#endif /* CONFIG_ANSI_C_EXTRA */
3647}
3648
3649
3650static void wpa_cli_cleanup(void)
3651{
3652	wpa_cli_close_connection();
3653	if (pid_file)
3654		os_daemonize_terminate(pid_file);
3655
3656	os_program_deinit();
3657}
3658
3659
3660static void wpa_cli_terminate(int sig, void *ctx)
3661{
3662	eloop_terminate();
3663}
3664
3665
3666static char * wpa_cli_get_default_ifname(void)
3667{
3668	char *ifname = NULL;
3669
3670#ifdef CONFIG_CTRL_IFACE_UNIX
3671	struct dirent *dent;
3672	DIR *dir = opendir(ctrl_iface_dir);
3673	if (!dir) {
3674#ifdef ANDROID
3675		char ifprop[PROPERTY_VALUE_MAX];
3676		if (property_get("wifi.interface", ifprop, NULL) != 0) {
3677			ifname = os_strdup(ifprop);
3678			printf("Using interface '%s'\n", ifname);
3679			return ifname;
3680		}
3681#endif /* ANDROID */
3682		return NULL;
3683	}
3684	while ((dent = readdir(dir))) {
3685#ifdef _DIRENT_HAVE_D_TYPE
3686		/*
3687		 * Skip the file if it is not a socket. Also accept
3688		 * DT_UNKNOWN (0) in case the C library or underlying
3689		 * file system does not support d_type.
3690		 */
3691		if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
3692			continue;
3693#endif /* _DIRENT_HAVE_D_TYPE */
3694		if (os_strcmp(dent->d_name, ".") == 0 ||
3695		    os_strcmp(dent->d_name, "..") == 0)
3696			continue;
3697		printf("Selected interface '%s'\n", dent->d_name);
3698		ifname = os_strdup(dent->d_name);
3699		break;
3700	}
3701	closedir(dir);
3702#endif /* CONFIG_CTRL_IFACE_UNIX */
3703
3704#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
3705	char buf[4096], *pos;
3706	size_t len;
3707	struct wpa_ctrl *ctrl;
3708	int ret;
3709
3710	ctrl = wpa_ctrl_open(NULL);
3711	if (ctrl == NULL)
3712		return NULL;
3713
3714	len = sizeof(buf) - 1;
3715	ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL);
3716	if (ret >= 0) {
3717		buf[len] = '\0';
3718		pos = os_strchr(buf, '\n');
3719		if (pos)
3720			*pos = '\0';
3721		ifname = os_strdup(buf);
3722	}
3723	wpa_ctrl_close(ctrl);
3724#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
3725
3726	return ifname;
3727}
3728
3729
3730int main(int argc, char *argv[])
3731{
3732	int c;
3733	int daemonize = 0;
3734	int ret = 0;
3735	const char *global = NULL;
3736
3737	if (os_program_init())
3738		return -1;
3739
3740	for (;;) {
3741		c = getopt(argc, argv, "a:Bg:G:hi:p:P:v");
3742		if (c < 0)
3743			break;
3744		switch (c) {
3745		case 'a':
3746			action_file = optarg;
3747			break;
3748		case 'B':
3749			daemonize = 1;
3750			break;
3751		case 'g':
3752			global = optarg;
3753			break;
3754		case 'G':
3755			ping_interval = atoi(optarg);
3756			break;
3757		case 'h':
3758			usage();
3759			return 0;
3760		case 'v':
3761			printf("%s\n", wpa_cli_version);
3762			return 0;
3763		case 'i':
3764			os_free(ctrl_ifname);
3765			ctrl_ifname = os_strdup(optarg);
3766			break;
3767		case 'p':
3768			ctrl_iface_dir = optarg;
3769			break;
3770		case 'P':
3771			pid_file = optarg;
3772			break;
3773		default:
3774			usage();
3775			return -1;
3776		}
3777	}
3778
3779	interactive = (argc == optind) && (action_file == NULL);
3780
3781	if (interactive)
3782		printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license);
3783
3784	if (eloop_init())
3785		return -1;
3786
3787	if (global) {
3788#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
3789		ctrl_conn = wpa_ctrl_open(NULL);
3790#else /* CONFIG_CTRL_IFACE_NAMED_PIPE */
3791		ctrl_conn = wpa_ctrl_open(global);
3792#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
3793		if (ctrl_conn == NULL) {
3794			fprintf(stderr, "Failed to connect to wpa_supplicant "
3795				"global interface: %s  error: %s\n",
3796				global, strerror(errno));
3797			return -1;
3798		}
3799
3800		if (interactive) {
3801			update_ifnames(ctrl_conn);
3802			mon_conn = wpa_ctrl_open(global);
3803			if (mon_conn) {
3804				if (wpa_ctrl_attach(mon_conn) == 0) {
3805					wpa_cli_attached = 1;
3806					eloop_register_read_sock(
3807						wpa_ctrl_get_fd(mon_conn),
3808						wpa_cli_mon_receive,
3809						NULL, NULL);
3810				} else {
3811					printf("Failed to open monitor "
3812					       "connection through global "
3813					       "control interface\n");
3814				}
3815			}
3816		}
3817	}
3818
3819	eloop_register_signal_terminate(wpa_cli_terminate, NULL);
3820
3821	if (ctrl_ifname == NULL)
3822		ctrl_ifname = wpa_cli_get_default_ifname();
3823
3824	if (interactive) {
3825		wpa_cli_interactive();
3826	} else {
3827		if (!global &&
3828		    wpa_cli_open_connection(ctrl_ifname, 0) < 0) {
3829			fprintf(stderr, "Failed to connect to non-global "
3830				"ctrl_ifname: %s  error: %s\n",
3831				ctrl_ifname, strerror(errno));
3832			return -1;
3833		}
3834
3835		if (action_file) {
3836			if (wpa_ctrl_attach(ctrl_conn) == 0) {
3837				wpa_cli_attached = 1;
3838			} else {
3839				printf("Warning: Failed to attach to "
3840				       "wpa_supplicant.\n");
3841				return -1;
3842			}
3843		}
3844
3845		if (daemonize && os_daemonize(pid_file))
3846			return -1;
3847
3848		if (action_file)
3849			wpa_cli_action(ctrl_conn);
3850		else
3851			ret = wpa_request(ctrl_conn, argc - optind,
3852					  &argv[optind]);
3853	}
3854
3855	os_free(ctrl_ifname);
3856	eloop_destroy();
3857	wpa_cli_cleanup();
3858
3859	return ret;
3860}
3861
3862#else /* CONFIG_CTRL_IFACE */
3863int main(int argc, char *argv[])
3864{
3865	printf("CONFIG_CTRL_IFACE not defined - wpa_cli disabled\n");
3866	return -1;
3867}
3868#endif /* CONFIG_CTRL_IFACE */
3869