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