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