hostapd_cli.c revision a54fa5fb807eaeff45464139b5a7759f060cec68
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#endif /* CONFIG_WPS_NFC */
479
480
481static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
482				      char *argv[])
483{
484	char buf[64];
485	if (argc < 1) {
486		printf("Invalid 'wps_ap_pin' command - at least one argument "
487		       "is required.\n");
488		return -1;
489	}
490	if (argc > 2)
491		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
492			 argv[0], argv[1], argv[2]);
493	else if (argc > 1)
494		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
495			 argv[0], argv[1]);
496	else
497		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
498	return wpa_ctrl_command(ctrl, buf);
499}
500
501
502static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
503				      char *argv[])
504{
505	char buf[256];
506	char ssid_hex[2 * 32 + 1];
507	char key_hex[2 * 64 + 1];
508	int i;
509
510	if (argc < 1) {
511		printf("Invalid 'wps_config' command - at least two arguments "
512		       "are required.\n");
513		return -1;
514	}
515
516	ssid_hex[0] = '\0';
517	for (i = 0; i < 32; i++) {
518		if (argv[0][i] == '\0')
519			break;
520		os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
521	}
522
523	key_hex[0] = '\0';
524	if (argc > 3) {
525		for (i = 0; i < 64; i++) {
526			if (argv[3][i] == '\0')
527				break;
528			os_snprintf(&key_hex[i * 2], 3, "%02x",
529				    argv[3][i]);
530		}
531	}
532
533	if (argc > 3)
534		snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
535			 ssid_hex, argv[1], argv[2], key_hex);
536	else if (argc > 2)
537		snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
538			 ssid_hex, argv[1], argv[2]);
539	else
540		snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
541			 ssid_hex, argv[1]);
542	return wpa_ctrl_command(ctrl, buf);
543}
544#endif /* CONFIG_WPS */
545
546
547static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
548					     char *argv[])
549{
550	char buf[300];
551	int res;
552
553	if (argc < 2) {
554		printf("Invalid 'disassoc_imminent' command - two arguments "
555		       "(STA addr and Disassociation Timer) are needed\n");
556		return -1;
557	}
558
559	res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
560			  argv[0], argv[1]);
561	if (res < 0 || res >= (int) sizeof(buf))
562		return -1;
563	return wpa_ctrl_command(ctrl, buf);
564}
565
566
567static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
568					char *argv[])
569{
570	char buf[300];
571	int res;
572
573	if (argc < 2) {
574		printf("Invalid 'ess_disassoc' command - two arguments (STA "
575		       "addr and URL) are needed\n");
576		return -1;
577	}
578
579	res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s",
580			  argv[0], argv[1]);
581	if (res < 0 || res >= (int) sizeof(buf))
582		return -1;
583	return wpa_ctrl_command(ctrl, buf);
584}
585
586
587static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
588				      char *argv[])
589{
590	return wpa_ctrl_command(ctrl, "GET_CONFIG");
591}
592
593
594static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
595				char *addr, size_t addr_len)
596{
597	char buf[4096], *pos;
598	size_t len;
599	int ret;
600
601	if (ctrl_conn == NULL) {
602		printf("Not connected to hostapd - command dropped.\n");
603		return -1;
604	}
605	len = sizeof(buf) - 1;
606	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
607			       hostapd_cli_msg_cb);
608	if (ret == -2) {
609		printf("'%s' command timed out.\n", cmd);
610		return -2;
611	} else if (ret < 0) {
612		printf("'%s' command failed.\n", cmd);
613		return -1;
614	}
615
616	buf[len] = '\0';
617	if (memcmp(buf, "FAIL", 4) == 0)
618		return -1;
619	printf("%s", buf);
620
621	pos = buf;
622	while (*pos != '\0' && *pos != '\n')
623		pos++;
624	*pos = '\0';
625	os_strlcpy(addr, buf, addr_len);
626	return 0;
627}
628
629
630static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
631				   char *argv[])
632{
633	char addr[32], cmd[64];
634
635	if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
636		return 0;
637	do {
638		snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
639	} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
640
641	return -1;
642}
643
644
645static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
646{
647	printf("%s", commands_help);
648	return 0;
649}
650
651
652static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
653				   char *argv[])
654{
655	printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
656	return 0;
657}
658
659
660static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
661{
662	hostapd_cli_quit = 1;
663	if (interactive)
664		eloop_terminate();
665	return 0;
666}
667
668
669static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
670{
671	char cmd[256];
672	if (argc != 1) {
673		printf("Invalid LEVEL command: needs one argument (debug "
674		       "level)\n");
675		return 0;
676	}
677	snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
678	return wpa_ctrl_command(ctrl, cmd);
679}
680
681
682static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
683{
684	struct dirent *dent;
685	DIR *dir;
686
687	dir = opendir(ctrl_iface_dir);
688	if (dir == NULL) {
689		printf("Control interface directory '%s' could not be "
690		       "openned.\n", ctrl_iface_dir);
691		return;
692	}
693
694	printf("Available interfaces:\n");
695	while ((dent = readdir(dir))) {
696		if (strcmp(dent->d_name, ".") == 0 ||
697		    strcmp(dent->d_name, "..") == 0)
698			continue;
699		printf("%s\n", dent->d_name);
700	}
701	closedir(dir);
702}
703
704
705static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
706				     char *argv[])
707{
708	if (argc < 1) {
709		hostapd_cli_list_interfaces(ctrl);
710		return 0;
711	}
712
713	hostapd_cli_close_connection();
714	free(ctrl_ifname);
715	ctrl_ifname = strdup(argv[0]);
716
717	if (hostapd_cli_open_connection(ctrl_ifname)) {
718		printf("Connected to interface '%s.\n", ctrl_ifname);
719		if (wpa_ctrl_attach(ctrl_conn) == 0) {
720			hostapd_cli_attached = 1;
721		} else {
722			printf("Warning: Failed to attach to "
723			       "hostapd.\n");
724		}
725	} else {
726		printf("Could not connect to interface '%s' - re-trying\n",
727			ctrl_ifname);
728	}
729	return 0;
730}
731
732
733static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
734{
735	char cmd[256];
736	int res;
737
738	if (argc != 2) {
739		printf("Invalid SET command: needs two arguments (variable "
740		       "name and value)\n");
741		return -1;
742	}
743
744	res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
745	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
746		printf("Too long SET command.\n");
747		return -1;
748	}
749	return wpa_ctrl_command(ctrl, cmd);
750}
751
752
753static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
754{
755	char cmd[256];
756	int res;
757
758	if (argc != 1) {
759		printf("Invalid GET command: needs one argument (variable "
760		       "name)\n");
761		return -1;
762	}
763
764	res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
765	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
766		printf("Too long GET command.\n");
767		return -1;
768	}
769	return wpa_ctrl_command(ctrl, cmd);
770}
771
772
773struct hostapd_cli_cmd {
774	const char *cmd;
775	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
776};
777
778static struct hostapd_cli_cmd hostapd_cli_commands[] = {
779	{ "ping", hostapd_cli_cmd_ping },
780	{ "mib", hostapd_cli_cmd_mib },
781	{ "relog", hostapd_cli_cmd_relog },
782	{ "sta", hostapd_cli_cmd_sta },
783	{ "all_sta", hostapd_cli_cmd_all_sta },
784	{ "new_sta", hostapd_cli_cmd_new_sta },
785	{ "deauthenticate", hostapd_cli_cmd_deauthenticate },
786	{ "disassociate", hostapd_cli_cmd_disassociate },
787#ifdef CONFIG_IEEE80211W
788	{ "sa_query", hostapd_cli_cmd_sa_query },
789#endif /* CONFIG_IEEE80211W */
790#ifdef CONFIG_WPS
791	{ "wps_pin", hostapd_cli_cmd_wps_pin },
792	{ "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
793	{ "wps_pbc", hostapd_cli_cmd_wps_pbc },
794	{ "wps_cancel", hostapd_cli_cmd_wps_cancel },
795#ifdef CONFIG_WPS_NFC
796	{ "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
797	{ "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
798	{ "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
799#endif /* CONFIG_WPS_NFC */
800	{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
801	{ "wps_config", hostapd_cli_cmd_wps_config },
802#endif /* CONFIG_WPS */
803	{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
804	{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
805	{ "get_config", hostapd_cli_cmd_get_config },
806	{ "help", hostapd_cli_cmd_help },
807	{ "interface", hostapd_cli_cmd_interface },
808	{ "level", hostapd_cli_cmd_level },
809	{ "license", hostapd_cli_cmd_license },
810	{ "quit", hostapd_cli_cmd_quit },
811	{ "set", hostapd_cli_cmd_set },
812	{ "get", hostapd_cli_cmd_get },
813	{ NULL, NULL }
814};
815
816
817static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
818{
819	struct hostapd_cli_cmd *cmd, *match = NULL;
820	int count;
821
822	count = 0;
823	cmd = hostapd_cli_commands;
824	while (cmd->cmd) {
825		if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
826			match = cmd;
827			if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
828				/* we have an exact match */
829				count = 1;
830				break;
831			}
832			count++;
833		}
834		cmd++;
835	}
836
837	if (count > 1) {
838		printf("Ambiguous command '%s'; possible commands:", argv[0]);
839		cmd = hostapd_cli_commands;
840		while (cmd->cmd) {
841			if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
842			    0) {
843				printf(" %s", cmd->cmd);
844			}
845			cmd++;
846		}
847		printf("\n");
848	} else if (count == 0) {
849		printf("Unknown command '%s'\n", argv[0]);
850	} else {
851		match->handler(ctrl, argc - 1, &argv[1]);
852	}
853}
854
855
856static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
857				     int action_monitor)
858{
859	int first = 1;
860	if (ctrl_conn == NULL)
861		return;
862	while (wpa_ctrl_pending(ctrl)) {
863		char buf[256];
864		size_t len = sizeof(buf) - 1;
865		if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
866			buf[len] = '\0';
867			if (action_monitor)
868				hostapd_cli_action_process(buf, len);
869			else {
870				if (in_read && first)
871					printf("\n");
872				first = 0;
873				printf("%s\n", buf);
874			}
875		} else {
876			printf("Could not read pending message.\n");
877			break;
878		}
879	}
880}
881
882
883#define max_args 10
884
885static int tokenize_cmd(char *cmd, char *argv[])
886{
887	char *pos;
888	int argc = 0;
889
890	pos = cmd;
891	for (;;) {
892		while (*pos == ' ')
893			pos++;
894		if (*pos == '\0')
895			break;
896		argv[argc] = pos;
897		argc++;
898		if (argc == max_args)
899			break;
900		if (*pos == '"') {
901			char *pos2 = os_strrchr(pos, '"');
902			if (pos2)
903				pos = pos2 + 1;
904		}
905		while (*pos != '\0' && *pos != ' ')
906			pos++;
907		if (*pos == ' ')
908			*pos++ = '\0';
909	}
910
911	return argc;
912}
913
914
915static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
916{
917	if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
918		printf("Connection to hostapd lost - trying to reconnect\n");
919		hostapd_cli_close_connection();
920	}
921	if (!ctrl_conn) {
922		ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
923		if (ctrl_conn) {
924			printf("Connection to hostapd re-established\n");
925			if (wpa_ctrl_attach(ctrl_conn) == 0) {
926				hostapd_cli_attached = 1;
927			} else {
928				printf("Warning: Failed to attach to "
929				       "hostapd.\n");
930			}
931		}
932	}
933	if (ctrl_conn)
934		hostapd_cli_recv_pending(ctrl_conn, 1, 0);
935	eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
936}
937
938
939static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
940{
941	eloop_terminate();
942}
943
944
945static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
946{
947	char *argv[max_args];
948	int argc;
949	argc = tokenize_cmd(cmd, argv);
950	if (argc)
951		wpa_request(ctrl_conn, argc, argv);
952}
953
954
955static void hostapd_cli_edit_eof_cb(void *ctx)
956{
957	eloop_terminate();
958}
959
960
961static void hostapd_cli_interactive(void)
962{
963	printf("\nInteractive mode\n\n");
964
965	eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
966	edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
967		  NULL, NULL, NULL, NULL);
968	eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
969
970	eloop_run();
971
972	edit_deinit(NULL, NULL);
973	eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
974}
975
976
977static void hostapd_cli_cleanup(void)
978{
979	hostapd_cli_close_connection();
980	if (pid_file)
981		os_daemonize_terminate(pid_file);
982
983	os_program_deinit();
984}
985
986
987static void hostapd_cli_action(struct wpa_ctrl *ctrl)
988{
989	fd_set rfds;
990	int fd, res;
991	struct timeval tv;
992	char buf[256];
993	size_t len;
994
995	fd = wpa_ctrl_get_fd(ctrl);
996
997	while (!hostapd_cli_quit) {
998		FD_ZERO(&rfds);
999		FD_SET(fd, &rfds);
1000		tv.tv_sec = ping_interval;
1001		tv.tv_usec = 0;
1002		res = select(fd + 1, &rfds, NULL, NULL, &tv);
1003		if (res < 0 && errno != EINTR) {
1004			perror("select");
1005			break;
1006		}
1007
1008		if (FD_ISSET(fd, &rfds))
1009			hostapd_cli_recv_pending(ctrl, 0, 1);
1010		else {
1011			len = sizeof(buf) - 1;
1012			if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1013					     hostapd_cli_action_process) < 0 ||
1014			    len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
1015				printf("hostapd did not reply to PING "
1016				       "command - exiting\n");
1017				break;
1018			}
1019		}
1020	}
1021}
1022
1023
1024int main(int argc, char *argv[])
1025{
1026	int warning_displayed = 0;
1027	int c;
1028	int daemonize = 0;
1029
1030	if (os_program_init())
1031		return -1;
1032
1033	for (;;) {
1034		c = getopt(argc, argv, "a:BhG:i:p:v");
1035		if (c < 0)
1036			break;
1037		switch (c) {
1038		case 'a':
1039			action_file = optarg;
1040			break;
1041		case 'B':
1042			daemonize = 1;
1043			break;
1044		case 'G':
1045			ping_interval = atoi(optarg);
1046			break;
1047		case 'h':
1048			usage();
1049			return 0;
1050		case 'v':
1051			printf("%s\n", hostapd_cli_version);
1052			return 0;
1053		case 'i':
1054			os_free(ctrl_ifname);
1055			ctrl_ifname = os_strdup(optarg);
1056			break;
1057		case 'p':
1058			ctrl_iface_dir = optarg;
1059			break;
1060		default:
1061			usage();
1062			return -1;
1063		}
1064	}
1065
1066	interactive = (argc == optind) && (action_file == NULL);
1067
1068	if (interactive) {
1069		printf("%s\n\n%s\n\n", hostapd_cli_version,
1070		       hostapd_cli_license);
1071	}
1072
1073	if (eloop_init())
1074		return -1;
1075
1076	for (;;) {
1077		if (ctrl_ifname == NULL) {
1078			struct dirent *dent;
1079			DIR *dir = opendir(ctrl_iface_dir);
1080			if (dir) {
1081				while ((dent = readdir(dir))) {
1082					if (os_strcmp(dent->d_name, ".") == 0
1083					    ||
1084					    os_strcmp(dent->d_name, "..") == 0)
1085						continue;
1086					printf("Selected interface '%s'\n",
1087					       dent->d_name);
1088					ctrl_ifname = os_strdup(dent->d_name);
1089					break;
1090				}
1091				closedir(dir);
1092			}
1093		}
1094		ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1095		if (ctrl_conn) {
1096			if (warning_displayed)
1097				printf("Connection established.\n");
1098			break;
1099		}
1100
1101		if (!interactive) {
1102			perror("Failed to connect to hostapd - "
1103			       "wpa_ctrl_open");
1104			return -1;
1105		}
1106
1107		if (!warning_displayed) {
1108			printf("Could not connect to hostapd - re-trying\n");
1109			warning_displayed = 1;
1110		}
1111		os_sleep(1, 0);
1112		continue;
1113	}
1114
1115	if (interactive || action_file) {
1116		if (wpa_ctrl_attach(ctrl_conn) == 0) {
1117			hostapd_cli_attached = 1;
1118		} else {
1119			printf("Warning: Failed to attach to hostapd.\n");
1120			if (action_file)
1121				return -1;
1122		}
1123	}
1124
1125	if (daemonize && os_daemonize(pid_file))
1126		return -1;
1127
1128	if (interactive)
1129		hostapd_cli_interactive();
1130	else if (action_file)
1131		hostapd_cli_action(ctrl_conn);
1132	else
1133		wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1134
1135	os_free(ctrl_ifname);
1136	eloop_destroy();
1137	hostapd_cli_cleanup();
1138	return 0;
1139}
1140