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