1/*
2 * hostapd - command line interface for hostapd daemon
3 * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "includes.h"
10#include <dirent.h>
11
12#include "common/wpa_ctrl.h"
13#include "utils/common.h"
14#include "utils/eloop.h"
15#include "utils/edit.h"
16#include "common/version.h"
17
18
19static const char *hostapd_cli_version =
20"hostapd_cli v" VERSION_STR "\n"
21"Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> and contributors";
22
23
24static const char *hostapd_cli_license =
25"This software may be distributed under the terms of the BSD license.\n"
26"See README for more details.\n";
27
28static const char *hostapd_cli_full_license =
29"This software may be distributed under the terms of the BSD license.\n"
30"\n"
31"Redistribution and use in source and binary forms, with or without\n"
32"modification, are permitted provided that the following conditions are\n"
33"met:\n"
34"\n"
35"1. Redistributions of source code must retain the above copyright\n"
36"   notice, this list of conditions and the following disclaimer.\n"
37"\n"
38"2. Redistributions in binary form must reproduce the above copyright\n"
39"   notice, this list of conditions and the following disclaimer in the\n"
40"   documentation and/or other materials provided with the distribution.\n"
41"\n"
42"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
43"   names of its contributors may be used to endorse or promote products\n"
44"   derived from this software without specific prior written permission.\n"
45"\n"
46"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
47"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
48"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
49"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
50"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
51"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
52"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
53"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
54"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
55"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
56"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
57"\n";
58
59static const char *commands_help =
60"Commands:\n"
61"   mib                  get MIB variables (dot1x, dot11, radius)\n"
62"   sta <addr>           get MIB variables for one station\n"
63"   all_sta              get MIB variables for all stations\n"
64"   new_sta <addr>       add a new station\n"
65"   deauthenticate <addr>  deauthenticate a station\n"
66"   disassociate <addr>  disassociate a station\n"
67#ifdef CONFIG_IEEE80211W
68"   sa_query <addr>      send SA Query to a station\n"
69#endif /* CONFIG_IEEE80211W */
70#ifdef CONFIG_WPS
71"   wps_pin <uuid> <pin> [timeout] [addr]  add WPS Enrollee PIN\n"
72"   wps_check_pin <PIN>  verify PIN checksum\n"
73"   wps_pbc              indicate button pushed to initiate PBC\n"
74"   wps_cancel           cancel the pending WPS operation\n"
75#ifdef CONFIG_WPS_NFC
76"   wps_nfc_tag_read <hexdump>  report read NFC tag with WPS data\n"
77"   wps_nfc_config_token <WPS/NDEF>  build NFC configuration token\n"
78"   wps_nfc_token <WPS/NDEF/enable/disable>  manager NFC password token\n"
79#endif /* CONFIG_WPS_NFC */
80"   wps_ap_pin <cmd> [params..]  enable/disable AP PIN\n"
81"   wps_config <SSID> <auth> <encr> <key>  configure AP\n"
82"   wps_get_status       show current WPS status\n"
83#endif /* CONFIG_WPS */
84"   get_config           show current configuration\n"
85"   help                 show this usage help\n"
86"   interface [ifname]   show interfaces/select interface\n"
87"   level <debug level>  change debug level\n"
88"   license              show full hostapd_cli license\n"
89"   quit                 exit hostapd_cli\n";
90
91static struct wpa_ctrl *ctrl_conn;
92static int hostapd_cli_quit = 0;
93static int hostapd_cli_attached = 0;
94
95#ifndef CONFIG_CTRL_IFACE_DIR
96#define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd"
97#endif /* CONFIG_CTRL_IFACE_DIR */
98static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
99
100static char *ctrl_ifname = NULL;
101static const char *pid_file = NULL;
102static const char *action_file = NULL;
103static int ping_interval = 5;
104static int interactive = 0;
105
106
107static void usage(void)
108{
109	fprintf(stderr, "%s\n", hostapd_cli_version);
110	fprintf(stderr,
111		"\n"
112		"usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
113		"[-a<path>] \\\n"
114		"                   [-G<ping interval>] [command..]\n"
115		"\n"
116		"Options:\n"
117		"   -h           help (show this usage text)\n"
118		"   -v           shown version information\n"
119		"   -p<path>     path to find control sockets (default: "
120		"/var/run/hostapd)\n"
121		"   -a<file>     run in daemon mode executing the action file "
122		"based on events\n"
123		"                from hostapd\n"
124		"   -B           run a daemon in the background\n"
125		"   -i<ifname>   Interface to listen on (default: first "
126		"interface found in the\n"
127		"                socket path)\n\n"
128		"%s",
129		commands_help);
130}
131
132
133static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
134{
135	char *cfile;
136	int flen;
137
138	if (ifname == NULL)
139		return NULL;
140
141	flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
142	cfile = malloc(flen);
143	if (cfile == NULL)
144		return NULL;
145	snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
146
147	ctrl_conn = wpa_ctrl_open(cfile);
148	free(cfile);
149	return ctrl_conn;
150}
151
152
153static void hostapd_cli_close_connection(void)
154{
155	if (ctrl_conn == NULL)
156		return;
157
158	if (hostapd_cli_attached) {
159		wpa_ctrl_detach(ctrl_conn);
160		hostapd_cli_attached = 0;
161	}
162	wpa_ctrl_close(ctrl_conn);
163	ctrl_conn = NULL;
164}
165
166
167static void hostapd_cli_msg_cb(char *msg, size_t len)
168{
169	printf("%s\n", msg);
170}
171
172
173static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
174{
175	char buf[4096];
176	size_t len;
177	int ret;
178
179	if (ctrl_conn == NULL) {
180		printf("Not connected to hostapd - command dropped.\n");
181		return -1;
182	}
183	len = sizeof(buf) - 1;
184	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
185			       hostapd_cli_msg_cb);
186	if (ret == -2) {
187		printf("'%s' command timed out.\n", cmd);
188		return -2;
189	} else if (ret < 0) {
190		printf("'%s' command failed.\n", cmd);
191		return -1;
192	}
193	if (print) {
194		buf[len] = '\0';
195		printf("%s", buf);
196	}
197	return 0;
198}
199
200
201static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
202{
203	return _wpa_ctrl_command(ctrl, cmd, 1);
204}
205
206
207static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
208{
209	return wpa_ctrl_command(ctrl, "PING");
210}
211
212
213static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
214{
215	return wpa_ctrl_command(ctrl, "RELOG");
216}
217
218
219static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
220{
221	return wpa_ctrl_command(ctrl, "MIB");
222}
223
224
225static int hostapd_cli_exec(const char *program, const char *arg1,
226			    const char *arg2)
227{
228	char *cmd;
229	size_t len;
230	int res;
231	int ret = 0;
232
233	len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
234	cmd = os_malloc(len);
235	if (cmd == NULL)
236		return -1;
237	res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
238	if (res < 0 || (size_t) res >= len) {
239		os_free(cmd);
240		return -1;
241	}
242	cmd[len - 1] = '\0';
243#ifndef _WIN32_WCE
244	if (system(cmd) < 0)
245		ret = -1;
246#endif /* _WIN32_WCE */
247	os_free(cmd);
248
249	return ret;
250}
251
252
253static void hostapd_cli_action_process(char *msg, size_t len)
254{
255	const char *pos;
256
257	pos = msg;
258	if (*pos == '<') {
259		pos = os_strchr(pos, '>');
260		if (pos)
261			pos++;
262		else
263			pos = msg;
264	}
265
266	hostapd_cli_exec(action_file, ctrl_ifname, pos);
267}
268
269
270static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
271{
272	char buf[64];
273	if (argc != 1) {
274		printf("Invalid 'sta' command - exactly one argument, STA "
275		       "address, is required.\n");
276		return -1;
277	}
278	snprintf(buf, sizeof(buf), "STA %s", argv[0]);
279	return wpa_ctrl_command(ctrl, buf);
280}
281
282
283static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
284				   char *argv[])
285{
286	char buf[64];
287	if (argc != 1) {
288		printf("Invalid 'new_sta' command - exactly one argument, STA "
289		       "address, is required.\n");
290		return -1;
291	}
292	snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
293	return wpa_ctrl_command(ctrl, buf);
294}
295
296
297static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
298					  char *argv[])
299{
300	char buf[64];
301	if (argc < 1) {
302		printf("Invalid 'deauthenticate' command - exactly one "
303		       "argument, STA address, is required.\n");
304		return -1;
305	}
306	if (argc > 1)
307		os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
308			    argv[0], argv[1]);
309	else
310		os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
311	return wpa_ctrl_command(ctrl, buf);
312}
313
314
315static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
316					char *argv[])
317{
318	char buf[64];
319	if (argc < 1) {
320		printf("Invalid 'disassociate' command - exactly one "
321		       "argument, STA address, is required.\n");
322		return -1;
323	}
324	if (argc > 1)
325		os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
326			    argv[0], argv[1]);
327	else
328		os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
329	return wpa_ctrl_command(ctrl, buf);
330}
331
332
333#ifdef CONFIG_IEEE80211W
334static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
335				    char *argv[])
336{
337	char buf[64];
338	if (argc != 1) {
339		printf("Invalid 'sa_query' command - exactly one argument, "
340		       "STA address, is required.\n");
341		return -1;
342	}
343	snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
344	return wpa_ctrl_command(ctrl, buf);
345}
346#endif /* CONFIG_IEEE80211W */
347
348
349#ifdef CONFIG_WPS
350static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
351				   char *argv[])
352{
353	char buf[256];
354	if (argc < 2) {
355		printf("Invalid 'wps_pin' command - at least two arguments, "
356		       "UUID and PIN, are required.\n");
357		return -1;
358	}
359	if (argc > 3)
360		snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
361			 argv[0], argv[1], argv[2], argv[3]);
362	else if (argc > 2)
363		snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
364			 argv[0], argv[1], argv[2]);
365	else
366		snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
367	return wpa_ctrl_command(ctrl, buf);
368}
369
370
371static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
372					 char *argv[])
373{
374	char cmd[256];
375	int res;
376
377	if (argc != 1 && argc != 2) {
378		printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
379		       "- PIN to be verified\n");
380		return -1;
381	}
382
383	if (argc == 2)
384		res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
385				  argv[0], argv[1]);
386	else
387		res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
388				  argv[0]);
389	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
390		printf("Too long WPS_CHECK_PIN command.\n");
391		return -1;
392	}
393	return wpa_ctrl_command(ctrl, cmd);
394}
395
396
397static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
398				   char *argv[])
399{
400	return wpa_ctrl_command(ctrl, "WPS_PBC");
401}
402
403
404static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
405				      char *argv[])
406{
407	return wpa_ctrl_command(ctrl, "WPS_CANCEL");
408}
409
410
411#ifdef CONFIG_WPS_NFC
412static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
413					    char *argv[])
414{
415	int ret;
416	char *buf;
417	size_t buflen;
418
419	if (argc != 1) {
420		printf("Invalid 'wps_nfc_tag_read' command - one argument "
421		       "is required.\n");
422		return -1;
423	}
424
425	buflen = 18 + os_strlen(argv[0]);
426	buf = os_malloc(buflen);
427	if (buf == NULL)
428		return -1;
429	os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
430
431	ret = wpa_ctrl_command(ctrl, buf);
432	os_free(buf);
433
434	return ret;
435}
436
437
438static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
439						int argc, char *argv[])
440{
441	char cmd[64];
442	int res;
443
444	if (argc != 1) {
445		printf("Invalid 'wps_nfc_config_token' command - one argument "
446		       "is required.\n");
447		return -1;
448	}
449
450	res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
451			  argv[0]);
452	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
453		printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
454		return -1;
455	}
456	return wpa_ctrl_command(ctrl, cmd);
457}
458
459
460static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
461					 int argc, char *argv[])
462{
463	char cmd[64];
464	int res;
465
466	if (argc != 1) {
467		printf("Invalid 'wps_nfc_token' command - one argument is "
468		       "required.\n");
469		return -1;
470	}
471
472	res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
473	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
474		printf("Too long WPS_NFC_TOKEN command.\n");
475		return -1;
476	}
477	return wpa_ctrl_command(ctrl, cmd);
478}
479
480
481static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
482						int argc, char *argv[])
483{
484	char cmd[64];
485	int res;
486
487	if (argc != 2) {
488		printf("Invalid 'nfc_get_handover_sel' command - two arguments "
489		       "are required.\n");
490		return -1;
491	}
492
493	res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
494			  argv[0], argv[1]);
495	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
496		printf("Too long NFC_GET_HANDOVER_SEL command.\n");
497		return -1;
498	}
499	return wpa_ctrl_command(ctrl, cmd);
500}
501
502#endif /* CONFIG_WPS_NFC */
503
504
505static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
506				      char *argv[])
507{
508	char buf[64];
509	if (argc < 1) {
510		printf("Invalid 'wps_ap_pin' command - at least one argument "
511		       "is required.\n");
512		return -1;
513	}
514	if (argc > 2)
515		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
516			 argv[0], argv[1], argv[2]);
517	else if (argc > 1)
518		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
519			 argv[0], argv[1]);
520	else
521		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
522	return wpa_ctrl_command(ctrl, buf);
523}
524
525
526static int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc,
527					  char *argv[])
528{
529	return wpa_ctrl_command(ctrl, "WPS_GET_STATUS");
530}
531
532
533static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
534				      char *argv[])
535{
536	char buf[256];
537	char ssid_hex[2 * 32 + 1];
538	char key_hex[2 * 64 + 1];
539	int i;
540
541	if (argc < 1) {
542		printf("Invalid 'wps_config' command - at least two arguments "
543		       "are required.\n");
544		return -1;
545	}
546
547	ssid_hex[0] = '\0';
548	for (i = 0; i < 32; i++) {
549		if (argv[0][i] == '\0')
550			break;
551		os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
552	}
553
554	key_hex[0] = '\0';
555	if (argc > 3) {
556		for (i = 0; i < 64; i++) {
557			if (argv[3][i] == '\0')
558				break;
559			os_snprintf(&key_hex[i * 2], 3, "%02x",
560				    argv[3][i]);
561		}
562	}
563
564	if (argc > 3)
565		snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
566			 ssid_hex, argv[1], argv[2], key_hex);
567	else if (argc > 2)
568		snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
569			 ssid_hex, argv[1], argv[2]);
570	else
571		snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
572			 ssid_hex, argv[1]);
573	return wpa_ctrl_command(ctrl, buf);
574}
575#endif /* CONFIG_WPS */
576
577
578static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
579					     char *argv[])
580{
581	char buf[300];
582	int res;
583
584	if (argc < 2) {
585		printf("Invalid 'disassoc_imminent' command - two arguments "
586		       "(STA addr and Disassociation Timer) are needed\n");
587		return -1;
588	}
589
590	res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
591			  argv[0], argv[1]);
592	if (res < 0 || res >= (int) sizeof(buf))
593		return -1;
594	return wpa_ctrl_command(ctrl, buf);
595}
596
597
598static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
599					char *argv[])
600{
601	char buf[300];
602	int res;
603
604	if (argc < 3) {
605		printf("Invalid 'ess_disassoc' command - three arguments (STA "
606		       "addr, disassoc timer, and URL) are needed\n");
607		return -1;
608	}
609
610	res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
611			  argv[0], argv[1], argv[2]);
612	if (res < 0 || res >= (int) sizeof(buf))
613		return -1;
614	return wpa_ctrl_command(ctrl, buf);
615}
616
617
618static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
619				      char *argv[])
620{
621	return wpa_ctrl_command(ctrl, "GET_CONFIG");
622}
623
624
625static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
626				char *addr, size_t addr_len)
627{
628	char buf[4096], *pos;
629	size_t len;
630	int ret;
631
632	if (ctrl_conn == NULL) {
633		printf("Not connected to hostapd - command dropped.\n");
634		return -1;
635	}
636	len = sizeof(buf) - 1;
637	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
638			       hostapd_cli_msg_cb);
639	if (ret == -2) {
640		printf("'%s' command timed out.\n", cmd);
641		return -2;
642	} else if (ret < 0) {
643		printf("'%s' command failed.\n", cmd);
644		return -1;
645	}
646
647	buf[len] = '\0';
648	if (memcmp(buf, "FAIL", 4) == 0)
649		return -1;
650	printf("%s", buf);
651
652	pos = buf;
653	while (*pos != '\0' && *pos != '\n')
654		pos++;
655	*pos = '\0';
656	os_strlcpy(addr, buf, addr_len);
657	return 0;
658}
659
660
661static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
662				   char *argv[])
663{
664	char addr[32], cmd[64];
665
666	if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
667		return 0;
668	do {
669		snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
670	} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
671
672	return -1;
673}
674
675
676static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
677{
678	printf("%s", commands_help);
679	return 0;
680}
681
682
683static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
684				   char *argv[])
685{
686	printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
687	return 0;
688}
689
690
691static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
692{
693	hostapd_cli_quit = 1;
694	if (interactive)
695		eloop_terminate();
696	return 0;
697}
698
699
700static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
701{
702	char cmd[256];
703	if (argc != 1) {
704		printf("Invalid LEVEL command: needs one argument (debug "
705		       "level)\n");
706		return 0;
707	}
708	snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
709	return wpa_ctrl_command(ctrl, cmd);
710}
711
712
713static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
714{
715	struct dirent *dent;
716	DIR *dir;
717
718	dir = opendir(ctrl_iface_dir);
719	if (dir == NULL) {
720		printf("Control interface directory '%s' could not be "
721		       "openned.\n", ctrl_iface_dir);
722		return;
723	}
724
725	printf("Available interfaces:\n");
726	while ((dent = readdir(dir))) {
727		if (strcmp(dent->d_name, ".") == 0 ||
728		    strcmp(dent->d_name, "..") == 0)
729			continue;
730		printf("%s\n", dent->d_name);
731	}
732	closedir(dir);
733}
734
735
736static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
737				     char *argv[])
738{
739	if (argc < 1) {
740		hostapd_cli_list_interfaces(ctrl);
741		return 0;
742	}
743
744	hostapd_cli_close_connection();
745	free(ctrl_ifname);
746	ctrl_ifname = strdup(argv[0]);
747
748	if (hostapd_cli_open_connection(ctrl_ifname)) {
749		printf("Connected to interface '%s.\n", ctrl_ifname);
750		if (wpa_ctrl_attach(ctrl_conn) == 0) {
751			hostapd_cli_attached = 1;
752		} else {
753			printf("Warning: Failed to attach to "
754			       "hostapd.\n");
755		}
756	} else {
757		printf("Could not connect to interface '%s' - re-trying\n",
758			ctrl_ifname);
759	}
760	return 0;
761}
762
763
764static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
765{
766	char cmd[256];
767	int res;
768
769	if (argc != 2) {
770		printf("Invalid SET command: needs two arguments (variable "
771		       "name and value)\n");
772		return -1;
773	}
774
775	res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
776	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
777		printf("Too long SET command.\n");
778		return -1;
779	}
780	return wpa_ctrl_command(ctrl, cmd);
781}
782
783
784static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
785{
786	char cmd[256];
787	int res;
788
789	if (argc != 1) {
790		printf("Invalid GET command: needs one argument (variable "
791		       "name)\n");
792		return -1;
793	}
794
795	res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
796	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
797		printf("Too long GET command.\n");
798		return -1;
799	}
800	return wpa_ctrl_command(ctrl, cmd);
801}
802
803
804struct hostapd_cli_cmd {
805	const char *cmd;
806	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
807};
808
809static struct hostapd_cli_cmd hostapd_cli_commands[] = {
810	{ "ping", hostapd_cli_cmd_ping },
811	{ "mib", hostapd_cli_cmd_mib },
812	{ "relog", hostapd_cli_cmd_relog },
813	{ "sta", hostapd_cli_cmd_sta },
814	{ "all_sta", hostapd_cli_cmd_all_sta },
815	{ "new_sta", hostapd_cli_cmd_new_sta },
816	{ "deauthenticate", hostapd_cli_cmd_deauthenticate },
817	{ "disassociate", hostapd_cli_cmd_disassociate },
818#ifdef CONFIG_IEEE80211W
819	{ "sa_query", hostapd_cli_cmd_sa_query },
820#endif /* CONFIG_IEEE80211W */
821#ifdef CONFIG_WPS
822	{ "wps_pin", hostapd_cli_cmd_wps_pin },
823	{ "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
824	{ "wps_pbc", hostapd_cli_cmd_wps_pbc },
825	{ "wps_cancel", hostapd_cli_cmd_wps_cancel },
826#ifdef CONFIG_WPS_NFC
827	{ "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
828	{ "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
829	{ "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
830	{ "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
831#endif /* CONFIG_WPS_NFC */
832	{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
833	{ "wps_config", hostapd_cli_cmd_wps_config },
834	{ "wps_get_status", hostapd_cli_cmd_wps_get_status },
835#endif /* CONFIG_WPS */
836	{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
837	{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
838	{ "get_config", hostapd_cli_cmd_get_config },
839	{ "help", hostapd_cli_cmd_help },
840	{ "interface", hostapd_cli_cmd_interface },
841	{ "level", hostapd_cli_cmd_level },
842	{ "license", hostapd_cli_cmd_license },
843	{ "quit", hostapd_cli_cmd_quit },
844	{ "set", hostapd_cli_cmd_set },
845	{ "get", hostapd_cli_cmd_get },
846	{ NULL, NULL }
847};
848
849
850static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
851{
852	struct hostapd_cli_cmd *cmd, *match = NULL;
853	int count;
854
855	count = 0;
856	cmd = hostapd_cli_commands;
857	while (cmd->cmd) {
858		if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
859			match = cmd;
860			if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
861				/* we have an exact match */
862				count = 1;
863				break;
864			}
865			count++;
866		}
867		cmd++;
868	}
869
870	if (count > 1) {
871		printf("Ambiguous command '%s'; possible commands:", argv[0]);
872		cmd = hostapd_cli_commands;
873		while (cmd->cmd) {
874			if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
875			    0) {
876				printf(" %s", cmd->cmd);
877			}
878			cmd++;
879		}
880		printf("\n");
881	} else if (count == 0) {
882		printf("Unknown command '%s'\n", argv[0]);
883	} else {
884		match->handler(ctrl, argc - 1, &argv[1]);
885	}
886}
887
888
889static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
890				     int action_monitor)
891{
892	int first = 1;
893	if (ctrl_conn == NULL)
894		return;
895	while (wpa_ctrl_pending(ctrl)) {
896		char buf[256];
897		size_t len = sizeof(buf) - 1;
898		if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
899			buf[len] = '\0';
900			if (action_monitor)
901				hostapd_cli_action_process(buf, len);
902			else {
903				if (in_read && first)
904					printf("\n");
905				first = 0;
906				printf("%s\n", buf);
907			}
908		} else {
909			printf("Could not read pending message.\n");
910			break;
911		}
912	}
913}
914
915
916#define max_args 10
917
918static int tokenize_cmd(char *cmd, char *argv[])
919{
920	char *pos;
921	int argc = 0;
922
923	pos = cmd;
924	for (;;) {
925		while (*pos == ' ')
926			pos++;
927		if (*pos == '\0')
928			break;
929		argv[argc] = pos;
930		argc++;
931		if (argc == max_args)
932			break;
933		if (*pos == '"') {
934			char *pos2 = os_strrchr(pos, '"');
935			if (pos2)
936				pos = pos2 + 1;
937		}
938		while (*pos != '\0' && *pos != ' ')
939			pos++;
940		if (*pos == ' ')
941			*pos++ = '\0';
942	}
943
944	return argc;
945}
946
947
948static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
949{
950	if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
951		printf("Connection to hostapd lost - trying to reconnect\n");
952		hostapd_cli_close_connection();
953	}
954	if (!ctrl_conn) {
955		ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
956		if (ctrl_conn) {
957			printf("Connection to hostapd re-established\n");
958			if (wpa_ctrl_attach(ctrl_conn) == 0) {
959				hostapd_cli_attached = 1;
960			} else {
961				printf("Warning: Failed to attach to "
962				       "hostapd.\n");
963			}
964		}
965	}
966	if (ctrl_conn)
967		hostapd_cli_recv_pending(ctrl_conn, 1, 0);
968	eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
969}
970
971
972static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
973{
974	eloop_terminate();
975}
976
977
978static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
979{
980	char *argv[max_args];
981	int argc;
982	argc = tokenize_cmd(cmd, argv);
983	if (argc)
984		wpa_request(ctrl_conn, argc, argv);
985}
986
987
988static void hostapd_cli_edit_eof_cb(void *ctx)
989{
990	eloop_terminate();
991}
992
993
994static void hostapd_cli_interactive(void)
995{
996	printf("\nInteractive mode\n\n");
997
998	eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
999	edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
1000		  NULL, NULL, NULL, NULL);
1001	eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1002
1003	eloop_run();
1004
1005	edit_deinit(NULL, NULL);
1006	eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
1007}
1008
1009
1010static void hostapd_cli_cleanup(void)
1011{
1012	hostapd_cli_close_connection();
1013	if (pid_file)
1014		os_daemonize_terminate(pid_file);
1015
1016	os_program_deinit();
1017}
1018
1019
1020static void hostapd_cli_action(struct wpa_ctrl *ctrl)
1021{
1022	fd_set rfds;
1023	int fd, res;
1024	struct timeval tv;
1025	char buf[256];
1026	size_t len;
1027
1028	fd = wpa_ctrl_get_fd(ctrl);
1029
1030	while (!hostapd_cli_quit) {
1031		FD_ZERO(&rfds);
1032		FD_SET(fd, &rfds);
1033		tv.tv_sec = ping_interval;
1034		tv.tv_usec = 0;
1035		res = select(fd + 1, &rfds, NULL, NULL, &tv);
1036		if (res < 0 && errno != EINTR) {
1037			perror("select");
1038			break;
1039		}
1040
1041		if (FD_ISSET(fd, &rfds))
1042			hostapd_cli_recv_pending(ctrl, 0, 1);
1043		else {
1044			len = sizeof(buf) - 1;
1045			if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1046					     hostapd_cli_action_process) < 0 ||
1047			    len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
1048				printf("hostapd did not reply to PING "
1049				       "command - exiting\n");
1050				break;
1051			}
1052		}
1053	}
1054}
1055
1056
1057int main(int argc, char *argv[])
1058{
1059	int warning_displayed = 0;
1060	int c;
1061	int daemonize = 0;
1062
1063	if (os_program_init())
1064		return -1;
1065
1066	for (;;) {
1067		c = getopt(argc, argv, "a:BhG:i:p:v");
1068		if (c < 0)
1069			break;
1070		switch (c) {
1071		case 'a':
1072			action_file = optarg;
1073			break;
1074		case 'B':
1075			daemonize = 1;
1076			break;
1077		case 'G':
1078			ping_interval = atoi(optarg);
1079			break;
1080		case 'h':
1081			usage();
1082			return 0;
1083		case 'v':
1084			printf("%s\n", hostapd_cli_version);
1085			return 0;
1086		case 'i':
1087			os_free(ctrl_ifname);
1088			ctrl_ifname = os_strdup(optarg);
1089			break;
1090		case 'p':
1091			ctrl_iface_dir = optarg;
1092			break;
1093		default:
1094			usage();
1095			return -1;
1096		}
1097	}
1098
1099	interactive = (argc == optind) && (action_file == NULL);
1100
1101	if (interactive) {
1102		printf("%s\n\n%s\n\n", hostapd_cli_version,
1103		       hostapd_cli_license);
1104	}
1105
1106	if (eloop_init())
1107		return -1;
1108
1109	for (;;) {
1110		if (ctrl_ifname == NULL) {
1111			struct dirent *dent;
1112			DIR *dir = opendir(ctrl_iface_dir);
1113			if (dir) {
1114				while ((dent = readdir(dir))) {
1115					if (os_strcmp(dent->d_name, ".") == 0
1116					    ||
1117					    os_strcmp(dent->d_name, "..") == 0)
1118						continue;
1119					printf("Selected interface '%s'\n",
1120					       dent->d_name);
1121					ctrl_ifname = os_strdup(dent->d_name);
1122					break;
1123				}
1124				closedir(dir);
1125			}
1126		}
1127		ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1128		if (ctrl_conn) {
1129			if (warning_displayed)
1130				printf("Connection established.\n");
1131			break;
1132		}
1133
1134		if (!interactive) {
1135			perror("Failed to connect to hostapd - "
1136			       "wpa_ctrl_open");
1137			return -1;
1138		}
1139
1140		if (!warning_displayed) {
1141			printf("Could not connect to hostapd - re-trying\n");
1142			warning_displayed = 1;
1143		}
1144		os_sleep(1, 0);
1145		continue;
1146	}
1147
1148	if (interactive || action_file) {
1149		if (wpa_ctrl_attach(ctrl_conn) == 0) {
1150			hostapd_cli_attached = 1;
1151		} else {
1152			printf("Warning: Failed to attach to hostapd.\n");
1153			if (action_file)
1154				return -1;
1155		}
1156	}
1157
1158	if (daemonize && os_daemonize(pid_file))
1159		return -1;
1160
1161	if (interactive)
1162		hostapd_cli_interactive();
1163	else if (action_file)
1164		hostapd_cli_action(ctrl_conn);
1165	else
1166		wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1167
1168	os_free(ctrl_ifname);
1169	eloop_destroy();
1170	hostapd_cli_cleanup();
1171	return 0;
1172}
1173