hostapd_cli.c revision 289549
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
20static 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
25static 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
29static 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
60static 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
92static struct wpa_ctrl *ctrl_conn;
93static int hostapd_cli_quit = 0;
94static 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 */
99static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
100static const char *client_socket_dir = NULL;
101
102static char *ctrl_ifname = NULL;
103static const char *pid_file = NULL;
104static const char *action_file = NULL;
105static int ping_interval = 5;
106static int interactive = 0;
107
108
109static 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
137static 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
164static 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
178static void hostapd_cli_msg_cb(char *msg, size_t len)
179{
180	printf("%s\n", msg);
181}
182
183
184static 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
212static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
213{
214	return _wpa_ctrl_command(ctrl, cmd, 1);
215}
216
217
218static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
219{
220	return wpa_ctrl_command(ctrl, "PING");
221}
222
223
224static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
225{
226	return wpa_ctrl_command(ctrl, "RELOG");
227}
228
229
230static 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
238static 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
249static 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
268static 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
285static 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
301static 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
315static 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
333static 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
352static 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
368static 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
389static 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
415static 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
422static 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
430static 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
456static 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
478static 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
499static 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
523static 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
544static 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
551static 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
596static 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
616static 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
636static 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
663static 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
670static 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
706static 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
721static 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
728static 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
736static 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
756static 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
775static 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
795static 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
820static 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
829static 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
842static 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
865static 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
895static 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
915static 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
936static 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
964static 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
1003static 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
1010static 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
1017static 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
1024static 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
1045static 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
1052static 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
1071struct hostapd_cli_cmd {
1072	const char *cmd;
1073	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
1074};
1075
1076static 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
1133static 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
1172static 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
1201static 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
1231static 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
1255static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
1256{
1257	eloop_terminate();
1258}
1259
1260
1261static 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
1271static void hostapd_cli_edit_eof_cb(void *ctx)
1272{
1273	eloop_terminate();
1274}
1275
1276
1277static 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
1293static 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
1303static 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
1340int 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