wpa_cli.c revision 214734
1189251Ssam/*
2189251Ssam * WPA Supplicant - command line interface for wpa_supplicant daemon
3214734Srpaulo * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
4189251Ssam *
5189251Ssam * This program is free software; you can redistribute it and/or modify
6189251Ssam * it under the terms of the GNU General Public License version 2 as
7189251Ssam * published by the Free Software Foundation.
8189251Ssam *
9189251Ssam * Alternatively, this software may be distributed under the terms of BSD
10189251Ssam * license.
11189251Ssam *
12189251Ssam * See README and COPYING for more details.
13189251Ssam */
14189251Ssam
15189251Ssam#include "includes.h"
16189251Ssam
17189251Ssam#ifdef CONFIG_CTRL_IFACE
18189251Ssam
19189251Ssam#ifdef CONFIG_CTRL_IFACE_UNIX
20189251Ssam#include <dirent.h>
21189251Ssam#endif /* CONFIG_CTRL_IFACE_UNIX */
22189251Ssam#ifdef CONFIG_READLINE
23189251Ssam#include <readline/readline.h>
24189251Ssam#include <readline/history.h>
25189251Ssam#endif /* CONFIG_READLINE */
26189251Ssam#ifdef CONFIG_WPA_CLI_FORK
27189251Ssam#include <sys/wait.h>
28189251Ssam#endif /* CONFIG_WPA_CLI_FORK */
29189251Ssam
30189251Ssam#include "common/wpa_ctrl.h"
31189251Ssam#include "common.h"
32189251Ssam#include "common/version.h"
33189251Ssam
34189251Ssam
35189251Ssamstatic const char *wpa_cli_version =
36214734Srpaulo"wpa_cli v" VERSION_STR "\n"
37189251Ssam"Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi> and contributors";
38214734Srpaulo
39189251Ssam
40189251Ssamstatic const char *wpa_cli_license =
41189251Ssam"This program is free software. You can distribute it and/or modify it\n"
42189251Ssam"under the terms of the GNU General Public License version 2.\n"
43189251Ssam"\n"
44189251Ssam"Alternatively, this software may be distributed under the terms of the\n"
45189251Ssam"BSD license. See README and COPYING for more details.\n";
46214734Srpaulo
47189251Ssamstatic const char *wpa_cli_full_license =
48214734Srpaulo"This program is free software; you can redistribute it and/or modify\n"
49189251Ssam"it under the terms of the GNU General Public License version 2 as\n"
50214734Srpaulo"published by the Free Software Foundation.\n"
51189251Ssam"\n"
52214734Srpaulo"This program is distributed in the hope that it will be useful,\n"
53214734Srpaulo"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
54214734Srpaulo"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
55214734Srpaulo"GNU General Public License for more details.\n"
56214734Srpaulo"\n"
57214734Srpaulo"You should have received a copy of the GNU General Public License\n"
58214734Srpaulo"along with this program; if not, write to the Free Software\n"
59214734Srpaulo"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n"
60214734Srpaulo"\n"
61214734Srpaulo"Alternatively, this software may be distributed under the terms of the\n"
62214734Srpaulo"BSD license.\n"
63214734Srpaulo"\n"
64214734Srpaulo"Redistribution and use in source and binary forms, with or without\n"
65214734Srpaulo"modification, are permitted provided that the following conditions are\n"
66214734Srpaulo"met:\n"
67189251Ssam"\n"
68189251Ssam"1. Redistributions of source code must retain the above copyright\n"
69189251Ssam"   notice, this list of conditions and the following disclaimer.\n"
70189251Ssam"\n"
71189251Ssam"2. Redistributions in binary form must reproduce the above copyright\n"
72214734Srpaulo"   notice, this list of conditions and the following disclaimer in the\n"
73189251Ssam"   documentation and/or other materials provided with the distribution.\n"
74214734Srpaulo"\n"
75214734Srpaulo"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
76189251Ssam"   names of its contributors may be used to endorse or promote products\n"
77189251Ssam"   derived from this software without specific prior written permission.\n"
78189251Ssam"\n"
79189251Ssam"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
80189251Ssam"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
81189251Ssam"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
82189251Ssam"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
83189251Ssam"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
84189251Ssam"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
85189251Ssam"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
86189251Ssam"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
87189251Ssam"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
88189251Ssam"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
89189251Ssam"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
90189251Ssam"\n";
91189251Ssam
92189251Ssamstatic struct wpa_ctrl *ctrl_conn;
93189251Ssamstatic struct wpa_ctrl *mon_conn;
94189251Ssam#ifdef CONFIG_WPA_CLI_FORK
95189251Ssamstatic pid_t mon_pid = 0;
96189251Ssam#endif /* CONFIG_WPA_CLI_FORK */
97189251Ssamstatic int wpa_cli_quit = 0;
98214734Srpaulostatic int wpa_cli_attached = 0;
99189251Ssamstatic int wpa_cli_connected = 0;
100214734Srpaulostatic int wpa_cli_last_id = 0;
101214734Srpaulostatic const char *ctrl_iface_dir = "/var/run/wpa_supplicant";
102189251Ssamstatic char *ctrl_ifname = NULL;
103189251Ssamstatic const char *pid_file = NULL;
104189251Ssamstatic const char *action_file = NULL;
105189251Ssamstatic int ping_interval = 5;
106189251Ssamstatic int interactive = 0;
107189251Ssam
108189251Ssam
109189251Ssamstatic void print_help();
110189251Ssam
111189251Ssam
112189251Ssamstatic void usage(void)
113189251Ssam{
114189251Ssam	printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] "
115189251Ssam	       "[-a<action file>] \\\n"
116189251Ssam	       "        [-P<pid file>] [-g<global ctrl>] [-G<ping interval>]  "
117189251Ssam	       "[command..]\n"
118189251Ssam	       "  -h = help (show this usage text)\n"
119189251Ssam	       "  -v = shown version information\n"
120189251Ssam	       "  -a = run in daemon mode executing the action file based on "
121189251Ssam	       "events from\n"
122189251Ssam	       "       wpa_supplicant\n"
123189251Ssam	       "  -B = run a daemon in the background\n"
124189251Ssam	       "  default path: /var/run/wpa_supplicant\n"
125189251Ssam	       "  default interface: first interface found in socket path\n");
126189251Ssam	print_help();
127189251Ssam}
128189251Ssam
129189251Ssam
130189251Ssam#ifdef CONFIG_WPA_CLI_FORK
131189251Ssamstatic int in_query = 0;
132189251Ssam
133189251Ssamstatic void wpa_cli_monitor_sig(int sig)
134189251Ssam{
135189251Ssam	if (sig == SIGUSR1)
136189251Ssam		in_query = 1;
137189251Ssam	else if (sig == SIGUSR2)
138189251Ssam		in_query = 0;
139189251Ssam}
140189251Ssam
141189251Ssamstatic void wpa_cli_monitor(void)
142189251Ssam{
143189251Ssam	char buf[256];
144189251Ssam	size_t len = sizeof(buf) - 1;
145189251Ssam	struct timeval tv;
146189251Ssam	fd_set rfds;
147189251Ssam
148189251Ssam	signal(SIGUSR1, wpa_cli_monitor_sig);
149189251Ssam	signal(SIGUSR2, wpa_cli_monitor_sig);
150189251Ssam
151189251Ssam	while (mon_conn) {
152189251Ssam		int s = wpa_ctrl_get_fd(mon_conn);
153189251Ssam		tv.tv_sec = 5;
154189251Ssam		tv.tv_usec = 0;
155189251Ssam		FD_ZERO(&rfds);
156189251Ssam		FD_SET(s, &rfds);
157189251Ssam		if (select(s + 1, &rfds, NULL, NULL, &tv) < 0) {
158189251Ssam			if (errno == EINTR)
159189251Ssam				continue;
160189251Ssam			perror("select");
161189251Ssam			break;
162189251Ssam		}
163189251Ssam		if (mon_conn == NULL)
164189251Ssam			break;
165189251Ssam		if (FD_ISSET(s, &rfds)) {
166189251Ssam			len = sizeof(buf) - 1;
167189251Ssam			int res = wpa_ctrl_recv(mon_conn, buf, &len);
168189251Ssam			if (res < 0) {
169189251Ssam				perror("wpa_ctrl_recv");
170189251Ssam				break;
171189251Ssam			}
172189251Ssam			buf[len] = '\0';
173189251Ssam			if (in_query)
174189251Ssam				printf("\r");
175189251Ssam			printf("%s\n", buf);
176189251Ssam			kill(getppid(), SIGUSR1);
177189251Ssam		}
178189251Ssam	}
179189251Ssam}
180189251Ssam#endif /* CONFIG_WPA_CLI_FORK */
181189251Ssam
182189251Ssam
183189251Ssamstatic int wpa_cli_open_connection(const char *ifname, int attach)
184189251Ssam{
185189251Ssam#if defined(CONFIG_CTRL_IFACE_UDP) || defined(CONFIG_CTRL_IFACE_NAMED_PIPE)
186189251Ssam	ctrl_conn = wpa_ctrl_open(ifname);
187189251Ssam	if (ctrl_conn == NULL)
188189251Ssam		return -1;
189189251Ssam
190189251Ssam	if (attach && interactive)
191189251Ssam		mon_conn = wpa_ctrl_open(ifname);
192189251Ssam	else
193189251Ssam		mon_conn = NULL;
194189251Ssam#else /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
195189251Ssam	char *cfile;
196189251Ssam	int flen, res;
197189251Ssam
198189251Ssam	if (ifname == NULL)
199189251Ssam		return -1;
200189251Ssam
201189251Ssam	flen = os_strlen(ctrl_iface_dir) + os_strlen(ifname) + 2;
202189251Ssam	cfile = os_malloc(flen);
203189251Ssam	if (cfile == NULL)
204189251Ssam		return -1L;
205189251Ssam	res = os_snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
206189251Ssam	if (res < 0 || res >= flen) {
207189251Ssam		os_free(cfile);
208189251Ssam		return -1;
209189251Ssam	}
210189251Ssam
211189251Ssam	ctrl_conn = wpa_ctrl_open(cfile);
212189251Ssam	if (ctrl_conn == NULL) {
213189251Ssam		os_free(cfile);
214189251Ssam		return -1;
215189251Ssam	}
216189251Ssam
217189251Ssam	if (attach && interactive)
218189251Ssam		mon_conn = wpa_ctrl_open(cfile);
219189251Ssam	else
220189251Ssam		mon_conn = NULL;
221189251Ssam	os_free(cfile);
222189251Ssam#endif /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
223189251Ssam
224189251Ssam	if (mon_conn) {
225189251Ssam		if (wpa_ctrl_attach(mon_conn) == 0) {
226189251Ssam			wpa_cli_attached = 1;
227189251Ssam		} else {
228189251Ssam			printf("Warning: Failed to attach to "
229189251Ssam			       "wpa_supplicant.\n");
230189251Ssam			return -1;
231189251Ssam		}
232189251Ssam
233189251Ssam#ifdef CONFIG_WPA_CLI_FORK
234189251Ssam		{
235189251Ssam			pid_t p = fork();
236189251Ssam			if (p < 0) {
237189251Ssam				perror("fork");
238189251Ssam				return -1;
239189251Ssam			}
240189251Ssam			if (p == 0) {
241189251Ssam				wpa_cli_monitor();
242189251Ssam				exit(0);
243189251Ssam			} else
244189251Ssam				mon_pid = p;
245189251Ssam		}
246189251Ssam#endif /* CONFIG_WPA_CLI_FORK */
247189251Ssam	}
248189251Ssam
249189251Ssam	return 0;
250189251Ssam}
251189251Ssam
252189251Ssam
253189251Ssamstatic void wpa_cli_close_connection(void)
254189251Ssam{
255189251Ssam	if (ctrl_conn == NULL)
256189251Ssam		return;
257189251Ssam
258189251Ssam#ifdef CONFIG_WPA_CLI_FORK
259189251Ssam	if (mon_pid) {
260189251Ssam		int status;
261189251Ssam		kill(mon_pid, SIGPIPE);
262189251Ssam		wait(&status);
263189251Ssam		mon_pid = 0;
264189251Ssam	}
265189251Ssam#endif /* CONFIG_WPA_CLI_FORK */
266189251Ssam
267189251Ssam	if (wpa_cli_attached) {
268189251Ssam		wpa_ctrl_detach(interactive ? mon_conn : ctrl_conn);
269189251Ssam		wpa_cli_attached = 0;
270189251Ssam	}
271189251Ssam	wpa_ctrl_close(ctrl_conn);
272189251Ssam	ctrl_conn = NULL;
273189251Ssam	if (mon_conn) {
274189251Ssam		wpa_ctrl_close(mon_conn);
275189251Ssam		mon_conn = NULL;
276189251Ssam	}
277189251Ssam}
278189251Ssam
279189251Ssam
280189251Ssamstatic void wpa_cli_msg_cb(char *msg, size_t len)
281189251Ssam{
282189251Ssam	printf("%s\n", msg);
283189251Ssam}
284189251Ssam
285189251Ssam
286189251Ssamstatic int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
287189251Ssam{
288189251Ssam	char buf[2048];
289189251Ssam	size_t len;
290189251Ssam	int ret;
291189251Ssam
292189251Ssam	if (ctrl_conn == NULL) {
293189251Ssam		printf("Not connected to wpa_supplicant - command dropped.\n");
294189251Ssam		return -1;
295189251Ssam	}
296189251Ssam	len = sizeof(buf) - 1;
297189251Ssam	ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
298214734Srpaulo			       wpa_cli_msg_cb);
299189251Ssam	if (ret == -2) {
300189251Ssam		printf("'%s' command timed out.\n", cmd);
301189251Ssam		return -2;
302189251Ssam	} else if (ret < 0) {
303189251Ssam		printf("'%s' command failed.\n", cmd);
304189251Ssam		return -1;
305189251Ssam	}
306214734Srpaulo	if (print) {
307214734Srpaulo		buf[len] = '\0';
308189251Ssam		printf("%s", buf);
309189251Ssam	}
310189251Ssam	return 0;
311189251Ssam}
312189251Ssam
313189251Ssam
314189251Ssamstatic int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
315189251Ssam{
316189251Ssam	return _wpa_ctrl_command(ctrl, cmd, 1);
317189251Ssam}
318189251Ssam
319189251Ssam
320189251Ssamstatic int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
321189251Ssam{
322189251Ssam	int verbose = argc > 0 && os_strcmp(argv[0], "verbose") == 0;
323189251Ssam	return wpa_ctrl_command(ctrl, verbose ? "STATUS-VERBOSE" : "STATUS");
324189251Ssam}
325189251Ssam
326189251Ssam
327189251Ssamstatic int wpa_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
328189251Ssam{
329189251Ssam	return wpa_ctrl_command(ctrl, "PING");
330189251Ssam}
331189251Ssam
332189251Ssam
333189251Ssamstatic int wpa_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
334189251Ssam{
335189251Ssam	return wpa_ctrl_command(ctrl, "MIB");
336189251Ssam}
337189251Ssam
338189251Ssam
339189251Ssamstatic int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
340189251Ssam{
341189251Ssam	return wpa_ctrl_command(ctrl, "PMKSA");
342189251Ssam}
343189251Ssam
344189251Ssam
345189251Ssamstatic int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
346189251Ssam{
347189251Ssam	print_help();
348189251Ssam	return 0;
349189251Ssam}
350189251Ssam
351189251Ssam
352189251Ssamstatic int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[])
353189251Ssam{
354189251Ssam	printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license);
355189251Ssam	return 0;
356189251Ssam}
357189251Ssam
358189251Ssam
359189251Ssamstatic int wpa_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
360189251Ssam{
361189251Ssam	wpa_cli_quit = 1;
362189251Ssam	return 0;
363189251Ssam}
364189251Ssam
365189251Ssam
366189251Ssamstatic void wpa_cli_show_variables(void)
367189251Ssam{
368189251Ssam	printf("set variables:\n"
369189251Ssam	       "  EAPOL::heldPeriod (EAPOL state machine held period, "
370189251Ssam	       "in seconds)\n"
371189251Ssam	       "  EAPOL::authPeriod (EAPOL state machine authentication "
372189251Ssam	       "period, in seconds)\n"
373189251Ssam	       "  EAPOL::startPeriod (EAPOL state machine start period, in "
374189251Ssam	       "seconds)\n"
375189251Ssam	       "  EAPOL::maxStart (EAPOL state machine maximum start "
376189251Ssam	       "attempts)\n");
377189251Ssam	printf("  dot11RSNAConfigPMKLifetime (WPA/WPA2 PMK lifetime in "
378189251Ssam	       "seconds)\n"
379189251Ssam	       "  dot11RSNAConfigPMKReauthThreshold (WPA/WPA2 reauthentication"
380189251Ssam	       " threshold\n\tpercentage)\n"
381189251Ssam	       "  dot11RSNAConfigSATimeout (WPA/WPA2 timeout for completing "
382189251Ssam	       "security\n\tassociation in seconds)\n");
383189251Ssam}
384189251Ssam
385189251Ssam
386189251Ssamstatic int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
387189251Ssam{
388189251Ssam	char cmd[256];
389189251Ssam	int res;
390189251Ssam
391189251Ssam	if (argc == 0) {
392189251Ssam		wpa_cli_show_variables();
393189251Ssam		return 0;
394189251Ssam	}
395189251Ssam
396189251Ssam	if (argc != 2) {
397189251Ssam		printf("Invalid SET command: needs two arguments (variable "
398189251Ssam		       "name and value)\n");
399189251Ssam		return -1;
400189251Ssam	}
401189251Ssam
402189251Ssam	res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
403189251Ssam	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
404189251Ssam		printf("Too long SET command.\n");
405189251Ssam		return -1;
406189251Ssam	}
407189251Ssam	return wpa_ctrl_command(ctrl, cmd);
408189251Ssam}
409189251Ssam
410189251Ssam
411189251Ssamstatic int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[])
412189251Ssam{
413189251Ssam	return wpa_ctrl_command(ctrl, "LOGOFF");
414189251Ssam}
415189251Ssam
416189251Ssam
417189251Ssamstatic int wpa_cli_cmd_logon(struct wpa_ctrl *ctrl, int argc, char *argv[])
418189251Ssam{
419189251Ssam	return wpa_ctrl_command(ctrl, "LOGON");
420189251Ssam}
421189251Ssam
422189251Ssam
423189251Ssamstatic int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc,
424189251Ssam				   char *argv[])
425189251Ssam{
426189251Ssam	return wpa_ctrl_command(ctrl, "REASSOCIATE");
427189251Ssam}
428189251Ssam
429189251Ssam
430189251Ssamstatic int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc,
431189251Ssam				       char *argv[])
432189251Ssam{
433189251Ssam	char cmd[256];
434189251Ssam	int res;
435189251Ssam
436189251Ssam	if (argc != 1) {
437189251Ssam		printf("Invalid PREAUTH command: needs one argument "
438189251Ssam		       "(BSSID)\n");
439189251Ssam		return -1;
440189251Ssam	}
441189251Ssam
442189251Ssam	res = os_snprintf(cmd, sizeof(cmd), "PREAUTH %s", argv[0]);
443189251Ssam	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
444189251Ssam		printf("Too long PREAUTH command.\n");
445189251Ssam		return -1;
446189251Ssam	}
447189251Ssam	return wpa_ctrl_command(ctrl, cmd);
448189251Ssam}
449189251Ssam
450189251Ssam
451189251Ssamstatic int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
452189251Ssam{
453214734Srpaulo	char cmd[256];
454214734Srpaulo	int res;
455214734Srpaulo
456214734Srpaulo	if (argc != 1) {
457214734Srpaulo		printf("Invalid AP_SCAN command: needs one argument (ap_scan "
458214734Srpaulo		       "value)\n");
459214734Srpaulo		return -1;
460214734Srpaulo	}
461214734Srpaulo	res = os_snprintf(cmd, sizeof(cmd), "AP_SCAN %s", argv[0]);
462214734Srpaulo	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
463214734Srpaulo		printf("Too long AP_SCAN command.\n");
464214734Srpaulo		return -1;
465214734Srpaulo	}
466214734Srpaulo	return wpa_ctrl_command(ctrl, cmd);
467214734Srpaulo}
468214734Srpaulo
469189251Ssam
470static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc,
471				char *argv[])
472{
473	char cmd[256];
474	int res;
475
476	if (argc != 1) {
477		printf("Invalid STKSTART command: needs one argument "
478		       "(Peer STA MAC address)\n");
479		return -1;
480	}
481
482	res = os_snprintf(cmd, sizeof(cmd), "STKSTART %s", argv[0]);
483	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
484		printf("Too long STKSTART command.\n");
485		return -1;
486	}
487	return wpa_ctrl_command(ctrl, cmd);
488}
489
490
491static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[])
492{
493	char cmd[256];
494	int res;
495
496	if (argc != 1) {
497		printf("Invalid FT_DS command: needs one argument "
498		       "(Target AP MAC address)\n");
499		return -1;
500	}
501
502	res = os_snprintf(cmd, sizeof(cmd), "FT_DS %s", argv[0]);
503	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
504		printf("Too long FT_DS command.\n");
505		return -1;
506	}
507	return wpa_ctrl_command(ctrl, cmd);
508}
509
510
511static int wpa_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[])
512{
513	char cmd[256];
514	int res;
515
516	if (argc == 0) {
517		/* Any BSSID */
518		return wpa_ctrl_command(ctrl, "WPS_PBC");
519	}
520
521	/* Specific BSSID */
522	res = os_snprintf(cmd, sizeof(cmd), "WPS_PBC %s", argv[0]);
523	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
524		printf("Too long WPS_PBC command.\n");
525		return -1;
526	}
527	return wpa_ctrl_command(ctrl, cmd);
528}
529
530
531static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
532{
533	char cmd[256];
534	int res;
535
536	if (argc == 0) {
537		printf("Invalid WPS_PIN command: need one or two arguments:\n"
538		       "- BSSID: use 'any' to select any\n"
539		       "- PIN: optional, used only with devices that have no "
540		       "display\n");
541		return -1;
542	}
543
544	if (argc == 1) {
545		/* Use dynamically generated PIN (returned as reply) */
546		res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s", argv[0]);
547		if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
548			printf("Too long WPS_PIN command.\n");
549			return -1;
550		}
551		return wpa_ctrl_command(ctrl, cmd);
552	}
553
554	/* Use hardcoded PIN from a label */
555	res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s", argv[0], argv[1]);
556	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
557		printf("Too long WPS_PIN command.\n");
558		return -1;
559	}
560	return wpa_ctrl_command(ctrl, cmd);
561}
562
563
564#ifdef CONFIG_WPS_OOB
565static int wpa_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, char *argv[])
566{
567	char cmd[256];
568	int res;
569
570	if (argc != 3 && argc != 4) {
571		printf("Invalid WPS_OOB command: need three or four "
572		       "arguments:\n"
573		       "- DEV_TYPE: use 'ufd' or 'nfc'\n"
574		       "- PATH: path of OOB device like '/mnt'\n"
575		       "- METHOD: OOB method 'pin-e' or 'pin-r', "
576		       "'cred'\n"
577		       "- DEV_NAME: (only for NFC) device name like "
578		       "'pn531'\n");
579		return -1;
580	}
581
582	if (argc == 3)
583		res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
584				  argv[0], argv[1], argv[2]);
585	else
586		res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
587				  argv[0], argv[1], argv[2], argv[3]);
588	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
589		printf("Too long WPS_OOB command.\n");
590		return -1;
591	}
592	return wpa_ctrl_command(ctrl, cmd);
593}
594#endif /* CONFIG_WPS_OOB */
595
596
597static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
598{
599	char cmd[256];
600	int res;
601
602	if (argc == 2)
603		res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s",
604				  argv[0], argv[1]);
605	else if (argc == 6) {
606		char ssid_hex[2 * 32 + 1];
607		char key_hex[2 * 64 + 1];
608		int i;
609
610		ssid_hex[0] = '\0';
611		for (i = 0; i < 32; i++) {
612			if (argv[2][i] == '\0')
613				break;
614			os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]);
615		}
616
617		key_hex[0] = '\0';
618		for (i = 0; i < 64; i++) {
619			if (argv[5][i] == '\0')
620				break;
621			os_snprintf(&key_hex[i * 2], 3, "%02x", argv[5][i]);
622		}
623
624		res = os_snprintf(cmd, sizeof(cmd),
625				  "WPS_REG %s %s %s %s %s %s",
626				  argv[0], argv[1], ssid_hex, argv[3], argv[4],
627				  key_hex);
628	} else {
629		printf("Invalid WPS_REG command: need two arguments:\n"
630		       "- BSSID: use 'any' to select any\n"
631		       "- AP PIN\n");
632		printf("Alternatively, six arguments can be used to "
633		       "reconfigure the AP:\n"
634		       "- BSSID: use 'any' to select any\n"
635		       "- AP PIN\n"
636		       "- new SSID\n"
637		       "- new auth (OPEN, WPAPSK, WPA2PSK)\n"
638		       "- new encr (NONE, WEP, TKIP, CCMP)\n"
639		       "- new key\n");
640		return -1;
641	}
642
643	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
644		printf("Too long WPS_REG command.\n");
645		return -1;
646	}
647	return wpa_ctrl_command(ctrl, cmd);
648}
649
650
651static int wpa_cli_cmd_wps_er_start(struct wpa_ctrl *ctrl, int argc,
652				    char *argv[])
653{
654	return wpa_ctrl_command(ctrl, "WPS_ER_START");
655
656}
657
658
659static int wpa_cli_cmd_wps_er_stop(struct wpa_ctrl *ctrl, int argc,
660				   char *argv[])
661{
662	return wpa_ctrl_command(ctrl, "WPS_ER_STOP");
663
664}
665
666
667static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc,
668				  char *argv[])
669{
670	char cmd[256];
671	int res;
672
673	if (argc != 2) {
674		printf("Invalid WPS_ER_PIN command: need two arguments:\n"
675		       "- UUID: use 'any' to select any\n"
676		       "- PIN: Enrollee PIN\n");
677		return -1;
678	}
679
680	res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s",
681			  argv[0], argv[1]);
682	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
683		printf("Too long WPS_ER_PIN command.\n");
684		return -1;
685	}
686	return wpa_ctrl_command(ctrl, cmd);
687}
688
689
690static int wpa_cli_cmd_wps_er_pbc(struct wpa_ctrl *ctrl, int argc,
691				  char *argv[])
692{
693	char cmd[256];
694	int res;
695
696	if (argc != 1) {
697		printf("Invalid WPS_ER_PBC command: need one argument:\n"
698		       "- UUID: Specify the Enrollee\n");
699		return -1;
700	}
701
702	res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PBC %s",
703			  argv[0]);
704	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
705		printf("Too long WPS_ER_PBC command.\n");
706		return -1;
707	}
708	return wpa_ctrl_command(ctrl, cmd);
709}
710
711
712static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc,
713				    char *argv[])
714{
715	char cmd[256];
716	int res;
717
718	if (argc != 2) {
719		printf("Invalid WPS_ER_LEARN command: need two arguments:\n"
720		       "- UUID: specify which AP to use\n"
721		       "- PIN: AP PIN\n");
722		return -1;
723	}
724
725	res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_LEARN %s %s",
726			  argv[0], argv[1]);
727	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
728		printf("Too long WPS_ER_LEARN command.\n");
729		return -1;
730	}
731	return wpa_ctrl_command(ctrl, cmd);
732}
733
734
735static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[])
736{
737	char cmd[256];
738	int res;
739
740	if (argc != 1) {
741		printf("Invalid IBSS_RSN command: needs one argument "
742		       "(Peer STA MAC address)\n");
743		return -1;
744	}
745
746	res = os_snprintf(cmd, sizeof(cmd), "IBSS_RSN %s", argv[0]);
747	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
748		printf("Too long IBSS_RSN command.\n");
749		return -1;
750	}
751	return wpa_ctrl_command(ctrl, cmd);
752}
753
754
755static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
756{
757	char cmd[256];
758	int res;
759
760	if (argc != 1) {
761		printf("Invalid LEVEL command: needs one argument (debug "
762		       "level)\n");
763		return -1;
764	}
765	res = os_snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
766	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
767		printf("Too long LEVEL command.\n");
768		return -1;
769	}
770	return wpa_ctrl_command(ctrl, cmd);
771}
772
773
774static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[])
775{
776	char cmd[256], *pos, *end;
777	int i, ret;
778
779	if (argc < 2) {
780		printf("Invalid IDENTITY command: needs two arguments "
781		       "(network id and identity)\n");
782		return -1;
783	}
784
785	end = cmd + sizeof(cmd);
786	pos = cmd;
787	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s",
788			  argv[0], argv[1]);
789	if (ret < 0 || ret >= end - pos) {
790		printf("Too long IDENTITY command.\n");
791		return -1;
792	}
793	pos += ret;
794	for (i = 2; i < argc; i++) {
795		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
796		if (ret < 0 || ret >= end - pos) {
797			printf("Too long IDENTITY command.\n");
798			return -1;
799		}
800		pos += ret;
801	}
802
803	return wpa_ctrl_command(ctrl, cmd);
804}
805
806
807static int wpa_cli_cmd_password(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 PASSWORD command: needs two arguments "
814		       "(network id and password)\n");
815		return -1;
816	}
817
818	end = cmd + sizeof(cmd);
819	pos = cmd;
820	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s",
821			  argv[0], argv[1]);
822	if (ret < 0 || ret >= end - pos) {
823		printf("Too long PASSWORD 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 PASSWORD 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_new_password(struct wpa_ctrl *ctrl, int argc,
841				    char *argv[])
842{
843	char cmd[256], *pos, *end;
844	int i, ret;
845
846	if (argc < 2) {
847		printf("Invalid NEW_PASSWORD command: needs two arguments "
848		       "(network id and password)\n");
849		return -1;
850	}
851
852	end = cmd + sizeof(cmd);
853	pos = cmd;
854	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s",
855			  argv[0], argv[1]);
856	if (ret < 0 || ret >= end - pos) {
857		printf("Too long NEW_PASSWORD command.\n");
858		return -1;
859	}
860	pos += ret;
861	for (i = 2; i < argc; i++) {
862		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
863		if (ret < 0 || ret >= end - pos) {
864			printf("Too long NEW_PASSWORD command.\n");
865			return -1;
866		}
867		pos += ret;
868	}
869
870	return wpa_ctrl_command(ctrl, cmd);
871}
872
873
874static int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
875{
876	char cmd[256], *pos, *end;
877	int i, ret;
878
879	if (argc < 2) {
880		printf("Invalid PIN command: needs two arguments "
881		       "(network id and pin)\n");
882		return -1;
883	}
884
885	end = cmd + sizeof(cmd);
886	pos = cmd;
887	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s",
888			  argv[0], argv[1]);
889	if (ret < 0 || ret >= end - pos) {
890		printf("Too long PIN 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 PIN command.\n");
898			return -1;
899		}
900		pos += ret;
901	}
902	return wpa_ctrl_command(ctrl, cmd);
903}
904
905
906static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[])
907{
908	char cmd[256], *pos, *end;
909	int i, ret;
910
911	if (argc < 2) {
912		printf("Invalid OTP command: needs two arguments (network "
913		       "id and password)\n");
914		return -1;
915	}
916
917	end = cmd + sizeof(cmd);
918	pos = cmd;
919	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s",
920			  argv[0], argv[1]);
921	if (ret < 0 || ret >= end - pos) {
922		printf("Too long OTP command.\n");
923		return -1;
924	}
925	pos += ret;
926	for (i = 2; i < argc; i++) {
927		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
928		if (ret < 0 || ret >= end - pos) {
929			printf("Too long OTP command.\n");
930			return -1;
931		}
932		pos += ret;
933	}
934
935	return wpa_ctrl_command(ctrl, cmd);
936}
937
938
939static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
940				  char *argv[])
941{
942	char cmd[256], *pos, *end;
943	int i, ret;
944
945	if (argc < 2) {
946		printf("Invalid PASSPHRASE command: needs two arguments "
947		       "(network id and passphrase)\n");
948		return -1;
949	}
950
951	end = cmd + sizeof(cmd);
952	pos = cmd;
953	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s",
954			  argv[0], argv[1]);
955	if (ret < 0 || ret >= end - pos) {
956		printf("Too long PASSPHRASE command.\n");
957		return -1;
958	}
959	pos += ret;
960	for (i = 2; i < argc; i++) {
961		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
962		if (ret < 0 || ret >= end - pos) {
963			printf("Too long PASSPHRASE command.\n");
964			return -1;
965		}
966		pos += ret;
967	}
968
969	return wpa_ctrl_command(ctrl, cmd);
970}
971
972
973static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[])
974{
975	char cmd[256], *pos, *end;
976	int i, ret;
977
978	if (argc < 2) {
979		printf("Invalid BSSID command: needs two arguments (network "
980		       "id and BSSID)\n");
981		return -1;
982	}
983
984	end = cmd + sizeof(cmd);
985	pos = cmd;
986	ret = os_snprintf(pos, end - pos, "BSSID");
987	if (ret < 0 || ret >= end - pos) {
988		printf("Too long BSSID command.\n");
989		return -1;
990	}
991	pos += ret;
992	for (i = 0; i < argc; i++) {
993		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
994		if (ret < 0 || ret >= end - pos) {
995			printf("Too long BSSID command.\n");
996			return -1;
997		}
998		pos += ret;
999	}
1000
1001	return wpa_ctrl_command(ctrl, cmd);
1002}
1003
1004
1005static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc,
1006				     char *argv[])
1007{
1008	return wpa_ctrl_command(ctrl, "LIST_NETWORKS");
1009}
1010
1011
1012static int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc,
1013				      char *argv[])
1014{
1015	char cmd[32];
1016	int res;
1017
1018	if (argc < 1) {
1019		printf("Invalid SELECT_NETWORK command: needs one argument "
1020		       "(network id)\n");
1021		return -1;
1022	}
1023
1024	res = os_snprintf(cmd, sizeof(cmd), "SELECT_NETWORK %s", argv[0]);
1025	if (res < 0 || (size_t) res >= sizeof(cmd))
1026		return -1;
1027	cmd[sizeof(cmd) - 1] = '\0';
1028
1029	return wpa_ctrl_command(ctrl, cmd);
1030}
1031
1032
1033static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc,
1034				      char *argv[])
1035{
1036	char cmd[32];
1037	int res;
1038
1039	if (argc < 1) {
1040		printf("Invalid ENABLE_NETWORK command: needs one argument "
1041		       "(network id)\n");
1042		return -1;
1043	}
1044
1045	res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s", argv[0]);
1046	if (res < 0 || (size_t) res >= sizeof(cmd))
1047		return -1;
1048	cmd[sizeof(cmd) - 1] = '\0';
1049
1050	return wpa_ctrl_command(ctrl, cmd);
1051}
1052
1053
1054static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc,
1055				       char *argv[])
1056{
1057	char cmd[32];
1058	int res;
1059
1060	if (argc < 1) {
1061		printf("Invalid DISABLE_NETWORK command: needs one argument "
1062		       "(network id)\n");
1063		return -1;
1064	}
1065
1066	res = os_snprintf(cmd, sizeof(cmd), "DISABLE_NETWORK %s", argv[0]);
1067	if (res < 0 || (size_t) res >= sizeof(cmd))
1068		return -1;
1069	cmd[sizeof(cmd) - 1] = '\0';
1070
1071	return wpa_ctrl_command(ctrl, cmd);
1072}
1073
1074
1075static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc,
1076				   char *argv[])
1077{
1078	return wpa_ctrl_command(ctrl, "ADD_NETWORK");
1079}
1080
1081
1082static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc,
1083				      char *argv[])
1084{
1085	char cmd[32];
1086	int res;
1087
1088	if (argc < 1) {
1089		printf("Invalid REMOVE_NETWORK command: needs one argument "
1090		       "(network id)\n");
1091		return -1;
1092	}
1093
1094	res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %s", argv[0]);
1095	if (res < 0 || (size_t) res >= sizeof(cmd))
1096		return -1;
1097	cmd[sizeof(cmd) - 1] = '\0';
1098
1099	return wpa_ctrl_command(ctrl, cmd);
1100}
1101
1102
1103static void wpa_cli_show_network_variables(void)
1104{
1105	printf("set_network variables:\n"
1106	       "  ssid (network name, SSID)\n"
1107	       "  psk (WPA passphrase or pre-shared key)\n"
1108	       "  key_mgmt (key management protocol)\n"
1109	       "  identity (EAP identity)\n"
1110	       "  password (EAP password)\n"
1111	       "  ...\n"
1112	       "\n"
1113	       "Note: Values are entered in the same format as the "
1114	       "configuration file is using,\n"
1115	       "i.e., strings values need to be inside double quotation "
1116	       "marks.\n"
1117	       "For example: set_network 1 ssid \"network name\"\n"
1118	       "\n"
1119	       "Please see wpa_supplicant.conf documentation for full list "
1120	       "of\navailable variables.\n");
1121}
1122
1123
1124static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc,
1125				   char *argv[])
1126{
1127	char cmd[256];
1128	int res;
1129
1130	if (argc == 0) {
1131		wpa_cli_show_network_variables();
1132		return 0;
1133	}
1134
1135	if (argc != 3) {
1136		printf("Invalid SET_NETWORK command: needs three arguments\n"
1137		       "(network id, variable name, and value)\n");
1138		return -1;
1139	}
1140
1141	res = os_snprintf(cmd, sizeof(cmd), "SET_NETWORK %s %s %s",
1142			  argv[0], argv[1], argv[2]);
1143	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
1144		printf("Too long SET_NETWORK command.\n");
1145		return -1;
1146	}
1147	return wpa_ctrl_command(ctrl, cmd);
1148}
1149
1150
1151static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
1152				   char *argv[])
1153{
1154	char cmd[256];
1155	int res;
1156
1157	if (argc == 0) {
1158		wpa_cli_show_network_variables();
1159		return 0;
1160	}
1161
1162	if (argc != 2) {
1163		printf("Invalid GET_NETWORK command: needs two arguments\n"
1164		       "(network id and variable name)\n");
1165		return -1;
1166	}
1167
1168	res = os_snprintf(cmd, sizeof(cmd), "GET_NETWORK %s %s",
1169			  argv[0], argv[1]);
1170	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
1171		printf("Too long GET_NETWORK command.\n");
1172		return -1;
1173	}
1174	return wpa_ctrl_command(ctrl, cmd);
1175}
1176
1177
1178static int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc,
1179				  char *argv[])
1180{
1181	return wpa_ctrl_command(ctrl, "DISCONNECT");
1182}
1183
1184
1185static int wpa_cli_cmd_reconnect(struct wpa_ctrl *ctrl, int argc,
1186				  char *argv[])
1187{
1188	return wpa_ctrl_command(ctrl, "RECONNECT");
1189}
1190
1191
1192static int wpa_cli_cmd_save_config(struct wpa_ctrl *ctrl, int argc,
1193				   char *argv[])
1194{
1195	return wpa_ctrl_command(ctrl, "SAVE_CONFIG");
1196}
1197
1198
1199static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
1200{
1201	return wpa_ctrl_command(ctrl, "SCAN");
1202}
1203
1204
1205static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc,
1206				    char *argv[])
1207{
1208	return wpa_ctrl_command(ctrl, "SCAN_RESULTS");
1209}
1210
1211
1212static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
1213{
1214	char cmd[64];
1215	int res;
1216
1217	if (argc != 1) {
1218		printf("Invalid BSS command: need one argument (index or "
1219		       "BSSID)\n");
1220		return -1;
1221	}
1222
1223	res = os_snprintf(cmd, sizeof(cmd), "BSS %s", argv[0]);
1224	if (res < 0 || (size_t) res >= sizeof(cmd))
1225		return -1;
1226	cmd[sizeof(cmd) - 1] = '\0';
1227
1228	return wpa_ctrl_command(ctrl, cmd);
1229}
1230
1231
1232static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
1233				      char *argv[])
1234{
1235	char cmd[64];
1236	int res;
1237
1238	if (argc < 1 || argc > 2) {
1239		printf("Invalid GET_CAPABILITY command: need either one or "
1240		       "two arguments\n");
1241		return -1;
1242	}
1243
1244	if ((argc == 2) && os_strcmp(argv[1], "strict") != 0) {
1245		printf("Invalid GET_CAPABILITY command: second argument, "
1246		       "if any, must be 'strict'\n");
1247		return -1;
1248	}
1249
1250	res = os_snprintf(cmd, sizeof(cmd), "GET_CAPABILITY %s%s", argv[0],
1251			  (argc == 2) ? " strict" : "");
1252	if (res < 0 || (size_t) res >= sizeof(cmd))
1253		return -1;
1254	cmd[sizeof(cmd) - 1] = '\0';
1255
1256	return wpa_ctrl_command(ctrl, cmd);
1257}
1258
1259
1260static int wpa_cli_list_interfaces(struct wpa_ctrl *ctrl)
1261{
1262	printf("Available interfaces:\n");
1263	return wpa_ctrl_command(ctrl, "INTERFACES");
1264}
1265
1266
1267static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[])
1268{
1269	if (argc < 1) {
1270		wpa_cli_list_interfaces(ctrl);
1271		return 0;
1272	}
1273
1274	wpa_cli_close_connection();
1275	os_free(ctrl_ifname);
1276	ctrl_ifname = os_strdup(argv[0]);
1277
1278	if (wpa_cli_open_connection(ctrl_ifname, 1)) {
1279		printf("Connected to interface '%s.\n", ctrl_ifname);
1280	} else {
1281		printf("Could not connect to interface '%s' - re-trying\n",
1282		       ctrl_ifname);
1283	}
1284	return 0;
1285}
1286
1287
1288static int wpa_cli_cmd_reconfigure(struct wpa_ctrl *ctrl, int argc,
1289				   char *argv[])
1290{
1291	return wpa_ctrl_command(ctrl, "RECONFIGURE");
1292}
1293
1294
1295static int wpa_cli_cmd_terminate(struct wpa_ctrl *ctrl, int argc,
1296				 char *argv[])
1297{
1298	return wpa_ctrl_command(ctrl, "TERMINATE");
1299}
1300
1301
1302static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc,
1303				     char *argv[])
1304{
1305	char cmd[256];
1306	int res;
1307
1308	if (argc < 1) {
1309		printf("Invalid INTERFACE_ADD command: needs at least one "
1310		       "argument (interface name)\n"
1311		       "All arguments: ifname confname driver ctrl_interface "
1312		       "driver_param bridge_name\n");
1313		return -1;
1314	}
1315
1316	/*
1317	 * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
1318	 * <driver_param>TAB<bridge_name>
1319	 */
1320	res = os_snprintf(cmd, sizeof(cmd),
1321			  "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s",
1322			  argv[0],
1323			  argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "",
1324			  argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "",
1325			  argc > 5 ? argv[5] : "");
1326	if (res < 0 || (size_t) res >= sizeof(cmd))
1327		return -1;
1328	cmd[sizeof(cmd) - 1] = '\0';
1329	return wpa_ctrl_command(ctrl, cmd);
1330}
1331
1332
1333static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc,
1334					char *argv[])
1335{
1336	char cmd[128];
1337	int res;
1338
1339	if (argc != 1) {
1340		printf("Invalid INTERFACE_REMOVE command: needs one argument "
1341		       "(interface name)\n");
1342		return -1;
1343	}
1344
1345	res = os_snprintf(cmd, sizeof(cmd), "INTERFACE_REMOVE %s", argv[0]);
1346	if (res < 0 || (size_t) res >= sizeof(cmd))
1347		return -1;
1348	cmd[sizeof(cmd) - 1] = '\0';
1349	return wpa_ctrl_command(ctrl, cmd);
1350}
1351
1352
1353static int wpa_cli_cmd_interface_list(struct wpa_ctrl *ctrl, int argc,
1354				      char *argv[])
1355{
1356	return wpa_ctrl_command(ctrl, "INTERFACE_LIST");
1357}
1358
1359
1360#ifdef CONFIG_AP
1361static int wpa_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
1362{
1363	char buf[64];
1364	if (argc != 1) {
1365		printf("Invalid 'sta' command - exactly one argument, STA "
1366		       "address, is required.\n");
1367		return -1;
1368	}
1369	os_snprintf(buf, sizeof(buf), "STA %s", argv[0]);
1370	return wpa_ctrl_command(ctrl, buf);
1371}
1372
1373
1374static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
1375				char *addr, size_t addr_len)
1376{
1377	char buf[4096], *pos;
1378	size_t len;
1379	int ret;
1380
1381	if (ctrl_conn == NULL) {
1382		printf("Not connected to hostapd - command dropped.\n");
1383		return -1;
1384	}
1385	len = sizeof(buf) - 1;
1386	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
1387			       wpa_cli_msg_cb);
1388	if (ret == -2) {
1389		printf("'%s' command timed out.\n", cmd);
1390		return -2;
1391	} else if (ret < 0) {
1392		printf("'%s' command failed.\n", cmd);
1393		return -1;
1394	}
1395
1396	buf[len] = '\0';
1397	if (memcmp(buf, "FAIL", 4) == 0)
1398		return -1;
1399	printf("%s", buf);
1400
1401	pos = buf;
1402	while (*pos != '\0' && *pos != '\n')
1403		pos++;
1404	*pos = '\0';
1405	os_strlcpy(addr, buf, addr_len);
1406	return 0;
1407}
1408
1409
1410static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
1411{
1412	char addr[32], cmd[64];
1413
1414	if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
1415		return 0;
1416	do {
1417		os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
1418	} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
1419
1420	return -1;
1421}
1422#endif /* CONFIG_AP */
1423
1424
1425static int wpa_cli_cmd_suspend(struct wpa_ctrl *ctrl, int argc, char *argv[])
1426{
1427	return wpa_ctrl_command(ctrl, "SUSPEND");
1428}
1429
1430
1431static int wpa_cli_cmd_resume(struct wpa_ctrl *ctrl, int argc, char *argv[])
1432{
1433	return wpa_ctrl_command(ctrl, "RESUME");
1434}
1435
1436
1437static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[])
1438{
1439	return wpa_ctrl_command(ctrl, "DROP_SA");
1440}
1441
1442
1443static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
1444{
1445	char cmd[128];
1446	int res;
1447
1448	if (argc != 1) {
1449		printf("Invalid ROAM command: needs one argument "
1450		       "(target AP's BSSID)\n");
1451		return -1;
1452	}
1453
1454	res = os_snprintf(cmd, sizeof(cmd), "ROAM %s", argv[0]);
1455	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
1456		printf("Too long ROAM command.\n");
1457		return -1;
1458	}
1459	return wpa_ctrl_command(ctrl, cmd);
1460}
1461
1462
1463enum wpa_cli_cmd_flags {
1464	cli_cmd_flag_none		= 0x00,
1465	cli_cmd_flag_sensitive		= 0x01
1466};
1467
1468struct wpa_cli_cmd {
1469	const char *cmd;
1470	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
1471	enum wpa_cli_cmd_flags flags;
1472	const char *usage;
1473};
1474
1475static struct wpa_cli_cmd wpa_cli_commands[] = {
1476	{ "status", wpa_cli_cmd_status,
1477	  cli_cmd_flag_none,
1478	  "[verbose] = get current WPA/EAPOL/EAP status" },
1479	{ "ping", wpa_cli_cmd_ping,
1480	  cli_cmd_flag_none,
1481	  "= pings wpa_supplicant" },
1482	{ "mib", wpa_cli_cmd_mib,
1483	  cli_cmd_flag_none,
1484	  "= get MIB variables (dot1x, dot11)" },
1485	{ "help", wpa_cli_cmd_help,
1486	  cli_cmd_flag_none,
1487	  "= show this usage help" },
1488	{ "interface", wpa_cli_cmd_interface,
1489	  cli_cmd_flag_none,
1490	  "[ifname] = show interfaces/select interface" },
1491	{ "level", wpa_cli_cmd_level,
1492	  cli_cmd_flag_none,
1493	  "<debug level> = change debug level" },
1494	{ "license", wpa_cli_cmd_license,
1495	  cli_cmd_flag_none,
1496	  "= show full wpa_cli license" },
1497	{ "quit", wpa_cli_cmd_quit,
1498	  cli_cmd_flag_none,
1499	  "= exit wpa_cli" },
1500	{ "set", wpa_cli_cmd_set,
1501	  cli_cmd_flag_none,
1502	  "= set variables (shows list of variables when run without "
1503	  "arguments)" },
1504	{ "logon", wpa_cli_cmd_logon,
1505	  cli_cmd_flag_none,
1506	  "= IEEE 802.1X EAPOL state machine logon" },
1507	{ "logoff", wpa_cli_cmd_logoff,
1508	  cli_cmd_flag_none,
1509	  "= IEEE 802.1X EAPOL state machine logoff" },
1510	{ "pmksa", wpa_cli_cmd_pmksa,
1511	  cli_cmd_flag_none,
1512	  "= show PMKSA cache" },
1513	{ "reassociate", wpa_cli_cmd_reassociate,
1514	  cli_cmd_flag_none,
1515	  "= force reassociation" },
1516	{ "preauthenticate", wpa_cli_cmd_preauthenticate,
1517	  cli_cmd_flag_none,
1518	  "<BSSID> = force preauthentication" },
1519	{ "identity", wpa_cli_cmd_identity,
1520	  cli_cmd_flag_none,
1521	  "<network id> <identity> = configure identity for an SSID" },
1522	{ "password", wpa_cli_cmd_password,
1523	  cli_cmd_flag_sensitive,
1524	  "<network id> <password> = configure password for an SSID" },
1525	{ "new_password", wpa_cli_cmd_new_password,
1526	  cli_cmd_flag_sensitive,
1527	  "<network id> <password> = change password for an SSID" },
1528	{ "pin", wpa_cli_cmd_pin,
1529	  cli_cmd_flag_sensitive,
1530	  "<network id> <pin> = configure pin for an SSID" },
1531	{ "otp", wpa_cli_cmd_otp,
1532	  cli_cmd_flag_sensitive,
1533	  "<network id> <password> = configure one-time-password for an SSID"
1534	},
1535	{ "passphrase", wpa_cli_cmd_passphrase,
1536	  cli_cmd_flag_sensitive,
1537	  "<network id> <passphrase> = configure private key passphrase\n"
1538	  "  for an SSID" },
1539	{ "bssid", wpa_cli_cmd_bssid,
1540	  cli_cmd_flag_none,
1541	  "<network id> <BSSID> = set preferred BSSID for an SSID" },
1542	{ "list_networks", wpa_cli_cmd_list_networks,
1543	  cli_cmd_flag_none,
1544	  "= list configured networks" },
1545	{ "select_network", wpa_cli_cmd_select_network,
1546	  cli_cmd_flag_none,
1547	  "<network id> = select a network (disable others)" },
1548	{ "enable_network", wpa_cli_cmd_enable_network,
1549	  cli_cmd_flag_none,
1550	  "<network id> = enable a network" },
1551	{ "disable_network", wpa_cli_cmd_disable_network,
1552	  cli_cmd_flag_none,
1553	  "<network id> = disable a network" },
1554	{ "add_network", wpa_cli_cmd_add_network,
1555	  cli_cmd_flag_none,
1556	  "= add a network" },
1557	{ "remove_network", wpa_cli_cmd_remove_network,
1558	  cli_cmd_flag_none,
1559	  "<network id> = remove a network" },
1560	{ "set_network", wpa_cli_cmd_set_network,
1561	  cli_cmd_flag_sensitive,
1562	  "<network id> <variable> <value> = set network variables (shows\n"
1563	  "  list of variables when run without arguments)" },
1564	{ "get_network", wpa_cli_cmd_get_network,
1565	  cli_cmd_flag_none,
1566	  "<network id> <variable> = get network variables" },
1567	{ "save_config", wpa_cli_cmd_save_config,
1568	  cli_cmd_flag_none,
1569	  "= save the current configuration" },
1570	{ "disconnect", wpa_cli_cmd_disconnect,
1571	  cli_cmd_flag_none,
1572	  "= disconnect and wait for reassociate/reconnect command before\n"
1573	  "  connecting" },
1574	{ "reconnect", wpa_cli_cmd_reconnect,
1575	  cli_cmd_flag_none,
1576	  "= like reassociate, but only takes effect if already disconnected"
1577	},
1578	{ "scan", wpa_cli_cmd_scan,
1579	  cli_cmd_flag_none,
1580	  "= request new BSS scan" },
1581	{ "scan_results", wpa_cli_cmd_scan_results,
1582	  cli_cmd_flag_none,
1583	  "= get latest scan results" },
1584	{ "bss", wpa_cli_cmd_bss,
1585	  cli_cmd_flag_none,
1586	  "<<idx> | <bssid>> = get detailed scan result info" },
1587	{ "get_capability", wpa_cli_cmd_get_capability,
1588	  cli_cmd_flag_none,
1589	  "<eap/pairwise/group/key_mgmt/proto/auth_alg> = get capabilies" },
1590	{ "reconfigure", wpa_cli_cmd_reconfigure,
1591	  cli_cmd_flag_none,
1592	  "= force wpa_supplicant to re-read its configuration file" },
1593	{ "terminate", wpa_cli_cmd_terminate,
1594	  cli_cmd_flag_none,
1595	  "= terminate wpa_supplicant" },
1596	{ "interface_add", wpa_cli_cmd_interface_add,
1597	  cli_cmd_flag_none,
1598	  "<ifname> <confname> <driver> <ctrl_interface> <driver_param>\n"
1599	  "  <bridge_name> = adds new interface, all parameters but <ifname>\n"
1600	  "  are optional" },
1601	{ "interface_remove", wpa_cli_cmd_interface_remove,
1602	  cli_cmd_flag_none,
1603	  "<ifname> = removes the interface" },
1604	{ "interface_list", wpa_cli_cmd_interface_list,
1605	  cli_cmd_flag_none,
1606	  "= list available interfaces" },
1607	{ "ap_scan", wpa_cli_cmd_ap_scan,
1608	  cli_cmd_flag_none,
1609	  "<value> = set ap_scan parameter" },
1610	{ "stkstart", wpa_cli_cmd_stkstart,
1611	  cli_cmd_flag_none,
1612	  "<addr> = request STK negotiation with <addr>" },
1613	{ "ft_ds", wpa_cli_cmd_ft_ds,
1614	  cli_cmd_flag_none,
1615	  "<addr> = request over-the-DS FT with <addr>" },
1616	{ "wps_pbc", wpa_cli_cmd_wps_pbc,
1617	  cli_cmd_flag_none,
1618	  "[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" },
1619	{ "wps_pin", wpa_cli_cmd_wps_pin,
1620	  cli_cmd_flag_sensitive,
1621	  "<BSSID> [PIN] = start WPS PIN method (returns PIN, if not "
1622	  "hardcoded)" },
1623#ifdef CONFIG_WPS_OOB
1624	{ "wps_oob", wpa_cli_cmd_wps_oob,
1625	  cli_cmd_flag_sensitive,
1626	  "<DEV_TYPE> <PATH> <METHOD> [DEV_NAME] = start WPS OOB" },
1627#endif /* CONFIG_WPS_OOB */
1628	{ "wps_reg", wpa_cli_cmd_wps_reg,
1629	  cli_cmd_flag_sensitive,
1630	  "<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
1631	{ "wps_er_start", wpa_cli_cmd_wps_er_start,
1632	  cli_cmd_flag_none,
1633	  "= start Wi-Fi Protected Setup External Registrar" },
1634	{ "wps_er_stop", wpa_cli_cmd_wps_er_stop,
1635	  cli_cmd_flag_none,
1636	  "= stop Wi-Fi Protected Setup External Registrar" },
1637	{ "wps_er_pin", wpa_cli_cmd_wps_er_pin,
1638	  cli_cmd_flag_sensitive,
1639	  "<UUID> <PIN> = add an Enrollee PIN to External Registrar" },
1640	{ "wps_er_pbc", wpa_cli_cmd_wps_er_pbc,
1641	  cli_cmd_flag_none,
1642	  "<UUID> = accept an Enrollee PBC using External Registrar" },
1643	{ "wps_er_learn", wpa_cli_cmd_wps_er_learn,
1644	  cli_cmd_flag_sensitive,
1645	  "<UUID> <PIN> = learn AP configuration" },
1646	{ "ibss_rsn", wpa_cli_cmd_ibss_rsn,
1647	  cli_cmd_flag_none,
1648	  "<addr> = request RSN authentication with <addr> in IBSS" },
1649#ifdef CONFIG_AP
1650	{ "sta", wpa_cli_cmd_sta,
1651	  cli_cmd_flag_none,
1652	  "<addr> = get information about an associated station (AP)" },
1653	{ "all_sta", wpa_cli_cmd_all_sta,
1654	  cli_cmd_flag_none,
1655	  "= get information about all associated stations (AP)" },
1656#endif /* CONFIG_AP */
1657	{ "suspend", wpa_cli_cmd_suspend, cli_cmd_flag_none,
1658	  "= notification of suspend/hibernate" },
1659	{ "resume", wpa_cli_cmd_resume, cli_cmd_flag_none,
1660	  "= notification of resume/thaw" },
1661	{ "drop_sa", wpa_cli_cmd_drop_sa, cli_cmd_flag_none,
1662	  "= drop SA without deauth/disassoc (test command)" },
1663	{ "roam", wpa_cli_cmd_roam,
1664	  cli_cmd_flag_none,
1665	  "<addr> = roam to the specified BSS" },
1666	{ NULL, NULL, cli_cmd_flag_none, NULL }
1667};
1668
1669
1670/*
1671 * Prints command usage, lines are padded with the specified string.
1672 */
1673static void print_cmd_help(struct wpa_cli_cmd *cmd, const char *pad)
1674{
1675	char c;
1676	size_t n;
1677
1678	printf("%s%s ", pad, cmd->cmd);
1679	for (n = 0; (c = cmd->usage[n]); n++) {
1680		printf("%c", c);
1681		if (c == '\n')
1682			printf("%s", pad);
1683	}
1684	printf("\n");
1685}
1686
1687
1688static void print_help(void)
1689{
1690	int n;
1691	printf("commands:\n");
1692	for (n = 0; wpa_cli_commands[n].cmd; n++)
1693		print_cmd_help(&wpa_cli_commands[n], "  ");
1694}
1695
1696
1697#ifdef CONFIG_READLINE
1698static int cmd_has_sensitive_data(const char *cmd)
1699{
1700	const char *c, *delim;
1701	int n;
1702	size_t len;
1703
1704	delim = os_strchr(cmd, ' ');
1705	if (delim)
1706		len = delim - cmd;
1707	else
1708		len = os_strlen(cmd);
1709
1710	for (n = 0; (c = wpa_cli_commands[n].cmd); n++) {
1711		if (os_strncasecmp(cmd, c, len) == 0 && len == os_strlen(c))
1712			return (wpa_cli_commands[n].flags &
1713				cli_cmd_flag_sensitive);
1714	}
1715	return 0;
1716}
1717#endif /* CONFIG_READLINE */
1718
1719
1720static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
1721{
1722	struct wpa_cli_cmd *cmd, *match = NULL;
1723	int count;
1724	int ret = 0;
1725
1726	count = 0;
1727	cmd = wpa_cli_commands;
1728	while (cmd->cmd) {
1729		if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0)
1730		{
1731			match = cmd;
1732			if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1733				/* we have an exact match */
1734				count = 1;
1735				break;
1736			}
1737			count++;
1738		}
1739		cmd++;
1740	}
1741
1742	if (count > 1) {
1743		printf("Ambiguous command '%s'; possible commands:", argv[0]);
1744		cmd = wpa_cli_commands;
1745		while (cmd->cmd) {
1746			if (os_strncasecmp(cmd->cmd, argv[0],
1747					   os_strlen(argv[0])) == 0) {
1748				printf(" %s", cmd->cmd);
1749			}
1750			cmd++;
1751		}
1752		printf("\n");
1753		ret = 1;
1754	} else if (count == 0) {
1755		printf("Unknown command '%s'\n", argv[0]);
1756		ret = 1;
1757	} else {
1758		ret = match->handler(ctrl, argc - 1, &argv[1]);
1759	}
1760
1761	return ret;
1762}
1763
1764
1765static int str_match(const char *a, const char *b)
1766{
1767	return os_strncmp(a, b, os_strlen(b)) == 0;
1768}
1769
1770
1771static int wpa_cli_exec(const char *program, const char *arg1,
1772			const char *arg2)
1773{
1774	char *cmd;
1775	size_t len;
1776	int res;
1777	int ret = 0;
1778
1779	len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
1780	cmd = os_malloc(len);
1781	if (cmd == NULL)
1782		return -1;
1783	res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
1784	if (res < 0 || (size_t) res >= len) {
1785		os_free(cmd);
1786		return -1;
1787	}
1788	cmd[len - 1] = '\0';
1789#ifndef _WIN32_WCE
1790	if (system(cmd) < 0)
1791		ret = -1;
1792#endif /* _WIN32_WCE */
1793	os_free(cmd);
1794
1795	return ret;
1796}
1797
1798
1799static void wpa_cli_action_process(const char *msg)
1800{
1801	const char *pos;
1802	char *copy = NULL, *id, *pos2;
1803
1804	pos = msg;
1805	if (*pos == '<') {
1806		/* skip priority */
1807		pos = os_strchr(pos, '>');
1808		if (pos)
1809			pos++;
1810		else
1811			pos = msg;
1812	}
1813
1814	if (str_match(pos, WPA_EVENT_CONNECTED)) {
1815		int new_id = -1;
1816		os_unsetenv("WPA_ID");
1817		os_unsetenv("WPA_ID_STR");
1818		os_unsetenv("WPA_CTRL_DIR");
1819
1820		pos = os_strstr(pos, "[id=");
1821		if (pos)
1822			copy = os_strdup(pos + 4);
1823
1824		if (copy) {
1825			pos2 = id = copy;
1826			while (*pos2 && *pos2 != ' ')
1827				pos2++;
1828			*pos2++ = '\0';
1829			new_id = atoi(id);
1830			os_setenv("WPA_ID", id, 1);
1831			while (*pos2 && *pos2 != '=')
1832				pos2++;
1833			if (*pos2 == '=')
1834				pos2++;
1835			id = pos2;
1836			while (*pos2 && *pos2 != ']')
1837				pos2++;
1838			*pos2 = '\0';
1839			os_setenv("WPA_ID_STR", id, 1);
1840			os_free(copy);
1841		}
1842
1843		os_setenv("WPA_CTRL_DIR", ctrl_iface_dir, 1);
1844
1845		if (!wpa_cli_connected || new_id != wpa_cli_last_id) {
1846			wpa_cli_connected = 1;
1847			wpa_cli_last_id = new_id;
1848			wpa_cli_exec(action_file, ctrl_ifname, "CONNECTED");
1849		}
1850	} else if (str_match(pos, WPA_EVENT_DISCONNECTED)) {
1851		if (wpa_cli_connected) {
1852			wpa_cli_connected = 0;
1853			wpa_cli_exec(action_file, ctrl_ifname, "DISCONNECTED");
1854		}
1855	} else if (str_match(pos, WPA_EVENT_TERMINATING)) {
1856		printf("wpa_supplicant is terminating - stop monitoring\n");
1857		wpa_cli_quit = 1;
1858	}
1859}
1860
1861
1862#ifndef CONFIG_ANSI_C_EXTRA
1863static void wpa_cli_action_cb(char *msg, size_t len)
1864{
1865	wpa_cli_action_process(msg);
1866}
1867#endif /* CONFIG_ANSI_C_EXTRA */
1868
1869
1870static void wpa_cli_reconnect(void)
1871{
1872	wpa_cli_close_connection();
1873	wpa_cli_open_connection(ctrl_ifname, 1);
1874}
1875
1876
1877static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
1878				 int action_monitor)
1879{
1880	int first = 1;
1881	if (ctrl_conn == NULL) {
1882		wpa_cli_reconnect();
1883		return;
1884	}
1885	while (wpa_ctrl_pending(ctrl) > 0) {
1886		char buf[256];
1887		size_t len = sizeof(buf) - 1;
1888		if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
1889			buf[len] = '\0';
1890			if (action_monitor)
1891				wpa_cli_action_process(buf);
1892			else {
1893				if (in_read && first)
1894					printf("\r");
1895				first = 0;
1896				printf("%s\n", buf);
1897#ifdef CONFIG_READLINE
1898				rl_on_new_line();
1899				rl_redisplay();
1900#endif /* CONFIG_READLINE */
1901			}
1902		} else {
1903			printf("Could not read pending message.\n");
1904			break;
1905		}
1906	}
1907
1908	if (wpa_ctrl_pending(ctrl) < 0) {
1909		printf("Connection to wpa_supplicant lost - trying to "
1910		       "reconnect\n");
1911		wpa_cli_reconnect();
1912	}
1913}
1914
1915
1916#ifdef CONFIG_READLINE
1917static char * wpa_cli_cmd_gen(const char *text, int state)
1918{
1919	static int i, len;
1920	const char *cmd;
1921
1922	if (state == 0) {
1923		i = 0;
1924		len = os_strlen(text);
1925	}
1926
1927	while ((cmd = wpa_cli_commands[i].cmd)) {
1928		i++;
1929		if (os_strncasecmp(cmd, text, len) == 0)
1930			return strdup(cmd);
1931	}
1932
1933	return NULL;
1934}
1935
1936
1937static char * wpa_cli_dummy_gen(const char *text, int state)
1938{
1939	int i;
1940
1941	for (i = 0; wpa_cli_commands[i].cmd; i++) {
1942		const char *cmd = wpa_cli_commands[i].cmd;
1943		size_t len = os_strlen(cmd);
1944		if (os_strncasecmp(rl_line_buffer, cmd, len) == 0 &&
1945		    rl_line_buffer[len] == ' ') {
1946			printf("\n%s\n", wpa_cli_commands[i].usage);
1947			rl_on_new_line();
1948			rl_redisplay();
1949			break;
1950		}
1951	}
1952
1953	rl_attempted_completion_over = 1;
1954	return NULL;
1955}
1956
1957
1958static char * wpa_cli_status_gen(const char *text, int state)
1959{
1960	static int i, len;
1961	char *options[] = {
1962		"verbose", NULL
1963	};
1964	char *t;
1965
1966	if (state == 0) {
1967		i = 0;
1968		len = os_strlen(text);
1969	}
1970
1971	while ((t = options[i])) {
1972		i++;
1973		if (os_strncasecmp(t, text, len) == 0)
1974			return strdup(t);
1975	}
1976
1977	rl_attempted_completion_over = 1;
1978	return NULL;
1979}
1980
1981
1982static char ** wpa_cli_completion(const char *text, int start, int end)
1983{
1984	char * (*func)(const char *text, int state);
1985
1986	if (start == 0)
1987		func = wpa_cli_cmd_gen;
1988	else if (os_strncasecmp(rl_line_buffer, "status ", 7) == 0)
1989		func = wpa_cli_status_gen;
1990	else
1991		func = wpa_cli_dummy_gen;
1992	return rl_completion_matches(text, func);
1993}
1994#endif /* CONFIG_READLINE */
1995
1996
1997static void wpa_cli_interactive(void)
1998{
1999#define max_args 10
2000	char cmdbuf[256], *cmd, *argv[max_args], *pos;
2001	int argc;
2002#ifdef CONFIG_READLINE
2003	char *home, *hfile = NULL;
2004#endif /* CONFIG_READLINE */
2005
2006	printf("\nInteractive mode\n\n");
2007
2008#ifdef CONFIG_READLINE
2009	rl_attempted_completion_function = wpa_cli_completion;
2010	home = getenv("HOME");
2011	if (home) {
2012		const char *fname = ".wpa_cli_history";
2013		int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
2014		hfile = os_malloc(hfile_len);
2015		if (hfile) {
2016			int res;
2017			res = os_snprintf(hfile, hfile_len, "%s/%s", home,
2018					  fname);
2019			if (res >= 0 && res < hfile_len) {
2020				hfile[hfile_len - 1] = '\0';
2021				read_history(hfile);
2022				stifle_history(100);
2023			}
2024		}
2025	}
2026#endif /* CONFIG_READLINE */
2027
2028	do {
2029		wpa_cli_recv_pending(mon_conn, 0, 0);
2030#ifndef CONFIG_NATIVE_WINDOWS
2031		alarm(ping_interval);
2032#endif /* CONFIG_NATIVE_WINDOWS */
2033#ifdef CONFIG_WPA_CLI_FORK
2034		if (mon_pid)
2035			kill(mon_pid, SIGUSR1);
2036#endif /* CONFIG_WPA_CLI_FORK */
2037#ifdef CONFIG_READLINE
2038		cmd = readline("> ");
2039		if (cmd && *cmd) {
2040			HIST_ENTRY *h;
2041			while (next_history())
2042				;
2043			h = previous_history();
2044			if (h == NULL || os_strcmp(cmd, h->line) != 0)
2045				add_history(cmd);
2046			next_history();
2047		}
2048#else /* CONFIG_READLINE */
2049		printf("> ");
2050		cmd = fgets(cmdbuf, sizeof(cmdbuf), stdin);
2051#endif /* CONFIG_READLINE */
2052#ifndef CONFIG_NATIVE_WINDOWS
2053		alarm(0);
2054#endif /* CONFIG_NATIVE_WINDOWS */
2055		if (cmd == NULL)
2056			break;
2057		wpa_cli_recv_pending(mon_conn, 0, 0);
2058		pos = cmd;
2059		while (*pos != '\0') {
2060			if (*pos == '\n') {
2061				*pos = '\0';
2062				break;
2063			}
2064			pos++;
2065		}
2066		argc = 0;
2067		pos = cmd;
2068		for (;;) {
2069			while (*pos == ' ')
2070				pos++;
2071			if (*pos == '\0')
2072				break;
2073			argv[argc] = pos;
2074			argc++;
2075			if (argc == max_args)
2076				break;
2077			if (*pos == '"') {
2078				char *pos2 = os_strrchr(pos, '"');
2079				if (pos2)
2080					pos = pos2 + 1;
2081			}
2082			while (*pos != '\0' && *pos != ' ')
2083				pos++;
2084			if (*pos == ' ')
2085				*pos++ = '\0';
2086		}
2087		if (argc)
2088			wpa_request(ctrl_conn, argc, argv);
2089
2090		if (cmd != cmdbuf)
2091			free(cmd);
2092#ifdef CONFIG_WPA_CLI_FORK
2093		if (mon_pid)
2094			kill(mon_pid, SIGUSR2);
2095#endif /* CONFIG_WPA_CLI_FORK */
2096	} while (!wpa_cli_quit);
2097
2098#ifdef CONFIG_READLINE
2099	if (hfile) {
2100		/* Save command history, excluding lines that may contain
2101		 * passwords. */
2102		HIST_ENTRY *h;
2103		history_set_pos(0);
2104		while ((h = current_history())) {
2105			char *p = h->line;
2106			while (*p == ' ' || *p == '\t')
2107				p++;
2108			if (cmd_has_sensitive_data(p)) {
2109				h = remove_history(where_history());
2110				if (h) {
2111					os_free(h->line);
2112					os_free(h->data);
2113					os_free(h);
2114				} else
2115					next_history();
2116			} else
2117				next_history();
2118		}
2119		write_history(hfile);
2120		os_free(hfile);
2121	}
2122#endif /* CONFIG_READLINE */
2123}
2124
2125
2126static void wpa_cli_action(struct wpa_ctrl *ctrl)
2127{
2128#ifdef CONFIG_ANSI_C_EXTRA
2129	/* TODO: ANSI C version(?) */
2130	printf("Action processing not supported in ANSI C build.\n");
2131#else /* CONFIG_ANSI_C_EXTRA */
2132	fd_set rfds;
2133	int fd, res;
2134	struct timeval tv;
2135	char buf[256]; /* note: large enough to fit in unsolicited messages */
2136	size_t len;
2137
2138	fd = wpa_ctrl_get_fd(ctrl);
2139
2140	while (!wpa_cli_quit) {
2141		FD_ZERO(&rfds);
2142		FD_SET(fd, &rfds);
2143		tv.tv_sec = ping_interval;
2144		tv.tv_usec = 0;
2145		res = select(fd + 1, &rfds, NULL, NULL, &tv);
2146		if (res < 0 && errno != EINTR) {
2147			perror("select");
2148			break;
2149		}
2150
2151		if (FD_ISSET(fd, &rfds))
2152			wpa_cli_recv_pending(ctrl, 0, 1);
2153		else {
2154			/* verify that connection is still working */
2155			len = sizeof(buf) - 1;
2156			if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
2157					     wpa_cli_action_cb) < 0 ||
2158			    len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
2159				printf("wpa_supplicant did not reply to PING "
2160				       "command - exiting\n");
2161				break;
2162			}
2163		}
2164	}
2165#endif /* CONFIG_ANSI_C_EXTRA */
2166}
2167
2168
2169static void wpa_cli_cleanup(void)
2170{
2171	wpa_cli_close_connection();
2172	if (pid_file)
2173		os_daemonize_terminate(pid_file);
2174
2175	os_program_deinit();
2176}
2177
2178static void wpa_cli_terminate(int sig)
2179{
2180	wpa_cli_cleanup();
2181	exit(0);
2182}
2183
2184
2185#ifdef CONFIG_WPA_CLI_FORK
2186static void wpa_cli_usr1(int sig)
2187{
2188#ifdef CONFIG_READLINE
2189	rl_on_new_line();
2190	rl_redisplay();
2191#endif /* CONFIG_READLINE */
2192}
2193#endif /* CONFIG_WPA_CLI_FORK */
2194
2195
2196#ifndef CONFIG_NATIVE_WINDOWS
2197static void wpa_cli_alarm(int sig)
2198{
2199	if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
2200		printf("Connection to wpa_supplicant lost - trying to "
2201		       "reconnect\n");
2202		wpa_cli_close_connection();
2203	}
2204	if (!ctrl_conn)
2205		wpa_cli_reconnect();
2206	if (mon_conn)
2207		wpa_cli_recv_pending(mon_conn, 1, 0);
2208	alarm(ping_interval);
2209}
2210#endif /* CONFIG_NATIVE_WINDOWS */
2211
2212
2213static char * wpa_cli_get_default_ifname(void)
2214{
2215	char *ifname = NULL;
2216
2217#ifdef CONFIG_CTRL_IFACE_UNIX
2218	struct dirent *dent;
2219	DIR *dir = opendir(ctrl_iface_dir);
2220	if (!dir)
2221		return NULL;
2222	while ((dent = readdir(dir))) {
2223#ifdef _DIRENT_HAVE_D_TYPE
2224		/*
2225		 * Skip the file if it is not a socket. Also accept
2226		 * DT_UNKNOWN (0) in case the C library or underlying
2227		 * file system does not support d_type.
2228		 */
2229		if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
2230			continue;
2231#endif /* _DIRENT_HAVE_D_TYPE */
2232		if (os_strcmp(dent->d_name, ".") == 0 ||
2233		    os_strcmp(dent->d_name, "..") == 0)
2234			continue;
2235		printf("Selected interface '%s'\n", dent->d_name);
2236		ifname = os_strdup(dent->d_name);
2237		break;
2238	}
2239	closedir(dir);
2240#endif /* CONFIG_CTRL_IFACE_UNIX */
2241
2242#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
2243	char buf[2048], *pos;
2244	size_t len;
2245	struct wpa_ctrl *ctrl;
2246	int ret;
2247
2248	ctrl = wpa_ctrl_open(NULL);
2249	if (ctrl == NULL)
2250		return NULL;
2251
2252	len = sizeof(buf) - 1;
2253	ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL);
2254	if (ret >= 0) {
2255		buf[len] = '\0';
2256		pos = os_strchr(buf, '\n');
2257		if (pos)
2258			*pos = '\0';
2259		ifname = os_strdup(buf);
2260	}
2261	wpa_ctrl_close(ctrl);
2262#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
2263
2264	return ifname;
2265}
2266
2267
2268int main(int argc, char *argv[])
2269{
2270	int warning_displayed = 0;
2271	int c;
2272	int daemonize = 0;
2273	int ret = 0;
2274	const char *global = NULL;
2275
2276	if (os_program_init())
2277		return -1;
2278
2279	for (;;) {
2280		c = getopt(argc, argv, "a:Bg:G:hi:p:P:v");
2281		if (c < 0)
2282			break;
2283		switch (c) {
2284		case 'a':
2285			action_file = optarg;
2286			break;
2287		case 'B':
2288			daemonize = 1;
2289			break;
2290		case 'g':
2291			global = optarg;
2292			break;
2293		case 'G':
2294			ping_interval = atoi(optarg);
2295			break;
2296		case 'h':
2297			usage();
2298			return 0;
2299		case 'v':
2300			printf("%s\n", wpa_cli_version);
2301			return 0;
2302		case 'i':
2303			os_free(ctrl_ifname);
2304			ctrl_ifname = os_strdup(optarg);
2305			break;
2306		case 'p':
2307			ctrl_iface_dir = optarg;
2308			break;
2309		case 'P':
2310			pid_file = optarg;
2311			break;
2312		default:
2313			usage();
2314			return -1;
2315		}
2316	}
2317
2318	interactive = (argc == optind) && (action_file == NULL);
2319
2320	if (interactive)
2321		printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license);
2322
2323	if (global) {
2324#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
2325		ctrl_conn = wpa_ctrl_open(NULL);
2326#else /* CONFIG_CTRL_IFACE_NAMED_PIPE */
2327		ctrl_conn = wpa_ctrl_open(global);
2328#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
2329		if (ctrl_conn == NULL) {
2330			perror("Failed to connect to wpa_supplicant - "
2331			       "wpa_ctrl_open");
2332			return -1;
2333		}
2334	}
2335
2336#ifndef _WIN32_WCE
2337	signal(SIGINT, wpa_cli_terminate);
2338	signal(SIGTERM, wpa_cli_terminate);
2339#endif /* _WIN32_WCE */
2340#ifndef CONFIG_NATIVE_WINDOWS
2341	signal(SIGALRM, wpa_cli_alarm);
2342#endif /* CONFIG_NATIVE_WINDOWS */
2343#ifdef CONFIG_WPA_CLI_FORK
2344	signal(SIGUSR1, wpa_cli_usr1);
2345#endif /* CONFIG_WPA_CLI_FORK */
2346
2347	if (ctrl_ifname == NULL)
2348		ctrl_ifname = wpa_cli_get_default_ifname();
2349
2350	if (interactive) {
2351		for (; !global;) {
2352			if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
2353				if (warning_displayed)
2354					printf("Connection established.\n");
2355				break;
2356			}
2357
2358			if (!warning_displayed) {
2359				printf("Could not connect to wpa_supplicant - "
2360				       "re-trying\n");
2361				warning_displayed = 1;
2362			}
2363			os_sleep(1, 0);
2364			continue;
2365		}
2366	} else {
2367		if (!global &&
2368		    wpa_cli_open_connection(ctrl_ifname, 0) < 0) {
2369			perror("Failed to connect to wpa_supplicant - "
2370			       "wpa_ctrl_open");
2371			return -1;
2372		}
2373
2374		if (action_file) {
2375			if (wpa_ctrl_attach(ctrl_conn) == 0) {
2376				wpa_cli_attached = 1;
2377			} else {
2378				printf("Warning: Failed to attach to "
2379				       "wpa_supplicant.\n");
2380				return -1;
2381			}
2382		}
2383	}
2384
2385	if (daemonize && os_daemonize(pid_file))
2386		return -1;
2387
2388	if (interactive)
2389		wpa_cli_interactive();
2390	else if (action_file)
2391		wpa_cli_action(ctrl_conn);
2392	else
2393		ret = wpa_request(ctrl_conn, argc - optind, &argv[optind]);
2394
2395	os_free(ctrl_ifname);
2396	wpa_cli_cleanup();
2397
2398	return ret;
2399}
2400
2401#else /* CONFIG_CTRL_IFACE */
2402int main(int argc, char *argv[])
2403{
2404	printf("CONFIG_CTRL_IFACE not defined - wpa_cli disabled\n");
2405	return -1;
2406}
2407#endif /* CONFIG_CTRL_IFACE */
2408