1/*
2 * WPA Supplicant - command line interface for wpa_supplicant daemon
3 * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "includes.h"
16
17#ifdef CONFIG_CTRL_IFACE
18
19#ifdef CONFIG_CTRL_IFACE_UNIX
20#include <dirent.h>
21#endif /* CONFIG_CTRL_IFACE_UNIX */
22#ifdef CONFIG_READLINE
23#include <readline/readline.h>
24#include <readline/history.h>
25#endif /* CONFIG_READLINE */
26#ifdef CONFIG_WPA_CLI_FORK
27#include <sys/wait.h>
28#endif /* CONFIG_WPA_CLI_FORK */
29
30#include "common/wpa_ctrl.h"
31#include "common.h"
32#include "common/version.h"
33
34
35static const char *wpa_cli_version =
36"wpa_cli v" VERSION_STR "\n"
37"Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi> and contributors";
38
39
40static const char *wpa_cli_license =
41"This program is free software. You can distribute it and/or modify it\n"
42"under the terms of the GNU General Public License version 2.\n"
43"\n"
44"Alternatively, this software may be distributed under the terms of the\n"
45"BSD license. See README and COPYING for more details.\n";
46
47static const char *wpa_cli_full_license =
48"This program is free software; you can redistribute it and/or modify\n"
49"it under the terms of the GNU General Public License version 2 as\n"
50"published by the Free Software Foundation.\n"
51"\n"
52"This program is distributed in the hope that it will be useful,\n"
53"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
54"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
55"GNU General Public License for more details.\n"
56"\n"
57"You should have received a copy of the GNU General Public License\n"
58"along with this program; if not, write to the Free Software\n"
59"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n"
60"\n"
61"Alternatively, this software may be distributed under the terms of the\n"
62"BSD license.\n"
63"\n"
64"Redistribution and use in source and binary forms, with or without\n"
65"modification, are permitted provided that the following conditions are\n"
66"met:\n"
67"\n"
68"1. Redistributions of source code must retain the above copyright\n"
69"   notice, this list of conditions and the following disclaimer.\n"
70"\n"
71"2. Redistributions in binary form must reproduce the above copyright\n"
72"   notice, this list of conditions and the following disclaimer in the\n"
73"   documentation and/or other materials provided with the distribution.\n"
74"\n"
75"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
76"   names of its contributors may be used to endorse or promote products\n"
77"   derived from this software without specific prior written permission.\n"
78"\n"
79"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
80"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
81"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
82"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
83"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
84"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
85"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
86"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
87"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
88"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
89"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
90"\n";
91
92static struct wpa_ctrl *ctrl_conn;
93static struct wpa_ctrl *mon_conn;
94#ifdef CONFIG_WPA_CLI_FORK
95static pid_t mon_pid = 0;
96#endif /* CONFIG_WPA_CLI_FORK */
97static int wpa_cli_quit = 0;
98static int wpa_cli_attached = 0;
99static int wpa_cli_connected = 0;
100static int wpa_cli_last_id = 0;
101static const char *ctrl_iface_dir = "/var/run/wpa_supplicant";
102static char *ctrl_ifname = NULL;
103static const char *pid_file = NULL;
104static const char *action_file = NULL;
105static int ping_interval = 5;
106static int interactive = 0;
107
108
109static void print_help();
110
111
112static void usage(void)
113{
114	printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] "
115	       "[-a<action file>] \\\n"
116	       "        [-P<pid file>] [-g<global ctrl>] [-G<ping interval>]  "
117	       "[command..]\n"
118	       "  -h = help (show this usage text)\n"
119	       "  -v = shown version information\n"
120	       "  -a = run in daemon mode executing the action file based on "
121	       "events from\n"
122	       "       wpa_supplicant\n"
123	       "  -B = run a daemon in the background\n"
124	       "  default path: /var/run/wpa_supplicant\n"
125	       "  default interface: first interface found in socket path\n");
126	print_help();
127}
128
129
130#ifdef CONFIG_WPA_CLI_FORK
131static int in_query = 0;
132
133static void wpa_cli_monitor_sig(int sig)
134{
135	if (sig == SIGUSR1)
136		in_query = 1;
137	else if (sig == SIGUSR2)
138		in_query = 0;
139}
140
141static void wpa_cli_monitor(void)
142{
143	char buf[256];
144	size_t len = sizeof(buf) - 1;
145	struct timeval tv;
146	fd_set rfds;
147
148	signal(SIGUSR1, wpa_cli_monitor_sig);
149	signal(SIGUSR2, wpa_cli_monitor_sig);
150
151	while (mon_conn) {
152		int s = wpa_ctrl_get_fd(mon_conn);
153		tv.tv_sec = 5;
154		tv.tv_usec = 0;
155		FD_ZERO(&rfds);
156		FD_SET(s, &rfds);
157		if (select(s + 1, &rfds, NULL, NULL, &tv) < 0) {
158			if (errno == EINTR)
159				continue;
160			perror("select");
161			break;
162		}
163		if (mon_conn == NULL)
164			break;
165		if (FD_ISSET(s, &rfds)) {
166			len = sizeof(buf) - 1;
167			int res = wpa_ctrl_recv(mon_conn, buf, &len);
168			if (res < 0) {
169				perror("wpa_ctrl_recv");
170				break;
171			}
172			buf[len] = '\0';
173			if (in_query)
174				printf("\r");
175			printf("%s\n", buf);
176			kill(getppid(), SIGUSR1);
177		}
178	}
179}
180#endif /* CONFIG_WPA_CLI_FORK */
181
182
183static int wpa_cli_open_connection(const char *ifname, int attach)
184{
185#if defined(CONFIG_CTRL_IFACE_UDP) || defined(CONFIG_CTRL_IFACE_NAMED_PIPE)
186	ctrl_conn = wpa_ctrl_open(ifname);
187	if (ctrl_conn == NULL)
188		return -1;
189
190	if (attach && interactive)
191		mon_conn = wpa_ctrl_open(ifname);
192	else
193		mon_conn = NULL;
194#else /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
195	char *cfile;
196	int flen, res;
197
198	if (ifname == NULL)
199		return -1;
200
201	flen = os_strlen(ctrl_iface_dir) + os_strlen(ifname) + 2;
202	cfile = os_malloc(flen);
203	if (cfile == NULL)
204		return -1L;
205	res = os_snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
206	if (res < 0 || res >= flen) {
207		os_free(cfile);
208		return -1;
209	}
210
211	ctrl_conn = wpa_ctrl_open(cfile);
212	if (ctrl_conn == NULL) {
213		os_free(cfile);
214		return -1;
215	}
216
217	if (attach && interactive)
218		mon_conn = wpa_ctrl_open(cfile);
219	else
220		mon_conn = NULL;
221	os_free(cfile);
222#endif /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
223
224	if (mon_conn) {
225		if (wpa_ctrl_attach(mon_conn) == 0) {
226			wpa_cli_attached = 1;
227		} else {
228			printf("Warning: Failed to attach to "
229			       "wpa_supplicant.\n");
230			return -1;
231		}
232
233#ifdef CONFIG_WPA_CLI_FORK
234		{
235			pid_t p = fork();
236			if (p < 0) {
237				perror("fork");
238				return -1;
239			}
240			if (p == 0) {
241				wpa_cli_monitor();
242				exit(0);
243			} else
244				mon_pid = p;
245		}
246#endif /* CONFIG_WPA_CLI_FORK */
247	}
248
249	return 0;
250}
251
252
253static void wpa_cli_close_connection(void)
254{
255	if (ctrl_conn == NULL)
256		return;
257
258#ifdef CONFIG_WPA_CLI_FORK
259	if (mon_pid) {
260		int status;
261		kill(mon_pid, SIGPIPE);
262		wait(&status);
263		mon_pid = 0;
264	}
265#endif /* CONFIG_WPA_CLI_FORK */
266
267	if (wpa_cli_attached) {
268		wpa_ctrl_detach(interactive ? mon_conn : ctrl_conn);
269		wpa_cli_attached = 0;
270	}
271	wpa_ctrl_close(ctrl_conn);
272	ctrl_conn = NULL;
273	if (mon_conn) {
274		wpa_ctrl_close(mon_conn);
275		mon_conn = NULL;
276	}
277}
278
279static const char *skip_priority(const char *msg)
280{
281	const char *pos = msg;
282
283	if (*msg != '<')
284		return msg;
285
286	for (pos = msg + 1; isdigit((unsigned char)*pos); pos++)
287		continue;
288
289	if (*pos != '>')
290		return msg;
291
292	return ++pos;
293}
294
295static const char *fmttime(char *buf, size_t buflen)
296{
297	struct timeval tv;
298	struct tm tm;
299	time_t t;
300
301	if (buflen <= 8)
302		return NULL;
303
304	(void)gettimeofday(&tv, NULL);
305	t = (time_t)tv.tv_sec;
306	(void)localtime_r(&t, &tm);
307	(void)strftime(buf, buflen, "%H:%M:%S", &tm);
308	(void)snprintf(buf + 8, buflen - 8, ".%.3d", (int)(tv.tv_usec / 1000));
309	return buf;
310}
311
312static void wpa_cli_msg_cb(char *msg, size_t len)
313{
314	char tbuf[32];
315	printf("%s: %s\n", fmttime(tbuf, sizeof(tbuf)), skip_priority(msg));
316}
317
318
319static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
320{
321	char buf[2048];
322	size_t len;
323	int ret;
324
325	if (ctrl_conn == NULL) {
326		printf("Not connected to wpa_supplicant - command dropped.\n");
327		return -1;
328	}
329	len = sizeof(buf) - 1;
330	ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
331			       wpa_cli_msg_cb);
332	if (ret == -2) {
333		printf("'%s' command timed out.\n", cmd);
334		return -2;
335	} else if (ret < 0) {
336		printf("'%s' command failed.\n", cmd);
337		return -1;
338	}
339	if (print) {
340		buf[len] = '\0';
341		wpa_cli_msg_cb(buf, 0);
342	}
343	return 0;
344}
345
346
347static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
348{
349	return _wpa_ctrl_command(ctrl, cmd, 1);
350}
351
352
353static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
354{
355	int verbose = argc > 0 && os_strcmp(argv[0], "verbose") == 0;
356	return wpa_ctrl_command(ctrl, verbose ? "STATUS-VERBOSE" : "STATUS");
357}
358
359
360static int wpa_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
361{
362	return wpa_ctrl_command(ctrl, "PING");
363}
364
365
366static int wpa_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
367{
368	return wpa_ctrl_command(ctrl, "MIB");
369}
370
371
372static int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
373{
374	return wpa_ctrl_command(ctrl, "PMKSA");
375}
376
377
378static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
379{
380	print_help();
381	return 0;
382}
383
384
385static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[])
386{
387	printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license);
388	return 0;
389}
390
391
392static int wpa_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
393{
394	wpa_cli_quit = 1;
395	return 0;
396}
397
398
399static void wpa_cli_show_variables(void)
400{
401	printf("set variables:\n"
402	       "  EAPOL::heldPeriod (EAPOL state machine held period, "
403	       "in seconds)\n"
404	       "  EAPOL::authPeriod (EAPOL state machine authentication "
405	       "period, in seconds)\n"
406	       "  EAPOL::startPeriod (EAPOL state machine start period, in "
407	       "seconds)\n"
408	       "  EAPOL::maxStart (EAPOL state machine maximum start "
409	       "attempts)\n");
410	printf("  dot11RSNAConfigPMKLifetime (WPA/WPA2 PMK lifetime in "
411	       "seconds)\n"
412	       "  dot11RSNAConfigPMKReauthThreshold (WPA/WPA2 reauthentication"
413	       " threshold\n\tpercentage)\n"
414	       "  dot11RSNAConfigSATimeout (WPA/WPA2 timeout for completing "
415	       "security\n\tassociation in seconds)\n");
416}
417
418
419static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
420{
421	char cmd[256];
422	int res;
423
424	if (argc == 0) {
425		wpa_cli_show_variables();
426		return 0;
427	}
428
429	if (argc != 2) {
430		printf("Invalid SET command: needs two arguments (variable "
431		       "name and value)\n");
432		return -1;
433	}
434
435	res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
436	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
437		printf("Too long SET command.\n");
438		return -1;
439	}
440	return wpa_ctrl_command(ctrl, cmd);
441}
442
443
444static int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[])
445{
446	return wpa_ctrl_command(ctrl, "LOGOFF");
447}
448
449
450static int wpa_cli_cmd_logon(struct wpa_ctrl *ctrl, int argc, char *argv[])
451{
452	return wpa_ctrl_command(ctrl, "LOGON");
453}
454
455
456static int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc,
457				   char *argv[])
458{
459	return wpa_ctrl_command(ctrl, "REASSOCIATE");
460}
461
462
463static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc,
464				       char *argv[])
465{
466	char cmd[256];
467	int res;
468
469	if (argc != 1) {
470		printf("Invalid PREAUTH command: needs one argument "
471		       "(BSSID)\n");
472		return -1;
473	}
474
475	res = os_snprintf(cmd, sizeof(cmd), "PREAUTH %s", argv[0]);
476	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
477		printf("Too long PREAUTH command.\n");
478		return -1;
479	}
480	return wpa_ctrl_command(ctrl, cmd);
481}
482
483
484static int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
485{
486	char cmd[256];
487	int res;
488
489	if (argc != 1) {
490		printf("Invalid AP_SCAN command: needs one argument (ap_scan "
491		       "value)\n");
492		return -1;
493	}
494	res = os_snprintf(cmd, sizeof(cmd), "AP_SCAN %s", argv[0]);
495	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
496		printf("Too long AP_SCAN command.\n");
497		return -1;
498	}
499	return wpa_ctrl_command(ctrl, cmd);
500}
501
502
503static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc,
504				char *argv[])
505{
506	char cmd[256];
507	int res;
508
509	if (argc != 1) {
510		printf("Invalid STKSTART command: needs one argument "
511		       "(Peer STA MAC address)\n");
512		return -1;
513	}
514
515	res = os_snprintf(cmd, sizeof(cmd), "STKSTART %s", argv[0]);
516	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
517		printf("Too long STKSTART command.\n");
518		return -1;
519	}
520	return wpa_ctrl_command(ctrl, cmd);
521}
522
523
524static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[])
525{
526	char cmd[256];
527	int res;
528
529	if (argc != 1) {
530		printf("Invalid FT_DS command: needs one argument "
531		       "(Target AP MAC address)\n");
532		return -1;
533	}
534
535	res = os_snprintf(cmd, sizeof(cmd), "FT_DS %s", argv[0]);
536	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
537		printf("Too long FT_DS command.\n");
538		return -1;
539	}
540	return wpa_ctrl_command(ctrl, cmd);
541}
542
543
544static int wpa_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[])
545{
546	char cmd[256];
547	int res;
548
549	if (argc == 0) {
550		/* Any BSSID */
551		return wpa_ctrl_command(ctrl, "WPS_PBC");
552	}
553
554	/* Specific BSSID */
555	res = os_snprintf(cmd, sizeof(cmd), "WPS_PBC %s", argv[0]);
556	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
557		printf("Too long WPS_PBC command.\n");
558		return -1;
559	}
560	return wpa_ctrl_command(ctrl, cmd);
561}
562
563
564static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
565{
566	char cmd[256];
567	int res;
568
569	if (argc == 0) {
570		printf("Invalid WPS_PIN command: need one or two arguments:\n"
571		       "- BSSID: use 'any' to select any\n"
572		       "- PIN: optional, used only with devices that have no "
573		       "display\n");
574		return -1;
575	}
576
577	if (argc == 1) {
578		/* Use dynamically generated PIN (returned as reply) */
579		res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s", argv[0]);
580		if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
581			printf("Too long WPS_PIN command.\n");
582			return -1;
583		}
584		return wpa_ctrl_command(ctrl, cmd);
585	}
586
587	/* Use hardcoded PIN from a label */
588	res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s", argv[0], argv[1]);
589	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
590		printf("Too long WPS_PIN command.\n");
591		return -1;
592	}
593	return wpa_ctrl_command(ctrl, cmd);
594}
595
596
597#ifdef CONFIG_WPS_OOB
598static int wpa_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, char *argv[])
599{
600	char cmd[256];
601	int res;
602
603	if (argc != 3 && argc != 4) {
604		printf("Invalid WPS_OOB command: need three or four "
605		       "arguments:\n"
606		       "- DEV_TYPE: use 'ufd' or 'nfc'\n"
607		       "- PATH: path of OOB device like '/mnt'\n"
608		       "- METHOD: OOB method 'pin-e' or 'pin-r', "
609		       "'cred'\n"
610		       "- DEV_NAME: (only for NFC) device name like "
611		       "'pn531'\n");
612		return -1;
613	}
614
615	if (argc == 3)
616		res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
617				  argv[0], argv[1], argv[2]);
618	else
619		res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
620				  argv[0], argv[1], argv[2], argv[3]);
621	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
622		printf("Too long WPS_OOB command.\n");
623		return -1;
624	}
625	return wpa_ctrl_command(ctrl, cmd);
626}
627#endif /* CONFIG_WPS_OOB */
628
629
630static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
631{
632	char cmd[256];
633	int res;
634
635	if (argc == 2)
636		res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s",
637				  argv[0], argv[1]);
638	else if (argc == 6) {
639		char ssid_hex[2 * 32 + 1];
640		char key_hex[2 * 64 + 1];
641		int i;
642
643		ssid_hex[0] = '\0';
644		for (i = 0; i < 32; i++) {
645			if (argv[2][i] == '\0')
646				break;
647			os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]);
648		}
649
650		key_hex[0] = '\0';
651		for (i = 0; i < 64; i++) {
652			if (argv[5][i] == '\0')
653				break;
654			os_snprintf(&key_hex[i * 2], 3, "%02x", argv[5][i]);
655		}
656
657		res = os_snprintf(cmd, sizeof(cmd),
658				  "WPS_REG %s %s %s %s %s %s",
659				  argv[0], argv[1], ssid_hex, argv[3], argv[4],
660				  key_hex);
661	} else {
662		printf("Invalid WPS_REG command: need two arguments:\n"
663		       "- BSSID: use 'any' to select any\n"
664		       "- AP PIN\n");
665		printf("Alternatively, six arguments can be used to "
666		       "reconfigure the AP:\n"
667		       "- BSSID: use 'any' to select any\n"
668		       "- AP PIN\n"
669		       "- new SSID\n"
670		       "- new auth (OPEN, WPAPSK, WPA2PSK)\n"
671		       "- new encr (NONE, WEP, TKIP, CCMP)\n"
672		       "- new key\n");
673		return -1;
674	}
675
676	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
677		printf("Too long WPS_REG command.\n");
678		return -1;
679	}
680	return wpa_ctrl_command(ctrl, cmd);
681}
682
683
684static int wpa_cli_cmd_wps_er_start(struct wpa_ctrl *ctrl, int argc,
685				    char *argv[])
686{
687	return wpa_ctrl_command(ctrl, "WPS_ER_START");
688
689}
690
691
692static int wpa_cli_cmd_wps_er_stop(struct wpa_ctrl *ctrl, int argc,
693				   char *argv[])
694{
695	return wpa_ctrl_command(ctrl, "WPS_ER_STOP");
696
697}
698
699
700static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc,
701				  char *argv[])
702{
703	char cmd[256];
704	int res;
705
706	if (argc != 2) {
707		printf("Invalid WPS_ER_PIN command: need two arguments:\n"
708		       "- UUID: use 'any' to select any\n"
709		       "- PIN: Enrollee PIN\n");
710		return -1;
711	}
712
713	res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s",
714			  argv[0], argv[1]);
715	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
716		printf("Too long WPS_ER_PIN command.\n");
717		return -1;
718	}
719	return wpa_ctrl_command(ctrl, cmd);
720}
721
722
723static int wpa_cli_cmd_wps_er_pbc(struct wpa_ctrl *ctrl, int argc,
724				  char *argv[])
725{
726	char cmd[256];
727	int res;
728
729	if (argc != 1) {
730		printf("Invalid WPS_ER_PBC command: need one argument:\n"
731		       "- UUID: Specify the Enrollee\n");
732		return -1;
733	}
734
735	res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PBC %s",
736			  argv[0]);
737	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
738		printf("Too long WPS_ER_PBC command.\n");
739		return -1;
740	}
741	return wpa_ctrl_command(ctrl, cmd);
742}
743
744
745static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc,
746				    char *argv[])
747{
748	char cmd[256];
749	int res;
750
751	if (argc != 2) {
752		printf("Invalid WPS_ER_LEARN command: need two arguments:\n"
753		       "- UUID: specify which AP to use\n"
754		       "- PIN: AP PIN\n");
755		return -1;
756	}
757
758	res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_LEARN %s %s",
759			  argv[0], argv[1]);
760	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
761		printf("Too long WPS_ER_LEARN command.\n");
762		return -1;
763	}
764	return wpa_ctrl_command(ctrl, cmd);
765}
766
767
768static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[])
769{
770	char cmd[256];
771	int res;
772
773	if (argc != 1) {
774		printf("Invalid IBSS_RSN command: needs one argument "
775		       "(Peer STA MAC address)\n");
776		return -1;
777	}
778
779	res = os_snprintf(cmd, sizeof(cmd), "IBSS_RSN %s", argv[0]);
780	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
781		printf("Too long IBSS_RSN command.\n");
782		return -1;
783	}
784	return wpa_ctrl_command(ctrl, cmd);
785}
786
787
788static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
789{
790	char cmd[256];
791	int res;
792
793	if (argc != 1) {
794		printf("Invalid LEVEL command: needs one argument (debug "
795		       "level)\n");
796		return -1;
797	}
798	res = os_snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
799	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
800		printf("Too long LEVEL command.\n");
801		return -1;
802	}
803	return wpa_ctrl_command(ctrl, cmd);
804}
805
806
807static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[])
808{
809	char cmd[256], *pos, *end;
810	int i, ret;
811
812	if (argc < 2) {
813		printf("Invalid IDENTITY command: needs two arguments "
814		       "(network id and identity)\n");
815		return -1;
816	}
817
818	end = cmd + sizeof(cmd);
819	pos = cmd;
820	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s",
821			  argv[0], argv[1]);
822	if (ret < 0 || ret >= end - pos) {
823		printf("Too long IDENTITY command.\n");
824		return -1;
825	}
826	pos += ret;
827	for (i = 2; i < argc; i++) {
828		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
829		if (ret < 0 || ret >= end - pos) {
830			printf("Too long IDENTITY command.\n");
831			return -1;
832		}
833		pos += ret;
834	}
835
836	return wpa_ctrl_command(ctrl, cmd);
837}
838
839
840static int wpa_cli_cmd_password(struct wpa_ctrl *ctrl, int argc, char *argv[])
841{
842	char cmd[256], *pos, *end;
843	int i, ret;
844
845	if (argc < 2) {
846		printf("Invalid PASSWORD command: needs two arguments "
847		       "(network id and password)\n");
848		return -1;
849	}
850
851	end = cmd + sizeof(cmd);
852	pos = cmd;
853	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s",
854			  argv[0], argv[1]);
855	if (ret < 0 || ret >= end - pos) {
856		printf("Too long PASSWORD command.\n");
857		return -1;
858	}
859	pos += ret;
860	for (i = 2; i < argc; i++) {
861		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
862		if (ret < 0 || ret >= end - pos) {
863			printf("Too long PASSWORD command.\n");
864			return -1;
865		}
866		pos += ret;
867	}
868
869	return wpa_ctrl_command(ctrl, cmd);
870}
871
872
873static int wpa_cli_cmd_new_password(struct wpa_ctrl *ctrl, int argc,
874				    char *argv[])
875{
876	char cmd[256], *pos, *end;
877	int i, ret;
878
879	if (argc < 2) {
880		printf("Invalid NEW_PASSWORD command: needs two arguments "
881		       "(network id and password)\n");
882		return -1;
883	}
884
885	end = cmd + sizeof(cmd);
886	pos = cmd;
887	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s",
888			  argv[0], argv[1]);
889	if (ret < 0 || ret >= end - pos) {
890		printf("Too long NEW_PASSWORD command.\n");
891		return -1;
892	}
893	pos += ret;
894	for (i = 2; i < argc; i++) {
895		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
896		if (ret < 0 || ret >= end - pos) {
897			printf("Too long NEW_PASSWORD command.\n");
898			return -1;
899		}
900		pos += ret;
901	}
902
903	return wpa_ctrl_command(ctrl, cmd);
904}
905
906
907static int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
908{
909	char cmd[256], *pos, *end;
910	int i, ret;
911
912	if (argc < 2) {
913		printf("Invalid PIN command: needs two arguments "
914		       "(network id and pin)\n");
915		return -1;
916	}
917
918	end = cmd + sizeof(cmd);
919	pos = cmd;
920	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s",
921			  argv[0], argv[1]);
922	if (ret < 0 || ret >= end - pos) {
923		printf("Too long PIN command.\n");
924		return -1;
925	}
926	pos += ret;
927	for (i = 2; i < argc; i++) {
928		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
929		if (ret < 0 || ret >= end - pos) {
930			printf("Too long PIN command.\n");
931			return -1;
932		}
933		pos += ret;
934	}
935	return wpa_ctrl_command(ctrl, cmd);
936}
937
938
939static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[])
940{
941	char cmd[256], *pos, *end;
942	int i, ret;
943
944	if (argc < 2) {
945		printf("Invalid OTP command: needs two arguments (network "
946		       "id and password)\n");
947		return -1;
948	}
949
950	end = cmd + sizeof(cmd);
951	pos = cmd;
952	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s",
953			  argv[0], argv[1]);
954	if (ret < 0 || ret >= end - pos) {
955		printf("Too long OTP command.\n");
956		return -1;
957	}
958	pos += ret;
959	for (i = 2; i < argc; i++) {
960		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
961		if (ret < 0 || ret >= end - pos) {
962			printf("Too long OTP command.\n");
963			return -1;
964		}
965		pos += ret;
966	}
967
968	return wpa_ctrl_command(ctrl, cmd);
969}
970
971
972static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
973				  char *argv[])
974{
975	char cmd[256], *pos, *end;
976	int i, ret;
977
978	if (argc < 2) {
979		printf("Invalid PASSPHRASE command: needs two arguments "
980		       "(network id and passphrase)\n");
981		return -1;
982	}
983
984	end = cmd + sizeof(cmd);
985	pos = cmd;
986	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s",
987			  argv[0], argv[1]);
988	if (ret < 0 || ret >= end - pos) {
989		printf("Too long PASSPHRASE command.\n");
990		return -1;
991	}
992	pos += ret;
993	for (i = 2; i < argc; i++) {
994		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
995		if (ret < 0 || ret >= end - pos) {
996			printf("Too long PASSPHRASE command.\n");
997			return -1;
998		}
999		pos += ret;
1000	}
1001
1002	return wpa_ctrl_command(ctrl, cmd);
1003}
1004
1005
1006static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[])
1007{
1008	char cmd[256], *pos, *end;
1009	int i, ret;
1010
1011	if (argc < 2) {
1012		printf("Invalid BSSID command: needs two arguments (network "
1013		       "id and BSSID)\n");
1014		return -1;
1015	}
1016
1017	end = cmd + sizeof(cmd);
1018	pos = cmd;
1019	ret = os_snprintf(pos, end - pos, "BSSID");
1020	if (ret < 0 || ret >= end - pos) {
1021		printf("Too long BSSID command.\n");
1022		return -1;
1023	}
1024	pos += ret;
1025	for (i = 0; i < argc; i++) {
1026		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
1027		if (ret < 0 || ret >= end - pos) {
1028			printf("Too long BSSID command.\n");
1029			return -1;
1030		}
1031		pos += ret;
1032	}
1033
1034	return wpa_ctrl_command(ctrl, cmd);
1035}
1036
1037
1038static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc,
1039				     char *argv[])
1040{
1041	return wpa_ctrl_command(ctrl, "LIST_NETWORKS");
1042}
1043
1044
1045static int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc,
1046				      char *argv[])
1047{
1048	char cmd[32];
1049	int res;
1050
1051	if (argc < 1) {
1052		printf("Invalid SELECT_NETWORK command: needs one argument "
1053		       "(network id)\n");
1054		return -1;
1055	}
1056
1057	res = os_snprintf(cmd, sizeof(cmd), "SELECT_NETWORK %s", argv[0]);
1058	if (res < 0 || (size_t) res >= sizeof(cmd))
1059		return -1;
1060	cmd[sizeof(cmd) - 1] = '\0';
1061
1062	return wpa_ctrl_command(ctrl, cmd);
1063}
1064
1065
1066static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc,
1067				      char *argv[])
1068{
1069	char cmd[32];
1070	int res;
1071
1072	if (argc < 1) {
1073		printf("Invalid ENABLE_NETWORK command: needs one argument "
1074		       "(network id)\n");
1075		return -1;
1076	}
1077
1078	res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s", argv[0]);
1079	if (res < 0 || (size_t) res >= sizeof(cmd))
1080		return -1;
1081	cmd[sizeof(cmd) - 1] = '\0';
1082
1083	return wpa_ctrl_command(ctrl, cmd);
1084}
1085
1086
1087static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc,
1088				       char *argv[])
1089{
1090	char cmd[32];
1091	int res;
1092
1093	if (argc < 1) {
1094		printf("Invalid DISABLE_NETWORK command: needs one argument "
1095		       "(network id)\n");
1096		return -1;
1097	}
1098
1099	res = os_snprintf(cmd, sizeof(cmd), "DISABLE_NETWORK %s", argv[0]);
1100	if (res < 0 || (size_t) res >= sizeof(cmd))
1101		return -1;
1102	cmd[sizeof(cmd) - 1] = '\0';
1103
1104	return wpa_ctrl_command(ctrl, cmd);
1105}
1106
1107
1108static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc,
1109				   char *argv[])
1110{
1111	return wpa_ctrl_command(ctrl, "ADD_NETWORK");
1112}
1113
1114
1115static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc,
1116				      char *argv[])
1117{
1118	char cmd[32];
1119	int res;
1120
1121	if (argc < 1) {
1122		printf("Invalid REMOVE_NETWORK command: needs one argument "
1123		       "(network id)\n");
1124		return -1;
1125	}
1126
1127	res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %s", argv[0]);
1128	if (res < 0 || (size_t) res >= sizeof(cmd))
1129		return -1;
1130	cmd[sizeof(cmd) - 1] = '\0';
1131
1132	return wpa_ctrl_command(ctrl, cmd);
1133}
1134
1135
1136static void wpa_cli_show_network_variables(void)
1137{
1138	printf("set_network variables:\n"
1139	       "  ssid (network name, SSID)\n"
1140	       "  psk (WPA passphrase or pre-shared key)\n"
1141	       "  key_mgmt (key management protocol)\n"
1142	       "  identity (EAP identity)\n"
1143	       "  password (EAP password)\n"
1144	       "  ...\n"
1145	       "\n"
1146	       "Note: Values are entered in the same format as the "
1147	       "configuration file is using,\n"
1148	       "i.e., strings values need to be inside double quotation "
1149	       "marks.\n"
1150	       "For example: set_network 1 ssid \"network name\"\n"
1151	       "\n"
1152	       "Please see wpa_supplicant.conf documentation for full list "
1153	       "of\navailable variables.\n");
1154}
1155
1156
1157static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc,
1158				   char *argv[])
1159{
1160	char cmd[256];
1161	int res;
1162
1163	if (argc == 0) {
1164		wpa_cli_show_network_variables();
1165		return 0;
1166	}
1167
1168	if (argc != 3) {
1169		printf("Invalid SET_NETWORK command: needs three arguments\n"
1170		       "(network id, variable name, and value)\n");
1171		return -1;
1172	}
1173
1174	res = os_snprintf(cmd, sizeof(cmd), "SET_NETWORK %s %s %s",
1175			  argv[0], argv[1], argv[2]);
1176	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
1177		printf("Too long SET_NETWORK command.\n");
1178		return -1;
1179	}
1180	return wpa_ctrl_command(ctrl, cmd);
1181}
1182
1183
1184static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
1185				   char *argv[])
1186{
1187	char cmd[256];
1188	int res;
1189
1190	if (argc == 0) {
1191		wpa_cli_show_network_variables();
1192		return 0;
1193	}
1194
1195	if (argc != 2) {
1196		printf("Invalid GET_NETWORK command: needs two arguments\n"
1197		       "(network id and variable name)\n");
1198		return -1;
1199	}
1200
1201	res = os_snprintf(cmd, sizeof(cmd), "GET_NETWORK %s %s",
1202			  argv[0], argv[1]);
1203	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
1204		printf("Too long GET_NETWORK command.\n");
1205		return -1;
1206	}
1207	return wpa_ctrl_command(ctrl, cmd);
1208}
1209
1210
1211static int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc,
1212				  char *argv[])
1213{
1214	return wpa_ctrl_command(ctrl, "DISCONNECT");
1215}
1216
1217
1218static int wpa_cli_cmd_reconnect(struct wpa_ctrl *ctrl, int argc,
1219				  char *argv[])
1220{
1221	return wpa_ctrl_command(ctrl, "RECONNECT");
1222}
1223
1224
1225static int wpa_cli_cmd_save_config(struct wpa_ctrl *ctrl, int argc,
1226				   char *argv[])
1227{
1228	return wpa_ctrl_command(ctrl, "SAVE_CONFIG");
1229}
1230
1231
1232static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
1233{
1234	return wpa_ctrl_command(ctrl, "SCAN");
1235}
1236
1237
1238static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc,
1239				    char *argv[])
1240{
1241	return wpa_ctrl_command(ctrl, "SCAN_RESULTS");
1242}
1243
1244
1245static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
1246{
1247	char cmd[64];
1248	int res;
1249
1250	if (argc != 1) {
1251		printf("Invalid BSS command: need one argument (index or "
1252		       "BSSID)\n");
1253		return -1;
1254	}
1255
1256	res = os_snprintf(cmd, sizeof(cmd), "BSS %s", argv[0]);
1257	if (res < 0 || (size_t) res >= sizeof(cmd))
1258		return -1;
1259	cmd[sizeof(cmd) - 1] = '\0';
1260
1261	return wpa_ctrl_command(ctrl, cmd);
1262}
1263
1264
1265static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
1266				      char *argv[])
1267{
1268	char cmd[64];
1269	int res;
1270
1271	if (argc < 1 || argc > 2) {
1272		printf("Invalid GET_CAPABILITY command: need either one or "
1273		       "two arguments\n");
1274		return -1;
1275	}
1276
1277	if ((argc == 2) && os_strcmp(argv[1], "strict") != 0) {
1278		printf("Invalid GET_CAPABILITY command: second argument, "
1279		       "if any, must be 'strict'\n");
1280		return -1;
1281	}
1282
1283	res = os_snprintf(cmd, sizeof(cmd), "GET_CAPABILITY %s%s", argv[0],
1284			  (argc == 2) ? " strict" : "");
1285	if (res < 0 || (size_t) res >= sizeof(cmd))
1286		return -1;
1287	cmd[sizeof(cmd) - 1] = '\0';
1288
1289	return wpa_ctrl_command(ctrl, cmd);
1290}
1291
1292
1293static int wpa_cli_list_interfaces(struct wpa_ctrl *ctrl)
1294{
1295	printf("Available interfaces:\n");
1296	return wpa_ctrl_command(ctrl, "INTERFACES");
1297}
1298
1299
1300static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[])
1301{
1302	if (argc < 1) {
1303		wpa_cli_list_interfaces(ctrl);
1304		return 0;
1305	}
1306
1307	wpa_cli_close_connection();
1308	os_free(ctrl_ifname);
1309	ctrl_ifname = os_strdup(argv[0]);
1310
1311	if (wpa_cli_open_connection(ctrl_ifname, 1)) {
1312		printf("Connected to interface '%s.\n", ctrl_ifname);
1313	} else {
1314		printf("Could not connect to interface '%s' - re-trying\n",
1315		       ctrl_ifname);
1316	}
1317	return 0;
1318}
1319
1320
1321static int wpa_cli_cmd_reconfigure(struct wpa_ctrl *ctrl, int argc,
1322				   char *argv[])
1323{
1324	return wpa_ctrl_command(ctrl, "RECONFIGURE");
1325}
1326
1327
1328static int wpa_cli_cmd_terminate(struct wpa_ctrl *ctrl, int argc,
1329				 char *argv[])
1330{
1331	return wpa_ctrl_command(ctrl, "TERMINATE");
1332}
1333
1334
1335static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc,
1336				     char *argv[])
1337{
1338	char cmd[256];
1339	int res;
1340
1341	if (argc < 1) {
1342		printf("Invalid INTERFACE_ADD command: needs at least one "
1343		       "argument (interface name)\n"
1344		       "All arguments: ifname confname driver ctrl_interface "
1345		       "driver_param bridge_name\n");
1346		return -1;
1347	}
1348
1349	/*
1350	 * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
1351	 * <driver_param>TAB<bridge_name>
1352	 */
1353	res = os_snprintf(cmd, sizeof(cmd),
1354			  "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s",
1355			  argv[0],
1356			  argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "",
1357			  argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "",
1358			  argc > 5 ? argv[5] : "");
1359	if (res < 0 || (size_t) res >= sizeof(cmd))
1360		return -1;
1361	cmd[sizeof(cmd) - 1] = '\0';
1362	return wpa_ctrl_command(ctrl, cmd);
1363}
1364
1365
1366static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc,
1367					char *argv[])
1368{
1369	char cmd[128];
1370	int res;
1371
1372	if (argc != 1) {
1373		printf("Invalid INTERFACE_REMOVE command: needs one argument "
1374		       "(interface name)\n");
1375		return -1;
1376	}
1377
1378	res = os_snprintf(cmd, sizeof(cmd), "INTERFACE_REMOVE %s", argv[0]);
1379	if (res < 0 || (size_t) res >= sizeof(cmd))
1380		return -1;
1381	cmd[sizeof(cmd) - 1] = '\0';
1382	return wpa_ctrl_command(ctrl, cmd);
1383}
1384
1385
1386static int wpa_cli_cmd_interface_list(struct wpa_ctrl *ctrl, int argc,
1387				      char *argv[])
1388{
1389	return wpa_ctrl_command(ctrl, "INTERFACE_LIST");
1390}
1391
1392
1393#ifdef CONFIG_AP
1394static int wpa_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
1395{
1396	char buf[64];
1397	if (argc != 1) {
1398		printf("Invalid 'sta' command - exactly one argument, STA "
1399		       "address, is required.\n");
1400		return -1;
1401	}
1402	os_snprintf(buf, sizeof(buf), "STA %s", argv[0]);
1403	return wpa_ctrl_command(ctrl, buf);
1404}
1405
1406
1407static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
1408				char *addr, size_t addr_len)
1409{
1410	char buf[4096], *pos;
1411	size_t len;
1412	int ret;
1413
1414	if (ctrl_conn == NULL) {
1415		printf("Not connected to hostapd - command dropped.\n");
1416		return -1;
1417	}
1418	len = sizeof(buf) - 1;
1419	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
1420			       wpa_cli_msg_cb);
1421	if (ret == -2) {
1422		printf("'%s' command timed out.\n", cmd);
1423		return -2;
1424	} else if (ret < 0) {
1425		printf("'%s' command failed.\n", cmd);
1426		return -1;
1427	}
1428
1429	buf[len] = '\0';
1430	if (memcmp(buf, "FAIL", 4) == 0)
1431		return -1;
1432	printf("%s", buf);
1433
1434	pos = buf;
1435	while (*pos != '\0' && *pos != '\n')
1436		pos++;
1437	*pos = '\0';
1438	os_strlcpy(addr, buf, addr_len);
1439	return 0;
1440}
1441
1442
1443static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
1444{
1445	char addr[32], cmd[64];
1446
1447	if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
1448		return 0;
1449	do {
1450		os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
1451	} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
1452
1453	return -1;
1454}
1455#endif /* CONFIG_AP */
1456
1457
1458static int wpa_cli_cmd_suspend(struct wpa_ctrl *ctrl, int argc, char *argv[])
1459{
1460	return wpa_ctrl_command(ctrl, "SUSPEND");
1461}
1462
1463
1464static int wpa_cli_cmd_resume(struct wpa_ctrl *ctrl, int argc, char *argv[])
1465{
1466	return wpa_ctrl_command(ctrl, "RESUME");
1467}
1468
1469
1470static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[])
1471{
1472	return wpa_ctrl_command(ctrl, "DROP_SA");
1473}
1474
1475
1476static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
1477{
1478	char cmd[128];
1479	int res;
1480
1481	if (argc != 1) {
1482		printf("Invalid ROAM command: needs one argument "
1483		       "(target AP's BSSID)\n");
1484		return -1;
1485	}
1486
1487	res = os_snprintf(cmd, sizeof(cmd), "ROAM %s", argv[0]);
1488	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
1489		printf("Too long ROAM command.\n");
1490		return -1;
1491	}
1492	return wpa_ctrl_command(ctrl, cmd);
1493}
1494
1495
1496enum wpa_cli_cmd_flags {
1497	cli_cmd_flag_none		= 0x00,
1498	cli_cmd_flag_sensitive		= 0x01
1499};
1500
1501struct wpa_cli_cmd {
1502	const char *cmd;
1503	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
1504	enum wpa_cli_cmd_flags flags;
1505	const char *usage;
1506};
1507
1508static struct wpa_cli_cmd wpa_cli_commands[] = {
1509	{ "status", wpa_cli_cmd_status,
1510	  cli_cmd_flag_none,
1511	  "[verbose] = get current WPA/EAPOL/EAP status" },
1512	{ "ping", wpa_cli_cmd_ping,
1513	  cli_cmd_flag_none,
1514	  "= pings wpa_supplicant" },
1515	{ "mib", wpa_cli_cmd_mib,
1516	  cli_cmd_flag_none,
1517	  "= get MIB variables (dot1x, dot11)" },
1518	{ "help", wpa_cli_cmd_help,
1519	  cli_cmd_flag_none,
1520	  "= show this usage help" },
1521	{ "interface", wpa_cli_cmd_interface,
1522	  cli_cmd_flag_none,
1523	  "[ifname] = show interfaces/select interface" },
1524	{ "level", wpa_cli_cmd_level,
1525	  cli_cmd_flag_none,
1526	  "<debug level> = change debug level" },
1527	{ "license", wpa_cli_cmd_license,
1528	  cli_cmd_flag_none,
1529	  "= show full wpa_cli license" },
1530	{ "quit", wpa_cli_cmd_quit,
1531	  cli_cmd_flag_none,
1532	  "= exit wpa_cli" },
1533	{ "set", wpa_cli_cmd_set,
1534	  cli_cmd_flag_none,
1535	  "= set variables (shows list of variables when run without "
1536	  "arguments)" },
1537	{ "logon", wpa_cli_cmd_logon,
1538	  cli_cmd_flag_none,
1539	  "= IEEE 802.1X EAPOL state machine logon" },
1540	{ "logoff", wpa_cli_cmd_logoff,
1541	  cli_cmd_flag_none,
1542	  "= IEEE 802.1X EAPOL state machine logoff" },
1543	{ "pmksa", wpa_cli_cmd_pmksa,
1544	  cli_cmd_flag_none,
1545	  "= show PMKSA cache" },
1546	{ "reassociate", wpa_cli_cmd_reassociate,
1547	  cli_cmd_flag_none,
1548	  "= force reassociation" },
1549	{ "preauthenticate", wpa_cli_cmd_preauthenticate,
1550	  cli_cmd_flag_none,
1551	  "<BSSID> = force preauthentication" },
1552	{ "identity", wpa_cli_cmd_identity,
1553	  cli_cmd_flag_none,
1554	  "<network id> <identity> = configure identity for an SSID" },
1555	{ "password", wpa_cli_cmd_password,
1556	  cli_cmd_flag_sensitive,
1557	  "<network id> <password> = configure password for an SSID" },
1558	{ "new_password", wpa_cli_cmd_new_password,
1559	  cli_cmd_flag_sensitive,
1560	  "<network id> <password> = change password for an SSID" },
1561	{ "pin", wpa_cli_cmd_pin,
1562	  cli_cmd_flag_sensitive,
1563	  "<network id> <pin> = configure pin for an SSID" },
1564	{ "otp", wpa_cli_cmd_otp,
1565	  cli_cmd_flag_sensitive,
1566	  "<network id> <password> = configure one-time-password for an SSID"
1567	},
1568	{ "passphrase", wpa_cli_cmd_passphrase,
1569	  cli_cmd_flag_sensitive,
1570	  "<network id> <passphrase> = configure private key passphrase\n"
1571	  "  for an SSID" },
1572	{ "bssid", wpa_cli_cmd_bssid,
1573	  cli_cmd_flag_none,
1574	  "<network id> <BSSID> = set preferred BSSID for an SSID" },
1575	{ "list_networks", wpa_cli_cmd_list_networks,
1576	  cli_cmd_flag_none,
1577	  "= list configured networks" },
1578	{ "select_network", wpa_cli_cmd_select_network,
1579	  cli_cmd_flag_none,
1580	  "<network id> = select a network (disable others)" },
1581	{ "enable_network", wpa_cli_cmd_enable_network,
1582	  cli_cmd_flag_none,
1583	  "<network id> = enable a network" },
1584	{ "disable_network", wpa_cli_cmd_disable_network,
1585	  cli_cmd_flag_none,
1586	  "<network id> = disable a network" },
1587	{ "add_network", wpa_cli_cmd_add_network,
1588	  cli_cmd_flag_none,
1589	  "= add a network" },
1590	{ "remove_network", wpa_cli_cmd_remove_network,
1591	  cli_cmd_flag_none,
1592	  "<network id> = remove a network" },
1593	{ "set_network", wpa_cli_cmd_set_network,
1594	  cli_cmd_flag_sensitive,
1595	  "<network id> <variable> <value> = set network variables (shows\n"
1596	  "  list of variables when run without arguments)" },
1597	{ "get_network", wpa_cli_cmd_get_network,
1598	  cli_cmd_flag_none,
1599	  "<network id> <variable> = get network variables" },
1600	{ "save_config", wpa_cli_cmd_save_config,
1601	  cli_cmd_flag_none,
1602	  "= save the current configuration" },
1603	{ "disconnect", wpa_cli_cmd_disconnect,
1604	  cli_cmd_flag_none,
1605	  "= disconnect and wait for reassociate/reconnect command before\n"
1606	  "  connecting" },
1607	{ "reconnect", wpa_cli_cmd_reconnect,
1608	  cli_cmd_flag_none,
1609	  "= like reassociate, but only takes effect if already disconnected"
1610	},
1611	{ "scan", wpa_cli_cmd_scan,
1612	  cli_cmd_flag_none,
1613	  "= request new BSS scan" },
1614	{ "scan_results", wpa_cli_cmd_scan_results,
1615	  cli_cmd_flag_none,
1616	  "= get latest scan results" },
1617	{ "bss", wpa_cli_cmd_bss,
1618	  cli_cmd_flag_none,
1619	  "<<idx> | <bssid>> = get detailed scan result info" },
1620	{ "get_capability", wpa_cli_cmd_get_capability,
1621	  cli_cmd_flag_none,
1622	  "<eap/pairwise/group/key_mgmt/proto/auth_alg> = get capabilies" },
1623	{ "reconfigure", wpa_cli_cmd_reconfigure,
1624	  cli_cmd_flag_none,
1625	  "= force wpa_supplicant to re-read its configuration file" },
1626	{ "terminate", wpa_cli_cmd_terminate,
1627	  cli_cmd_flag_none,
1628	  "= terminate wpa_supplicant" },
1629	{ "interface_add", wpa_cli_cmd_interface_add,
1630	  cli_cmd_flag_none,
1631	  "<ifname> <confname> <driver> <ctrl_interface> <driver_param>\n"
1632	  "  <bridge_name> = adds new interface, all parameters but <ifname>\n"
1633	  "  are optional" },
1634	{ "interface_remove", wpa_cli_cmd_interface_remove,
1635	  cli_cmd_flag_none,
1636	  "<ifname> = removes the interface" },
1637	{ "interface_list", wpa_cli_cmd_interface_list,
1638	  cli_cmd_flag_none,
1639	  "= list available interfaces" },
1640	{ "ap_scan", wpa_cli_cmd_ap_scan,
1641	  cli_cmd_flag_none,
1642	  "<value> = set ap_scan parameter" },
1643	{ "stkstart", wpa_cli_cmd_stkstart,
1644	  cli_cmd_flag_none,
1645	  "<addr> = request STK negotiation with <addr>" },
1646	{ "ft_ds", wpa_cli_cmd_ft_ds,
1647	  cli_cmd_flag_none,
1648	  "<addr> = request over-the-DS FT with <addr>" },
1649	{ "wps_pbc", wpa_cli_cmd_wps_pbc,
1650	  cli_cmd_flag_none,
1651	  "[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" },
1652	{ "wps_pin", wpa_cli_cmd_wps_pin,
1653	  cli_cmd_flag_sensitive,
1654	  "<BSSID> [PIN] = start WPS PIN method (returns PIN, if not "
1655	  "hardcoded)" },
1656#ifdef CONFIG_WPS_OOB
1657	{ "wps_oob", wpa_cli_cmd_wps_oob,
1658	  cli_cmd_flag_sensitive,
1659	  "<DEV_TYPE> <PATH> <METHOD> [DEV_NAME] = start WPS OOB" },
1660#endif /* CONFIG_WPS_OOB */
1661	{ "wps_reg", wpa_cli_cmd_wps_reg,
1662	  cli_cmd_flag_sensitive,
1663	  "<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
1664	{ "wps_er_start", wpa_cli_cmd_wps_er_start,
1665	  cli_cmd_flag_none,
1666	  "= start Wi-Fi Protected Setup External Registrar" },
1667	{ "wps_er_stop", wpa_cli_cmd_wps_er_stop,
1668	  cli_cmd_flag_none,
1669	  "= stop Wi-Fi Protected Setup External Registrar" },
1670	{ "wps_er_pin", wpa_cli_cmd_wps_er_pin,
1671	  cli_cmd_flag_sensitive,
1672	  "<UUID> <PIN> = add an Enrollee PIN to External Registrar" },
1673	{ "wps_er_pbc", wpa_cli_cmd_wps_er_pbc,
1674	  cli_cmd_flag_none,
1675	  "<UUID> = accept an Enrollee PBC using External Registrar" },
1676	{ "wps_er_learn", wpa_cli_cmd_wps_er_learn,
1677	  cli_cmd_flag_sensitive,
1678	  "<UUID> <PIN> = learn AP configuration" },
1679	{ "ibss_rsn", wpa_cli_cmd_ibss_rsn,
1680	  cli_cmd_flag_none,
1681	  "<addr> = request RSN authentication with <addr> in IBSS" },
1682#ifdef CONFIG_AP
1683	{ "sta", wpa_cli_cmd_sta,
1684	  cli_cmd_flag_none,
1685	  "<addr> = get information about an associated station (AP)" },
1686	{ "all_sta", wpa_cli_cmd_all_sta,
1687	  cli_cmd_flag_none,
1688	  "= get information about all associated stations (AP)" },
1689#endif /* CONFIG_AP */
1690	{ "suspend", wpa_cli_cmd_suspend, cli_cmd_flag_none,
1691	  "= notification of suspend/hibernate" },
1692	{ "resume", wpa_cli_cmd_resume, cli_cmd_flag_none,
1693	  "= notification of resume/thaw" },
1694	{ "drop_sa", wpa_cli_cmd_drop_sa, cli_cmd_flag_none,
1695	  "= drop SA without deauth/disassoc (test command)" },
1696	{ "roam", wpa_cli_cmd_roam,
1697	  cli_cmd_flag_none,
1698	  "<addr> = roam to the specified BSS" },
1699	{ NULL, NULL, cli_cmd_flag_none, NULL }
1700};
1701
1702
1703/*
1704 * Prints command usage, lines are padded with the specified string.
1705 */
1706static void print_cmd_help(struct wpa_cli_cmd *cmd, const char *pad)
1707{
1708	char c;
1709	size_t n;
1710
1711	printf("%s%s ", pad, cmd->cmd);
1712	for (n = 0; (c = cmd->usage[n]); n++) {
1713		printf("%c", c);
1714		if (c == '\n')
1715			printf("%s", pad);
1716	}
1717	printf("\n");
1718}
1719
1720
1721static void print_help(void)
1722{
1723	int n;
1724	printf("commands:\n");
1725	for (n = 0; wpa_cli_commands[n].cmd; n++)
1726		print_cmd_help(&wpa_cli_commands[n], "  ");
1727}
1728
1729
1730#ifdef CONFIG_READLINE
1731static int cmd_has_sensitive_data(const char *cmd)
1732{
1733	const char *c, *delim;
1734	int n;
1735	size_t len;
1736
1737	delim = os_strchr(cmd, ' ');
1738	if (delim)
1739		len = delim - cmd;
1740	else
1741		len = os_strlen(cmd);
1742
1743	for (n = 0; (c = wpa_cli_commands[n].cmd); n++) {
1744		if (os_strncasecmp(cmd, c, len) == 0 && len == os_strlen(c))
1745			return (wpa_cli_commands[n].flags &
1746				cli_cmd_flag_sensitive);
1747	}
1748	return 0;
1749}
1750#endif /* CONFIG_READLINE */
1751
1752
1753static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
1754{
1755	struct wpa_cli_cmd *cmd, *match = NULL;
1756	int count;
1757	int ret = 0;
1758
1759	count = 0;
1760	cmd = wpa_cli_commands;
1761	while (cmd->cmd) {
1762		if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0)
1763		{
1764			match = cmd;
1765			if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1766				/* we have an exact match */
1767				count = 1;
1768				break;
1769			}
1770			count++;
1771		}
1772		cmd++;
1773	}
1774
1775	if (count > 1) {
1776		printf("Ambiguous command '%s'; possible commands:", argv[0]);
1777		cmd = wpa_cli_commands;
1778		while (cmd->cmd) {
1779			if (os_strncasecmp(cmd->cmd, argv[0],
1780					   os_strlen(argv[0])) == 0) {
1781				printf(" %s", cmd->cmd);
1782			}
1783			cmd++;
1784		}
1785		printf("\n");
1786		ret = 1;
1787	} else if (count == 0) {
1788		printf("Unknown command '%s'\n", argv[0]);
1789		ret = 1;
1790	} else {
1791		ret = match->handler(ctrl, argc - 1, &argv[1]);
1792	}
1793
1794	return ret;
1795}
1796
1797
1798static int str_match(const char *a, const char *b)
1799{
1800	return os_strncmp(a, b, os_strlen(b)) == 0;
1801}
1802
1803
1804static int wpa_cli_exec(const char *program, const char *arg1,
1805			const char *arg2)
1806{
1807	char *cmd;
1808	size_t len;
1809	int res;
1810	int ret = 0;
1811
1812	len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
1813	cmd = os_malloc(len);
1814	if (cmd == NULL)
1815		return -1;
1816	res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
1817	if (res < 0 || (size_t) res >= len) {
1818		os_free(cmd);
1819		return -1;
1820	}
1821	cmd[len - 1] = '\0';
1822#ifndef _WIN32_WCE
1823	if (system(cmd) < 0)
1824		ret = -1;
1825#endif /* _WIN32_WCE */
1826	os_free(cmd);
1827
1828	return ret;
1829}
1830
1831
1832static void wpa_cli_action_process(const char *msg)
1833{
1834 	const char *pos = skip_priority(msg);
1835
1836	if (str_match(pos, WPA_EVENT_CONNECTED)) {
1837		int new_id = -1;
1838		char *id, *copy;
1839		os_unsetenv("WPA_ID");
1840		os_unsetenv("WPA_ID_STR");
1841		os_unsetenv("WPA_CTRL_DIR");
1842
1843		pos = os_strstr(pos, "[id=");
1844		copy = pos ? os_strdup(pos + 4) : NULL;
1845
1846		if (copy) {
1847			char *pos2 = id = copy;
1848			while (*pos2 && *pos2 != ' ')
1849				pos2++;
1850			*pos2++ = '\0';
1851			new_id = atoi(id);
1852			os_setenv("WPA_ID", id, 1);
1853			while (*pos2 && *pos2 != '=')
1854				pos2++;
1855			if (*pos2 == '=')
1856				pos2++;
1857			id = pos2;
1858			while (*pos2 && *pos2 != ']')
1859				pos2++;
1860			*pos2 = '\0';
1861			os_setenv("WPA_ID_STR", id, 1);
1862			os_free(copy);
1863		}
1864
1865		os_setenv("WPA_CTRL_DIR", ctrl_iface_dir, 1);
1866
1867		if (!wpa_cli_connected || new_id != wpa_cli_last_id) {
1868			wpa_cli_connected = 1;
1869			wpa_cli_last_id = new_id;
1870			wpa_cli_exec(action_file, ctrl_ifname, "CONNECTED");
1871		}
1872	} else if (str_match(pos, WPA_EVENT_DISCONNECTED)) {
1873		if (wpa_cli_connected) {
1874			wpa_cli_connected = 0;
1875			wpa_cli_exec(action_file, ctrl_ifname, "DISCONNECTED");
1876		}
1877	} else if (str_match(pos, WPA_EVENT_TERMINATING)) {
1878		printf("wpa_supplicant is terminating - stop monitoring\n");
1879		wpa_cli_quit = 1;
1880	}
1881}
1882
1883
1884#ifndef CONFIG_ANSI_C_EXTRA
1885static void wpa_cli_action_cb(char *msg, size_t len)
1886{
1887	wpa_cli_action_process(msg);
1888}
1889#endif /* CONFIG_ANSI_C_EXTRA */
1890
1891
1892static void wpa_cli_reconnect(void)
1893{
1894	wpa_cli_close_connection();
1895	wpa_cli_open_connection(ctrl_ifname, 1);
1896}
1897
1898
1899static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
1900				 int action_monitor)
1901{
1902	int first = 1;
1903	if (ctrl_conn == NULL) {
1904		wpa_cli_reconnect();
1905		return;
1906	}
1907	while (wpa_ctrl_pending(ctrl) > 0) {
1908		char buf[256];
1909		size_t len = sizeof(buf) - 1;
1910		if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
1911			buf[len] = '\0';
1912			if (action_monitor)
1913				wpa_cli_action_process(buf);
1914			else {
1915				if (in_read && first)
1916					printf("\r");
1917				first = 0;
1918				wpa_cli_msg_cb(buf, 0);
1919#ifdef CONFIG_READLINE
1920				rl_on_new_line();
1921				rl_redisplay();
1922#endif /* CONFIG_READLINE */
1923			}
1924		} else {
1925			printf("Could not read pending message.\n");
1926			break;
1927		}
1928	}
1929
1930	if (wpa_ctrl_pending(ctrl) < 0) {
1931		printf("Connection to wpa_supplicant lost - trying to "
1932		       "reconnect\n");
1933		wpa_cli_reconnect();
1934	}
1935}
1936
1937
1938#ifdef CONFIG_READLINE
1939static char * wpa_cli_cmd_gen(const char *text, int state)
1940{
1941	static int i, len;
1942	const char *cmd;
1943
1944	if (state == 0) {
1945		i = 0;
1946		len = os_strlen(text);
1947	}
1948
1949	while ((cmd = wpa_cli_commands[i].cmd)) {
1950		i++;
1951		if (os_strncasecmp(cmd, text, len) == 0)
1952			return strdup(cmd);
1953	}
1954
1955	return NULL;
1956}
1957
1958
1959static char * wpa_cli_dummy_gen(const char *text, int state)
1960{
1961	int i;
1962
1963	for (i = 0; wpa_cli_commands[i].cmd; i++) {
1964		const char *cmd = wpa_cli_commands[i].cmd;
1965		size_t len = os_strlen(cmd);
1966		if (os_strncasecmp(rl_line_buffer, cmd, len) == 0 &&
1967		    rl_line_buffer[len] == ' ') {
1968			printf("\n%s\n", wpa_cli_commands[i].usage);
1969			rl_on_new_line();
1970			rl_redisplay();
1971			break;
1972		}
1973	}
1974
1975	rl_attempted_completion_over = 1;
1976	return NULL;
1977}
1978
1979
1980static char * wpa_cli_status_gen(const char *text, int state)
1981{
1982	static int i, len;
1983	char *options[] = {
1984		"verbose", NULL
1985	};
1986	char *t;
1987
1988	if (state == 0) {
1989		i = 0;
1990		len = os_strlen(text);
1991	}
1992
1993	while ((t = options[i])) {
1994		i++;
1995		if (os_strncasecmp(t, text, len) == 0)
1996			return strdup(t);
1997	}
1998
1999	rl_attempted_completion_over = 1;
2000	return NULL;
2001}
2002
2003
2004static char ** wpa_cli_completion(const char *text, int start, int end)
2005{
2006	char * (*func)(const char *text, int state);
2007
2008	if (start == 0)
2009		func = wpa_cli_cmd_gen;
2010	else if (os_strncasecmp(rl_line_buffer, "status ", 7) == 0)
2011		func = wpa_cli_status_gen;
2012	else
2013		func = wpa_cli_dummy_gen;
2014	return rl_completion_matches(text, func);
2015}
2016#endif /* CONFIG_READLINE */
2017
2018
2019static void wpa_cli_interactive(void)
2020{
2021#define max_args 10
2022	char cmdbuf[256], *cmd, *argv[max_args], *pos;
2023	int argc;
2024#ifdef CONFIG_READLINE
2025	char *home, *hfile = NULL;
2026#endif /* CONFIG_READLINE */
2027
2028	printf("\nInteractive mode\n\n");
2029
2030#ifdef CONFIG_READLINE
2031	rl_attempted_completion_function = wpa_cli_completion;
2032	home = getenv("HOME");
2033	if (home) {
2034		const char *fname = ".wpa_cli_history";
2035		int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
2036		hfile = os_malloc(hfile_len);
2037		if (hfile) {
2038			int res;
2039			res = os_snprintf(hfile, hfile_len, "%s/%s", home,
2040					  fname);
2041			if (res >= 0 && res < hfile_len) {
2042				hfile[hfile_len - 1] = '\0';
2043				read_history(hfile);
2044				stifle_history(100);
2045			}
2046		}
2047	}
2048#endif /* CONFIG_READLINE */
2049
2050	do {
2051		wpa_cli_recv_pending(mon_conn, 0, 0);
2052#ifndef CONFIG_NATIVE_WINDOWS
2053		alarm(ping_interval);
2054#endif /* CONFIG_NATIVE_WINDOWS */
2055#ifdef CONFIG_WPA_CLI_FORK
2056		if (mon_pid)
2057			kill(mon_pid, SIGUSR1);
2058#endif /* CONFIG_WPA_CLI_FORK */
2059#ifdef CONFIG_READLINE
2060		cmd = readline("> ");
2061		if (cmd && *cmd) {
2062			HIST_ENTRY *h;
2063			while (next_history())
2064				;
2065			h = previous_history();
2066			if (h == NULL || os_strcmp(cmd, h->line) != 0)
2067				add_history(cmd);
2068			next_history();
2069		}
2070#else /* CONFIG_READLINE */
2071		printf("> ");
2072		cmd = fgets(cmdbuf, sizeof(cmdbuf), stdin);
2073#endif /* CONFIG_READLINE */
2074#ifndef CONFIG_NATIVE_WINDOWS
2075		alarm(0);
2076#endif /* CONFIG_NATIVE_WINDOWS */
2077		if (cmd == NULL)
2078			break;
2079		wpa_cli_recv_pending(mon_conn, 0, 0);
2080		pos = cmd;
2081		while (*pos != '\0') {
2082			if (*pos == '\n') {
2083				*pos = '\0';
2084				break;
2085			}
2086			pos++;
2087		}
2088		argc = 0;
2089		pos = cmd;
2090		for (;;) {
2091			while (*pos == ' ')
2092				pos++;
2093			if (*pos == '\0')
2094				break;
2095			argv[argc] = pos;
2096			argc++;
2097			if (argc == max_args)
2098				break;
2099			if (*pos == '"') {
2100				char *pos2 = os_strrchr(pos, '"');
2101				if (pos2)
2102					pos = pos2 + 1;
2103			}
2104			while (*pos != '\0' && *pos != ' ')
2105				pos++;
2106			if (*pos == ' ')
2107				*pos++ = '\0';
2108		}
2109		if (argc)
2110			wpa_request(ctrl_conn, argc, argv);
2111
2112		if (cmd != cmdbuf)
2113			free(cmd);
2114#ifdef CONFIG_WPA_CLI_FORK
2115		if (mon_pid)
2116			kill(mon_pid, SIGUSR2);
2117#endif /* CONFIG_WPA_CLI_FORK */
2118	} while (!wpa_cli_quit);
2119
2120#ifdef CONFIG_READLINE
2121	if (hfile) {
2122		/* Save command history, excluding lines that may contain
2123		 * passwords. */
2124		HIST_ENTRY *h;
2125		history_set_pos(0);
2126		while ((h = current_history())) {
2127			const char *p = h->line;
2128			while (*p == ' ' || *p == '\t')
2129				p++;
2130			if (cmd_has_sensitive_data(p)) {
2131				h = remove_history(where_history());
2132				if (h) {
2133					os_free(__UNCONST(h->line));
2134					os_free(__UNCONST(h->data));
2135					os_free(h);
2136				} else
2137					next_history();
2138			} else
2139				next_history();
2140		}
2141		write_history(hfile);
2142		os_free(hfile);
2143	}
2144#endif /* CONFIG_READLINE */
2145}
2146
2147
2148static void wpa_cli_action(struct wpa_ctrl *ctrl)
2149{
2150#ifdef CONFIG_ANSI_C_EXTRA
2151	/* TODO: ANSI C version(?) */
2152	printf("Action processing not supported in ANSI C build.\n");
2153#else /* CONFIG_ANSI_C_EXTRA */
2154	fd_set rfds;
2155	int fd, res;
2156	struct timeval tv;
2157	char buf[256]; /* note: large enough to fit in unsolicited messages */
2158	size_t len;
2159
2160	fd = wpa_ctrl_get_fd(ctrl);
2161
2162	while (!wpa_cli_quit) {
2163		FD_ZERO(&rfds);
2164		FD_SET(fd, &rfds);
2165		tv.tv_sec = ping_interval;
2166		tv.tv_usec = 0;
2167		res = select(fd + 1, &rfds, NULL, NULL, &tv);
2168		if (res < 0 && errno != EINTR) {
2169			perror("select");
2170			break;
2171		}
2172
2173		if (FD_ISSET(fd, &rfds))
2174			wpa_cli_recv_pending(ctrl, 0, 1);
2175		else {
2176			/* verify that connection is still working */
2177			len = sizeof(buf) - 1;
2178			if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
2179					     wpa_cli_action_cb) < 0 ||
2180			    len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
2181				printf("wpa_supplicant did not reply to PING "
2182				       "command - exiting\n");
2183				break;
2184			}
2185		}
2186	}
2187#endif /* CONFIG_ANSI_C_EXTRA */
2188}
2189
2190
2191static void wpa_cli_cleanup(void)
2192{
2193	wpa_cli_close_connection();
2194	if (pid_file)
2195		os_daemonize_terminate(pid_file);
2196
2197	os_program_deinit();
2198}
2199
2200static void wpa_cli_terminate(int sig)
2201{
2202	wpa_cli_cleanup();
2203	exit(0);
2204}
2205
2206
2207#ifdef CONFIG_WPA_CLI_FORK
2208static void wpa_cli_usr1(int sig)
2209{
2210#ifdef CONFIG_READLINE
2211	rl_on_new_line();
2212	rl_redisplay();
2213#endif /* CONFIG_READLINE */
2214}
2215#endif /* CONFIG_WPA_CLI_FORK */
2216
2217
2218#ifndef CONFIG_NATIVE_WINDOWS
2219static void wpa_cli_alarm(int sig)
2220{
2221	if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
2222		printf("Connection to wpa_supplicant lost - trying to "
2223		       "reconnect\n");
2224		wpa_cli_close_connection();
2225	}
2226	if (!ctrl_conn)
2227		wpa_cli_reconnect();
2228	if (mon_conn)
2229		wpa_cli_recv_pending(mon_conn, 1, 0);
2230	alarm(ping_interval);
2231}
2232#endif /* CONFIG_NATIVE_WINDOWS */
2233
2234
2235static char * wpa_cli_get_default_ifname(void)
2236{
2237	char *ifname = NULL;
2238
2239#ifdef CONFIG_CTRL_IFACE_UNIX
2240	struct dirent *dent;
2241	DIR *dir = opendir(ctrl_iface_dir);
2242	if (!dir)
2243		return NULL;
2244	while ((dent = readdir(dir))) {
2245#ifdef _DIRENT_HAVE_D_TYPE
2246		/*
2247		 * Skip the file if it is not a socket. Also accept
2248		 * DT_UNKNOWN (0) in case the C library or underlying
2249		 * file system does not support d_type.
2250		 */
2251		if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
2252			continue;
2253#endif /* _DIRENT_HAVE_D_TYPE */
2254		if (os_strcmp(dent->d_name, ".") == 0 ||
2255		    os_strcmp(dent->d_name, "..") == 0)
2256			continue;
2257		printf("Selected interface '%s'\n", dent->d_name);
2258		ifname = os_strdup(dent->d_name);
2259		break;
2260	}
2261	closedir(dir);
2262#endif /* CONFIG_CTRL_IFACE_UNIX */
2263
2264#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
2265	char buf[2048], *pos;
2266	size_t len;
2267	struct wpa_ctrl *ctrl;
2268	int ret;
2269
2270	ctrl = wpa_ctrl_open(NULL);
2271	if (ctrl == NULL)
2272		return NULL;
2273
2274	len = sizeof(buf) - 1;
2275	ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL);
2276	if (ret >= 0) {
2277		buf[len] = '\0';
2278		pos = os_strchr(buf, '\n');
2279		if (pos)
2280			*pos = '\0';
2281		ifname = os_strdup(buf);
2282	}
2283	wpa_ctrl_close(ctrl);
2284#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
2285
2286	return ifname;
2287}
2288
2289
2290int main(int argc, char *argv[])
2291{
2292	int warning_displayed = 0;
2293	int c;
2294	int daemonize = 0;
2295	int ret = 0;
2296	const char *global = NULL;
2297
2298	if (os_program_init())
2299		return -1;
2300
2301	for (;;) {
2302		c = getopt(argc, argv, "a:Bg:G:hi:p:P:v");
2303		if (c < 0)
2304			break;
2305		switch (c) {
2306		case 'a':
2307			action_file = optarg;
2308			break;
2309		case 'B':
2310			daemonize = 1;
2311			break;
2312		case 'g':
2313			global = optarg;
2314			break;
2315		case 'G':
2316			ping_interval = atoi(optarg);
2317			break;
2318		case 'h':
2319			usage();
2320			return 0;
2321		case 'v':
2322			printf("%s\n", wpa_cli_version);
2323			return 0;
2324		case 'i':
2325			os_free(ctrl_ifname);
2326			ctrl_ifname = os_strdup(optarg);
2327			break;
2328		case 'p':
2329			ctrl_iface_dir = optarg;
2330			break;
2331		case 'P':
2332			pid_file = optarg;
2333			break;
2334		default:
2335			usage();
2336			return -1;
2337		}
2338	}
2339
2340	interactive = (argc == optind) && (action_file == NULL);
2341
2342	if (interactive)
2343		printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license);
2344
2345	if (global) {
2346#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
2347		ctrl_conn = wpa_ctrl_open(NULL);
2348#else /* CONFIG_CTRL_IFACE_NAMED_PIPE */
2349		ctrl_conn = wpa_ctrl_open(global);
2350#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
2351		if (ctrl_conn == NULL) {
2352			perror("Failed to connect to wpa_supplicant - "
2353			       "wpa_ctrl_open");
2354			return -1;
2355		}
2356	}
2357
2358#ifndef _WIN32_WCE
2359	signal(SIGINT, wpa_cli_terminate);
2360	signal(SIGTERM, wpa_cli_terminate);
2361#endif /* _WIN32_WCE */
2362#ifndef CONFIG_NATIVE_WINDOWS
2363	signal(SIGALRM, wpa_cli_alarm);
2364#endif /* CONFIG_NATIVE_WINDOWS */
2365#ifdef CONFIG_WPA_CLI_FORK
2366	signal(SIGUSR1, wpa_cli_usr1);
2367#endif /* CONFIG_WPA_CLI_FORK */
2368
2369	if (ctrl_ifname == NULL)
2370		ctrl_ifname = wpa_cli_get_default_ifname();
2371
2372	if (interactive) {
2373		for (; !global;) {
2374			if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
2375				if (warning_displayed)
2376					printf("Connection established.\n");
2377				break;
2378			}
2379
2380			if (!warning_displayed) {
2381				printf("Could not connect to wpa_supplicant - "
2382				       "re-trying\n");
2383				warning_displayed = 1;
2384			}
2385			os_sleep(1, 0);
2386			continue;
2387		}
2388	} else {
2389		if (!global &&
2390		    wpa_cli_open_connection(ctrl_ifname, 0) < 0) {
2391			perror("Failed to connect to wpa_supplicant - "
2392			       "wpa_ctrl_open");
2393			return -1;
2394		}
2395
2396		if (action_file) {
2397			if (wpa_ctrl_attach(ctrl_conn) == 0) {
2398				wpa_cli_attached = 1;
2399			} else {
2400				printf("Warning: Failed to attach to "
2401				       "wpa_supplicant.\n");
2402				return -1;
2403			}
2404		}
2405	}
2406
2407	if (daemonize && os_daemonize(pid_file))
2408		return -1;
2409
2410	if (interactive)
2411		wpa_cli_interactive();
2412	else if (action_file)
2413		wpa_cli_action(ctrl_conn);
2414	else
2415		ret = wpa_request(ctrl_conn, argc - optind, &argv[optind]);
2416
2417	os_free(ctrl_ifname);
2418	wpa_cli_cleanup();
2419
2420	return ret;
2421}
2422
2423#else /* CONFIG_CTRL_IFACE */
2424int main(int argc, char *argv[])
2425{
2426	printf("CONFIG_CTRL_IFACE not defined - wpa_cli disabled\n");
2427	return -1;
2428}
2429#endif /* CONFIG_CTRL_IFACE */
2430