xref: /netbsd-src/external/bsd/wpa/dist/hostapd/hostapd_cli.c (revision c2f76ff004a2cb67efe5b12d97bd3ef7fe89e18d)
1 /*
2  * hostapd - command line interface for hostapd daemon
3  * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14 
15 #include "includes.h"
16 #include <dirent.h>
17 
18 #include "common/wpa_ctrl.h"
19 #include "common.h"
20 #include "common/version.h"
21 
22 
23 static const char *hostapd_cli_version =
24 "hostapd_cli v" VERSION_STR "\n"
25 "Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi> and contributors";
26 
27 
28 static const char *hostapd_cli_license =
29 "This program is free software. You can distribute it and/or modify it\n"
30 "under the terms of the GNU General Public License version 2.\n"
31 "\n"
32 "Alternatively, this software may be distributed under the terms of the\n"
33 "BSD license. See README and COPYING for more details.\n";
34 
35 static const char *hostapd_cli_full_license =
36 "This program is free software; you can redistribute it and/or modify\n"
37 "it under the terms of the GNU General Public License version 2 as\n"
38 "published by the Free Software Foundation.\n"
39 "\n"
40 "This program is distributed in the hope that it will be useful,\n"
41 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
42 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
43 "GNU General Public License for more details.\n"
44 "\n"
45 "You should have received a copy of the GNU General Public License\n"
46 "along with this program; if not, write to the Free Software\n"
47 "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n"
48 "\n"
49 "Alternatively, this software may be distributed under the terms of the\n"
50 "BSD license.\n"
51 "\n"
52 "Redistribution and use in source and binary forms, with or without\n"
53 "modification, are permitted provided that the following conditions are\n"
54 "met:\n"
55 "\n"
56 "1. Redistributions of source code must retain the above copyright\n"
57 "   notice, this list of conditions and the following disclaimer.\n"
58 "\n"
59 "2. Redistributions in binary form must reproduce the above copyright\n"
60 "   notice, this list of conditions and the following disclaimer in the\n"
61 "   documentation and/or other materials provided with the distribution.\n"
62 "\n"
63 "3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
64 "   names of its contributors may be used to endorse or promote products\n"
65 "   derived from this software without specific prior written permission.\n"
66 "\n"
67 "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
68 "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
69 "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
70 "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
71 "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
72 "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
73 "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
74 "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
75 "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
76 "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
77 "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
78 "\n";
79 
80 static const char *commands_help =
81 "Commands:\n"
82 "   mib                  get MIB variables (dot1x, dot11, radius)\n"
83 "   sta <addr>           get MIB variables for one station\n"
84 "   all_sta              get MIB variables for all stations\n"
85 "   new_sta <addr>       add a new station\n"
86 "   deauthenticate <addr>  deauthenticate a station\n"
87 "   disassociate <addr>  disassociate a station\n"
88 #ifdef CONFIG_IEEE80211W
89 "   sa_query <addr>      send SA Query to a station\n"
90 #endif /* CONFIG_IEEE80211W */
91 #ifdef CONFIG_WPS
92 "   wps_pin <uuid> <pin> [timeout]  add WPS Enrollee PIN (Device Password)\n"
93 "   wps_pbc              indicate button pushed to initiate PBC\n"
94 #ifdef CONFIG_WPS_OOB
95 "   wps_oob <type> <path> <method>  use WPS with out-of-band (UFD)\n"
96 #endif /* CONFIG_WPS_OOB */
97 #endif /* CONFIG_WPS */
98 "   help                 show this usage help\n"
99 "   interface [ifname]   show interfaces/select interface\n"
100 "   level <debug level>  change debug level\n"
101 "   license              show full hostapd_cli license\n"
102 "   quit                 exit hostapd_cli\n";
103 
104 static struct wpa_ctrl *ctrl_conn;
105 static int hostapd_cli_quit = 0;
106 static int hostapd_cli_attached = 0;
107 static const char *ctrl_iface_dir = "/var/run/hostapd";
108 static char *ctrl_ifname = NULL;
109 static const char *pid_file = NULL;
110 static const char *action_file = NULL;
111 static int ping_interval = 5;
112 
113 
114 static void usage(void)
115 {
116 	fprintf(stderr, "%s\n", hostapd_cli_version);
117 	fprintf(stderr,
118 		"\n"
119 		"usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
120 		"[-a<path>] \\\n"
121 		"                   [-G<ping interval>] [command..]\n"
122 		"\n"
123 		"Options:\n"
124 		"   -h           help (show this usage text)\n"
125 		"   -v           shown version information\n"
126 		"   -p<path>     path to find control sockets (default: "
127 		"/var/run/hostapd)\n"
128 		"   -a<file>     run in daemon mode executing the action file "
129 		"based on events\n"
130 		"                from hostapd\n"
131 		"   -B           run a daemon in the background\n"
132 		"   -i<ifname>   Interface to listen on (default: first "
133 		"interface found in the\n"
134 		"                socket path)\n\n"
135 		"%s",
136 		commands_help);
137 }
138 
139 
140 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
141 {
142 	char *cfile;
143 	int flen;
144 
145 	if (ifname == NULL)
146 		return NULL;
147 
148 	flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
149 	cfile = malloc(flen);
150 	if (cfile == NULL)
151 		return NULL;
152 	snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
153 
154 	ctrl_conn = wpa_ctrl_open(cfile);
155 	free(cfile);
156 	return ctrl_conn;
157 }
158 
159 
160 static void hostapd_cli_close_connection(void)
161 {
162 	if (ctrl_conn == NULL)
163 		return;
164 
165 	if (hostapd_cli_attached) {
166 		wpa_ctrl_detach(ctrl_conn);
167 		hostapd_cli_attached = 0;
168 	}
169 	wpa_ctrl_close(ctrl_conn);
170 	ctrl_conn = NULL;
171 }
172 
173 
174 static void hostapd_cli_msg_cb(char *msg, size_t len)
175 {
176 	printf("%s\n", msg);
177 }
178 
179 
180 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
181 {
182 	char buf[4096];
183 	size_t len;
184 	int ret;
185 
186 	if (ctrl_conn == NULL) {
187 		printf("Not connected to hostapd - command dropped.\n");
188 		return -1;
189 	}
190 	len = sizeof(buf) - 1;
191 	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
192 			       hostapd_cli_msg_cb);
193 	if (ret == -2) {
194 		printf("'%s' command timed out.\n", cmd);
195 		return -2;
196 	} else if (ret < 0) {
197 		printf("'%s' command failed.\n", cmd);
198 		return -1;
199 	}
200 	if (print) {
201 		buf[len] = '\0';
202 		printf("%s", buf);
203 	}
204 	return 0;
205 }
206 
207 
208 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
209 {
210 	return _wpa_ctrl_command(ctrl, cmd, 1);
211 }
212 
213 
214 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
215 {
216 	return wpa_ctrl_command(ctrl, "PING");
217 }
218 
219 
220 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
221 {
222 	return wpa_ctrl_command(ctrl, "MIB");
223 }
224 
225 
226 static int hostapd_cli_exec(const char *program, const char *arg1,
227 			    const char *arg2)
228 {
229 	char *cmd;
230 	size_t len;
231 	int res;
232 	int ret = 0;
233 
234 	len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
235 	cmd = os_malloc(len);
236 	if (cmd == NULL)
237 		return -1;
238 	res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
239 	if (res < 0 || (size_t) res >= len) {
240 		os_free(cmd);
241 		return -1;
242 	}
243 	cmd[len - 1] = '\0';
244 #ifndef _WIN32_WCE
245 	if (system(cmd) < 0)
246 		ret = -1;
247 #endif /* _WIN32_WCE */
248 	os_free(cmd);
249 
250 	return ret;
251 }
252 
253 
254 static void hostapd_cli_action_process(char *msg, size_t len)
255 {
256 	const char *pos;
257 
258 	pos = msg;
259 	if (*pos == '<') {
260 		pos = os_strchr(pos, '>');
261 		if (pos)
262 			pos++;
263 		else
264 			pos = msg;
265 	}
266 
267 	hostapd_cli_exec(action_file, ctrl_ifname, pos);
268 }
269 
270 
271 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
272 {
273 	char buf[64];
274 	if (argc != 1) {
275 		printf("Invalid 'sta' command - exactly one argument, STA "
276 		       "address, is required.\n");
277 		return -1;
278 	}
279 	snprintf(buf, sizeof(buf), "STA %s", argv[0]);
280 	return wpa_ctrl_command(ctrl, buf);
281 }
282 
283 
284 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
285 				   char *argv[])
286 {
287 	char buf[64];
288 	if (argc != 1) {
289 		printf("Invalid 'new_sta' command - exactly one argument, STA "
290 		       "address, is required.\n");
291 		return -1;
292 	}
293 	snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
294 	return wpa_ctrl_command(ctrl, buf);
295 }
296 
297 
298 static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
299 					  char *argv[])
300 {
301 	char buf[64];
302 	if (argc < 1) {
303 		printf("Invalid 'deauthenticate' command - exactly one "
304 		       "argument, STA address, is required.\n");
305 		return -1;
306 	}
307 	if (argc > 1)
308 		os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
309 			    argv[0], argv[1]);
310 	else
311 		os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
312 	return wpa_ctrl_command(ctrl, buf);
313 }
314 
315 
316 static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
317 					char *argv[])
318 {
319 	char buf[64];
320 	if (argc < 1) {
321 		printf("Invalid 'disassociate' command - exactly one "
322 		       "argument, STA address, is required.\n");
323 		return -1;
324 	}
325 	if (argc > 1)
326 		os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
327 			    argv[0], argv[1]);
328 	else
329 		os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
330 	return wpa_ctrl_command(ctrl, buf);
331 }
332 
333 
334 #ifdef CONFIG_IEEE80211W
335 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
336 				    char *argv[])
337 {
338 	char buf[64];
339 	if (argc != 1) {
340 		printf("Invalid 'sa_query' command - exactly one argument, "
341 		       "STA address, is required.\n");
342 		return -1;
343 	}
344 	snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
345 	return wpa_ctrl_command(ctrl, buf);
346 }
347 #endif /* CONFIG_IEEE80211W */
348 
349 
350 #ifdef CONFIG_WPS
351 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
352 				   char *argv[])
353 {
354 	char buf[64];
355 	if (argc < 2) {
356 		printf("Invalid 'wps_pin' command - at least two arguments, "
357 		       "UUID and PIN, are required.\n");
358 		return -1;
359 	}
360 	if (argc > 2)
361 		snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
362 			 argv[0], argv[1], argv[2]);
363 	else
364 		snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
365 	return wpa_ctrl_command(ctrl, buf);
366 }
367 
368 
369 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
370 				   char *argv[])
371 {
372 	return wpa_ctrl_command(ctrl, "WPS_PBC");
373 }
374 
375 
376 #ifdef CONFIG_WPS_OOB
377 static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
378 				   char *argv[])
379 {
380 	char cmd[256];
381 	int res;
382 
383 	if (argc != 3 && argc != 4) {
384 		printf("Invalid WPS_OOB command: need three or four "
385 		       "arguments:\n"
386 		       "- DEV_TYPE: use 'ufd' or 'nfc'\n"
387 		       "- PATH: path of OOB device like '/mnt'\n"
388 		       "- METHOD: OOB method 'pin-e' or 'pin-r', "
389 		       "'cred'\n"
390 		       "- DEV_NAME: (only for NFC) device name like "
391 		       "'pn531'\n");
392 		return -1;
393 	}
394 
395 	if (argc == 3)
396 		res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
397 				  argv[0], argv[1], argv[2]);
398 	else
399 		res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
400 				  argv[0], argv[1], argv[2], argv[3]);
401 	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
402 		printf("Too long WPS_OOB command.\n");
403 		return -1;
404 	}
405 	return wpa_ctrl_command(ctrl, cmd);
406 }
407 #endif /* CONFIG_WPS_OOB */
408 #endif /* CONFIG_WPS */
409 
410 
411 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
412 				char *addr, size_t addr_len)
413 {
414 	char buf[4096], *pos;
415 	size_t len;
416 	int ret;
417 
418 	if (ctrl_conn == NULL) {
419 		printf("Not connected to hostapd - command dropped.\n");
420 		return -1;
421 	}
422 	len = sizeof(buf) - 1;
423 	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
424 			       hostapd_cli_msg_cb);
425 	if (ret == -2) {
426 		printf("'%s' command timed out.\n", cmd);
427 		return -2;
428 	} else if (ret < 0) {
429 		printf("'%s' command failed.\n", cmd);
430 		return -1;
431 	}
432 
433 	buf[len] = '\0';
434 	if (memcmp(buf, "FAIL", 4) == 0)
435 		return -1;
436 	printf("%s", buf);
437 
438 	pos = buf;
439 	while (*pos != '\0' && *pos != '\n')
440 		pos++;
441 	*pos = '\0';
442 	os_strlcpy(addr, buf, addr_len);
443 	return 0;
444 }
445 
446 
447 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
448 				   char *argv[])
449 {
450 	char addr[32], cmd[64];
451 
452 	if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
453 		return 0;
454 	do {
455 		snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
456 	} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
457 
458 	return -1;
459 }
460 
461 
462 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
463 {
464 	printf("%s", commands_help);
465 	return 0;
466 }
467 
468 
469 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
470 				   char *argv[])
471 {
472 	printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
473 	return 0;
474 }
475 
476 
477 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
478 {
479 	hostapd_cli_quit = 1;
480 	return 0;
481 }
482 
483 
484 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
485 {
486 	char cmd[256];
487 	if (argc != 1) {
488 		printf("Invalid LEVEL command: needs one argument (debug "
489 		       "level)\n");
490 		return 0;
491 	}
492 	snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
493 	return wpa_ctrl_command(ctrl, cmd);
494 }
495 
496 
497 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
498 {
499 	struct dirent *dent;
500 	DIR *dir;
501 
502 	dir = opendir(ctrl_iface_dir);
503 	if (dir == NULL) {
504 		printf("Control interface directory '%s' could not be "
505 		       "openned.\n", ctrl_iface_dir);
506 		return;
507 	}
508 
509 	printf("Available interfaces:\n");
510 	while ((dent = readdir(dir))) {
511 		if (strcmp(dent->d_name, ".") == 0 ||
512 		    strcmp(dent->d_name, "..") == 0)
513 			continue;
514 		printf("%s\n", dent->d_name);
515 	}
516 	closedir(dir);
517 }
518 
519 
520 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
521 				     char *argv[])
522 {
523 	if (argc < 1) {
524 		hostapd_cli_list_interfaces(ctrl);
525 		return 0;
526 	}
527 
528 	hostapd_cli_close_connection();
529 	free(ctrl_ifname);
530 	ctrl_ifname = strdup(argv[0]);
531 
532 	if (hostapd_cli_open_connection(ctrl_ifname)) {
533 		printf("Connected to interface '%s.\n", ctrl_ifname);
534 		if (wpa_ctrl_attach(ctrl_conn) == 0) {
535 			hostapd_cli_attached = 1;
536 		} else {
537 			printf("Warning: Failed to attach to "
538 			       "hostapd.\n");
539 		}
540 	} else {
541 		printf("Could not connect to interface '%s' - re-trying\n",
542 			ctrl_ifname);
543 	}
544 	return 0;
545 }
546 
547 
548 struct hostapd_cli_cmd {
549 	const char *cmd;
550 	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
551 };
552 
553 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
554 	{ "ping", hostapd_cli_cmd_ping },
555 	{ "mib", hostapd_cli_cmd_mib },
556 	{ "sta", hostapd_cli_cmd_sta },
557 	{ "all_sta", hostapd_cli_cmd_all_sta },
558 	{ "new_sta", hostapd_cli_cmd_new_sta },
559 	{ "deauthenticate", hostapd_cli_cmd_deauthenticate },
560 	{ "disassociate", hostapd_cli_cmd_disassociate },
561 #ifdef CONFIG_IEEE80211W
562 	{ "sa_query", hostapd_cli_cmd_sa_query },
563 #endif /* CONFIG_IEEE80211W */
564 #ifdef CONFIG_WPS
565 	{ "wps_pin", hostapd_cli_cmd_wps_pin },
566 	{ "wps_pbc", hostapd_cli_cmd_wps_pbc },
567 #ifdef CONFIG_WPS_OOB
568 	{ "wps_oob", hostapd_cli_cmd_wps_oob },
569 #endif /* CONFIG_WPS_OOB */
570 #endif /* CONFIG_WPS */
571 	{ "help", hostapd_cli_cmd_help },
572 	{ "interface", hostapd_cli_cmd_interface },
573 	{ "level", hostapd_cli_cmd_level },
574 	{ "license", hostapd_cli_cmd_license },
575 	{ "quit", hostapd_cli_cmd_quit },
576 	{ NULL, NULL }
577 };
578 
579 
580 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
581 {
582 	struct hostapd_cli_cmd *cmd, *match = NULL;
583 	int count;
584 
585 	count = 0;
586 	cmd = hostapd_cli_commands;
587 	while (cmd->cmd) {
588 		if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
589 			match = cmd;
590 			count++;
591 		}
592 		cmd++;
593 	}
594 
595 	if (count > 1) {
596 		printf("Ambiguous command '%s'; possible commands:", argv[0]);
597 		cmd = hostapd_cli_commands;
598 		while (cmd->cmd) {
599 			if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
600 			    0) {
601 				printf(" %s", cmd->cmd);
602 			}
603 			cmd++;
604 		}
605 		printf("\n");
606 	} else if (count == 0) {
607 		printf("Unknown command '%s'\n", argv[0]);
608 	} else {
609 		match->handler(ctrl, argc - 1, &argv[1]);
610 	}
611 }
612 
613 
614 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
615 				     int action_monitor)
616 {
617 	int first = 1;
618 	if (ctrl_conn == NULL)
619 		return;
620 	while (wpa_ctrl_pending(ctrl)) {
621 		char buf[256];
622 		size_t len = sizeof(buf) - 1;
623 		if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
624 			buf[len] = '\0';
625 			if (action_monitor)
626 				hostapd_cli_action_process(buf, len);
627 			else {
628 				if (in_read && first)
629 					printf("\n");
630 				first = 0;
631 				printf("%s\n", buf);
632 			}
633 		} else {
634 			printf("Could not read pending message.\n");
635 			break;
636 		}
637 	}
638 }
639 
640 
641 static void hostapd_cli_interactive(void)
642 {
643 #define	max_args 10
644 	char cmd[256], *res, *argv[max_args], *pos;
645 	int argc;
646 
647 	printf("\nInteractive mode\n\n");
648 
649 	do {
650 		hostapd_cli_recv_pending(ctrl_conn, 0, 0);
651 		printf("> ");
652 		alarm(ping_interval);
653 		res = fgets(cmd, sizeof(cmd), stdin);
654 		alarm(0);
655 		if (res == NULL)
656 			break;
657 		pos = cmd;
658 		while (*pos != '\0') {
659 			if (*pos == '\n') {
660 				*pos = '\0';
661 				break;
662 			}
663 			pos++;
664 		}
665 		argc = 0;
666 		pos = cmd;
667 		for (;;) {
668 			while (*pos == ' ')
669 				pos++;
670 			if (*pos == '\0')
671 				break;
672 			argv[argc] = pos;
673 			argc++;
674 			if (argc == max_args)
675 				break;
676 			while (*pos != '\0' && *pos != ' ')
677 				pos++;
678 			if (*pos == ' ')
679 				*pos++ = '\0';
680 		}
681 		if (argc)
682 			wpa_request(ctrl_conn, argc, argv);
683 	} while (!hostapd_cli_quit);
684 }
685 
686 
687 static void hostapd_cli_cleanup(void)
688 {
689 	hostapd_cli_close_connection();
690 	if (pid_file)
691 		os_daemonize_terminate(pid_file);
692 
693 	os_program_deinit();
694 }
695 
696 
697 static void hostapd_cli_terminate(int sig)
698 {
699 	hostapd_cli_cleanup();
700 	exit(0);
701 }
702 
703 
704 static void hostapd_cli_alarm(int sig)
705 {
706 	if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
707 		printf("Connection to hostapd lost - trying to reconnect\n");
708 		hostapd_cli_close_connection();
709 	}
710 	if (!ctrl_conn) {
711 		ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
712 		if (ctrl_conn) {
713 			printf("Connection to hostapd re-established\n");
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 		}
721 	}
722 	if (ctrl_conn)
723 		hostapd_cli_recv_pending(ctrl_conn, 1, 0);
724 	alarm(ping_interval);
725 }
726 
727 
728 static void hostapd_cli_action(struct wpa_ctrl *ctrl)
729 {
730 	fd_set rfds;
731 	int fd, res;
732 	struct timeval tv;
733 	char buf[256];
734 	size_t len;
735 
736 	fd = wpa_ctrl_get_fd(ctrl);
737 
738 	while (!hostapd_cli_quit) {
739 		FD_ZERO(&rfds);
740 		FD_SET(fd, &rfds);
741 		tv.tv_sec = ping_interval;
742 		tv.tv_usec = 0;
743 		res = select(fd + 1, &rfds, NULL, NULL, &tv);
744 		if (res < 0 && errno != EINTR) {
745 			perror("select");
746 			break;
747 		}
748 
749 		if (FD_ISSET(fd, &rfds))
750 			hostapd_cli_recv_pending(ctrl, 0, 1);
751 		else {
752 			len = sizeof(buf) - 1;
753 			if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
754 					     hostapd_cli_action_process) < 0 ||
755 			    len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
756 				printf("hostapd did not reply to PING "
757 				       "command - exiting\n");
758 				break;
759 			}
760 		}
761 	}
762 }
763 
764 
765 int main(int argc, char *argv[])
766 {
767 	int interactive;
768 	int warning_displayed = 0;
769 	int c;
770 	int daemonize = 0;
771 
772 	if (os_program_init())
773 		return -1;
774 
775 	for (;;) {
776 		c = getopt(argc, argv, "a:BhG:i:p:v");
777 		if (c < 0)
778 			break;
779 		switch (c) {
780 		case 'a':
781 			action_file = optarg;
782 			break;
783 		case 'B':
784 			daemonize = 1;
785 			break;
786 		case 'G':
787 			ping_interval = atoi(optarg);
788 			break;
789 		case 'h':
790 			usage();
791 			return 0;
792 		case 'v':
793 			printf("%s\n", hostapd_cli_version);
794 			return 0;
795 		case 'i':
796 			os_free(ctrl_ifname);
797 			ctrl_ifname = os_strdup(optarg);
798 			break;
799 		case 'p':
800 			ctrl_iface_dir = optarg;
801 			break;
802 		default:
803 			usage();
804 			return -1;
805 		}
806 	}
807 
808 	interactive = (argc == optind) && (action_file == NULL);
809 
810 	if (interactive) {
811 		printf("%s\n\n%s\n\n", hostapd_cli_version,
812 		       hostapd_cli_license);
813 	}
814 
815 	for (;;) {
816 		if (ctrl_ifname == NULL) {
817 			struct dirent *dent;
818 			DIR *dir = opendir(ctrl_iface_dir);
819 			if (dir) {
820 				while ((dent = readdir(dir))) {
821 					if (os_strcmp(dent->d_name, ".") == 0
822 					    ||
823 					    os_strcmp(dent->d_name, "..") == 0)
824 						continue;
825 					printf("Selected interface '%s'\n",
826 					       dent->d_name);
827 					ctrl_ifname = os_strdup(dent->d_name);
828 					break;
829 				}
830 				closedir(dir);
831 			}
832 		}
833 		ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
834 		if (ctrl_conn) {
835 			if (warning_displayed)
836 				printf("Connection established.\n");
837 			break;
838 		}
839 
840 		if (!interactive) {
841 			perror("Failed to connect to hostapd - "
842 			       "wpa_ctrl_open");
843 			return -1;
844 		}
845 
846 		if (!warning_displayed) {
847 			printf("Could not connect to hostapd - re-trying\n");
848 			warning_displayed = 1;
849 		}
850 		os_sleep(1, 0);
851 		continue;
852 	}
853 
854 	signal(SIGINT, hostapd_cli_terminate);
855 	signal(SIGTERM, hostapd_cli_terminate);
856 	signal(SIGALRM, hostapd_cli_alarm);
857 
858 	if (interactive || action_file) {
859 		if (wpa_ctrl_attach(ctrl_conn) == 0) {
860 			hostapd_cli_attached = 1;
861 		} else {
862 			printf("Warning: Failed to attach to hostapd.\n");
863 			if (action_file)
864 				return -1;
865 		}
866 	}
867 
868 	if (daemonize && os_daemonize(pid_file))
869 		return -1;
870 
871 	if (interactive)
872 		hostapd_cli_interactive();
873 	else if (action_file)
874 		hostapd_cli_action(ctrl_conn);
875 	else
876 		wpa_request(ctrl_conn, argc - optind, &argv[optind]);
877 
878 	os_free(ctrl_ifname);
879 	hostapd_cli_cleanup();
880 	return 0;
881 }
882