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