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