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