• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * hostapd - command line interface for hostapd daemon
3  * Copyright (c) 2004-2014, 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-2014, 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 
usage(void)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 
hostapd_cli_open_connection(const char * ifname)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 
hostapd_cli_close_connection(void)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 
hostapd_cli_msg_cb(char * msg,size_t len)167 static void hostapd_cli_msg_cb(char *msg, size_t len)
168 {
169 	printf("%s\n", msg);
170 }
171 
172 
_wpa_ctrl_command(struct wpa_ctrl * ctrl,char * cmd,int print)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 
wpa_ctrl_command(struct wpa_ctrl * ctrl,char * cmd)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 
hostapd_cli_cmd_ping(struct wpa_ctrl * ctrl,int argc,char * argv[])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 
hostapd_cli_cmd_relog(struct wpa_ctrl * ctrl,int argc,char * argv[])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 
hostapd_cli_cmd_status(struct wpa_ctrl * ctrl,int argc,char * argv[])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 
hostapd_cli_cmd_mib(struct wpa_ctrl * ctrl,int argc,char * argv[])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 
hostapd_cli_exec(const char * program,const char * arg1,const char * arg2)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 
hostapd_cli_action_process(char * msg,size_t len)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 
hostapd_cli_cmd_sta(struct wpa_ctrl * ctrl,int argc,char * argv[])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 
hostapd_cli_cmd_new_sta(struct wpa_ctrl * ctrl,int argc,char * argv[])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 
hostapd_cli_cmd_deauthenticate(struct wpa_ctrl * ctrl,int argc,char * argv[])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 
hostapd_cli_cmd_disassociate(struct wpa_ctrl * ctrl,int argc,char * argv[])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
hostapd_cli_cmd_sa_query(struct wpa_ctrl * ctrl,int argc,char * argv[])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
hostapd_cli_cmd_wps_pin(struct wpa_ctrl * ctrl,int argc,char * argv[])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 
hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl * ctrl,int argc,char * argv[])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 (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
397 		printf("Too long WPS_CHECK_PIN command.\n");
398 		return -1;
399 	}
400 	return wpa_ctrl_command(ctrl, cmd);
401 }
402 
403 
hostapd_cli_cmd_wps_pbc(struct wpa_ctrl * ctrl,int argc,char * argv[])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 
hostapd_cli_cmd_wps_cancel(struct wpa_ctrl * ctrl,int argc,char * argv[])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
hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl * ctrl,int argc,char * argv[])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 
hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl * ctrl,int argc,char * argv[])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 (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
460 		printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
461 		return -1;
462 	}
463 	return wpa_ctrl_command(ctrl, cmd);
464 }
465 
466 
hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl * ctrl,int argc,char * argv[])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 (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
481 		printf("Too long WPS_NFC_TOKEN command.\n");
482 		return -1;
483 	}
484 	return wpa_ctrl_command(ctrl, cmd);
485 }
486 
487 
hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl * ctrl,int argc,char * argv[])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 (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
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 
hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl * ctrl,int argc,char * argv[])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 
hostapd_cli_cmd_wps_get_status(struct wpa_ctrl * ctrl,int argc,char * argv[])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 
hostapd_cli_cmd_wps_config(struct wpa_ctrl * ctrl,int argc,char * argv[])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 
hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl * ctrl,int argc,char * argv[])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 (res < 0 || res >= (int) sizeof(buf))
600 		return -1;
601 	return wpa_ctrl_command(ctrl, buf);
602 }
603 
604 
hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl * ctrl,int argc,char * argv[])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 (res < 0 || res >= (int) sizeof(buf))
620 		return -1;
621 	return wpa_ctrl_command(ctrl, buf);
622 }
623 
624 
hostapd_cli_cmd_get_config(struct wpa_ctrl * ctrl,int argc,char * argv[])625 static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
626 				      char *argv[])
627 {
628 	return wpa_ctrl_command(ctrl, "GET_CONFIG");
629 }
630 
631 
wpa_ctrl_command_sta(struct wpa_ctrl * ctrl,char * cmd,char * addr,size_t addr_len)632 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
633 				char *addr, size_t addr_len)
634 {
635 	char buf[4096], *pos;
636 	size_t len;
637 	int ret;
638 
639 	if (ctrl_conn == NULL) {
640 		printf("Not connected to hostapd - command dropped.\n");
641 		return -1;
642 	}
643 	len = sizeof(buf) - 1;
644 	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
645 			       hostapd_cli_msg_cb);
646 	if (ret == -2) {
647 		printf("'%s' command timed out.\n", cmd);
648 		return -2;
649 	} else if (ret < 0) {
650 		printf("'%s' command failed.\n", cmd);
651 		return -1;
652 	}
653 
654 	buf[len] = '\0';
655 	if (memcmp(buf, "FAIL", 4) == 0)
656 		return -1;
657 	printf("%s", buf);
658 
659 	pos = buf;
660 	while (*pos != '\0' && *pos != '\n')
661 		pos++;
662 	*pos = '\0';
663 	os_strlcpy(addr, buf, addr_len);
664 	return 0;
665 }
666 
667 
hostapd_cli_cmd_all_sta(struct wpa_ctrl * ctrl,int argc,char * argv[])668 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
669 				   char *argv[])
670 {
671 	char addr[32], cmd[64];
672 
673 	if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
674 		return 0;
675 	do {
676 		snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
677 	} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
678 
679 	return -1;
680 }
681 
682 
hostapd_cli_cmd_help(struct wpa_ctrl * ctrl,int argc,char * argv[])683 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
684 {
685 	printf("%s", commands_help);
686 	return 0;
687 }
688 
689 
hostapd_cli_cmd_license(struct wpa_ctrl * ctrl,int argc,char * argv[])690 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
691 				   char *argv[])
692 {
693 	printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
694 	return 0;
695 }
696 
697 
hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl * ctrl,int argc,char * argv[])698 static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl,
699 					   int argc, char *argv[])
700 {
701 	char buf[200];
702 	int res;
703 
704 	if (argc != 1) {
705 		printf("Invalid 'set_qos_map_set' command - "
706 		       "one argument (comma delimited QoS map set) "
707 		       "is needed\n");
708 		return -1;
709 	}
710 
711 	res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
712 	if (res < 0 || res >= (int) sizeof(buf))
713 		return -1;
714 	return wpa_ctrl_command(ctrl, buf);
715 }
716 
717 
hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl * ctrl,int argc,char * argv[])718 static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
719 					     int argc, char *argv[])
720 {
721 	char buf[50];
722 	int res;
723 
724 	if (argc != 1) {
725 		printf("Invalid 'send_qos_map_conf' command - "
726 		       "one argument (STA addr) is needed\n");
727 		return -1;
728 	}
729 
730 	res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
731 	if (res < 0 || res >= (int) sizeof(buf))
732 		return -1;
733 	return wpa_ctrl_command(ctrl, buf);
734 }
735 
736 
hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl * ctrl,int argc,char * argv[])737 static int hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc,
738 					  char *argv[])
739 {
740 	char buf[300];
741 	int res;
742 
743 	if (argc < 2) {
744 		printf("Invalid 'hs20_wnm_notif' command - two arguments (STA "
745 		       "addr and URL) are needed\n");
746 		return -1;
747 	}
748 
749 	res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s",
750 			  argv[0], argv[1]);
751 	if (res < 0 || res >= (int) sizeof(buf))
752 		return -1;
753 	return wpa_ctrl_command(ctrl, buf);
754 }
755 
756 
hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl * ctrl,int argc,char * argv[])757 static int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc,
758 					   char *argv[])
759 {
760 	char buf[300];
761 	int res;
762 
763 	if (argc < 3) {
764 		printf("Invalid 'hs20_deauth_req' command - at least three arguments (STA addr, Code, Re-auth Delay) are needed\n");
765 		return -1;
766 	}
767 
768 	if (argc > 3)
769 		res = os_snprintf(buf, sizeof(buf),
770 				  "HS20_DEAUTH_REQ %s %s %s %s",
771 				  argv[0], argv[1], argv[2], argv[3]);
772 	else
773 		res = os_snprintf(buf, sizeof(buf),
774 				  "HS20_DEAUTH_REQ %s %s %s",
775 				  argv[0], argv[1], argv[2]);
776 	if (res < 0 || res >= (int) sizeof(buf))
777 		return -1;
778 	return wpa_ctrl_command(ctrl, buf);
779 }
780 
781 
hostapd_cli_cmd_quit(struct wpa_ctrl * ctrl,int argc,char * argv[])782 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
783 {
784 	hostapd_cli_quit = 1;
785 	if (interactive)
786 		eloop_terminate();
787 	return 0;
788 }
789 
790 
hostapd_cli_cmd_level(struct wpa_ctrl * ctrl,int argc,char * argv[])791 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
792 {
793 	char cmd[256];
794 	if (argc != 1) {
795 		printf("Invalid LEVEL command: needs one argument (debug "
796 		       "level)\n");
797 		return 0;
798 	}
799 	snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
800 	return wpa_ctrl_command(ctrl, cmd);
801 }
802 
803 
hostapd_cli_list_interfaces(struct wpa_ctrl * ctrl)804 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
805 {
806 	struct dirent *dent;
807 	DIR *dir;
808 
809 	dir = opendir(ctrl_iface_dir);
810 	if (dir == NULL) {
811 		printf("Control interface directory '%s' could not be "
812 		       "openned.\n", ctrl_iface_dir);
813 		return;
814 	}
815 
816 	printf("Available interfaces:\n");
817 	while ((dent = readdir(dir))) {
818 		if (strcmp(dent->d_name, ".") == 0 ||
819 		    strcmp(dent->d_name, "..") == 0)
820 			continue;
821 		printf("%s\n", dent->d_name);
822 	}
823 	closedir(dir);
824 }
825 
826 
hostapd_cli_cmd_interface(struct wpa_ctrl * ctrl,int argc,char * argv[])827 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
828 				     char *argv[])
829 {
830 	if (argc < 1) {
831 		hostapd_cli_list_interfaces(ctrl);
832 		return 0;
833 	}
834 
835 	hostapd_cli_close_connection();
836 	os_free(ctrl_ifname);
837 	ctrl_ifname = os_strdup(argv[0]);
838 	if (ctrl_ifname == NULL)
839 		return -1;
840 
841 	if (hostapd_cli_open_connection(ctrl_ifname)) {
842 		printf("Connected to interface '%s.\n", ctrl_ifname);
843 		if (wpa_ctrl_attach(ctrl_conn) == 0) {
844 			hostapd_cli_attached = 1;
845 		} else {
846 			printf("Warning: Failed to attach to "
847 			       "hostapd.\n");
848 		}
849 	} else {
850 		printf("Could not connect to interface '%s' - re-trying\n",
851 			ctrl_ifname);
852 	}
853 	return 0;
854 }
855 
856 
hostapd_cli_cmd_set(struct wpa_ctrl * ctrl,int argc,char * argv[])857 static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
858 {
859 	char cmd[256];
860 	int res;
861 
862 	if (argc != 2) {
863 		printf("Invalid SET command: needs two arguments (variable "
864 		       "name and value)\n");
865 		return -1;
866 	}
867 
868 	res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
869 	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
870 		printf("Too long SET command.\n");
871 		return -1;
872 	}
873 	return wpa_ctrl_command(ctrl, cmd);
874 }
875 
876 
hostapd_cli_cmd_get(struct wpa_ctrl * ctrl,int argc,char * argv[])877 static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
878 {
879 	char cmd[256];
880 	int res;
881 
882 	if (argc != 1) {
883 		printf("Invalid GET command: needs one argument (variable "
884 		       "name)\n");
885 		return -1;
886 	}
887 
888 	res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
889 	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
890 		printf("Too long GET command.\n");
891 		return -1;
892 	}
893 	return wpa_ctrl_command(ctrl, cmd);
894 }
895 
896 
hostapd_cli_cmd_chan_switch(struct wpa_ctrl * ctrl,int argc,char * argv[])897 static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
898 				       int argc, char *argv[])
899 {
900 	char cmd[256];
901 	int res;
902 	int i;
903 	char *tmp;
904 	int total;
905 
906 	if (argc < 2) {
907 		printf("Invalid chan_switch command: needs at least two "
908 		       "arguments (count and freq)\n"
909 		       "usage: <cs_count> <freq> [sec_channel_offset=] "
910 		       "[center_freq1=] [center_freq2=] [bandwidth=] "
911 		       "[blocktx] [ht|vht]\n");
912 		return -1;
913 	}
914 
915 	res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
916 			  argv[0], argv[1]);
917 	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
918 		printf("Too long CHAN_SWITCH command.\n");
919 		return -1;
920 	}
921 
922 	total = res;
923 	for (i = 2; i < argc; i++) {
924 		tmp = cmd + total;
925 		res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
926 		if (res < 0 || (size_t) res >= sizeof(cmd) - total - 1) {
927 			printf("Too long CHAN_SWITCH command.\n");
928 			return -1;
929 		}
930 		total += res;
931 	}
932 	return wpa_ctrl_command(ctrl, cmd);
933 }
934 
935 
hostapd_cli_cmd_vendor(struct wpa_ctrl * ctrl,int argc,char * argv[])936 static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
937 {
938 	char cmd[256];
939 	int res;
940 
941 	if (argc < 2 || argc > 3) {
942 		printf("Invalid vendor command\n"
943 		       "usage: <vendor id> <command id> [<hex formatted command argument>]\n");
944 		return -1;
945 	}
946 
947 	res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
948 			  argc == 3 ? argv[2] : "");
949 	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
950 		printf("Too long VENDOR command.\n");
951 		return -1;
952 	}
953 	return wpa_ctrl_command(ctrl, cmd);
954 }
955 
956 
957 struct hostapd_cli_cmd {
958 	const char *cmd;
959 	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
960 };
961 
962 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
963 	{ "ping", hostapd_cli_cmd_ping },
964 	{ "mib", hostapd_cli_cmd_mib },
965 	{ "relog", hostapd_cli_cmd_relog },
966 	{ "status", hostapd_cli_cmd_status },
967 	{ "sta", hostapd_cli_cmd_sta },
968 	{ "all_sta", hostapd_cli_cmd_all_sta },
969 	{ "new_sta", hostapd_cli_cmd_new_sta },
970 	{ "deauthenticate", hostapd_cli_cmd_deauthenticate },
971 	{ "disassociate", hostapd_cli_cmd_disassociate },
972 #ifdef CONFIG_IEEE80211W
973 	{ "sa_query", hostapd_cli_cmd_sa_query },
974 #endif /* CONFIG_IEEE80211W */
975 #ifdef CONFIG_WPS
976 	{ "wps_pin", hostapd_cli_cmd_wps_pin },
977 	{ "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
978 	{ "wps_pbc", hostapd_cli_cmd_wps_pbc },
979 	{ "wps_cancel", hostapd_cli_cmd_wps_cancel },
980 #ifdef CONFIG_WPS_NFC
981 	{ "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
982 	{ "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
983 	{ "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
984 	{ "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
985 #endif /* CONFIG_WPS_NFC */
986 	{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
987 	{ "wps_config", hostapd_cli_cmd_wps_config },
988 	{ "wps_get_status", hostapd_cli_cmd_wps_get_status },
989 #endif /* CONFIG_WPS */
990 	{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
991 	{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
992 	{ "get_config", hostapd_cli_cmd_get_config },
993 	{ "help", hostapd_cli_cmd_help },
994 	{ "interface", hostapd_cli_cmd_interface },
995 	{ "level", hostapd_cli_cmd_level },
996 	{ "license", hostapd_cli_cmd_license },
997 	{ "quit", hostapd_cli_cmd_quit },
998 	{ "set", hostapd_cli_cmd_set },
999 	{ "get", hostapd_cli_cmd_get },
1000 	{ "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
1001 	{ "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
1002 	{ "chan_switch", hostapd_cli_cmd_chan_switch },
1003 	{ "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif },
1004 	{ "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req },
1005 	{ "vendor", hostapd_cli_cmd_vendor },
1006 	{ NULL, NULL }
1007 };
1008 
1009 
wpa_request(struct wpa_ctrl * ctrl,int argc,char * argv[])1010 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
1011 {
1012 	struct hostapd_cli_cmd *cmd, *match = NULL;
1013 	int count;
1014 
1015 	count = 0;
1016 	cmd = hostapd_cli_commands;
1017 	while (cmd->cmd) {
1018 		if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
1019 			match = cmd;
1020 			if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1021 				/* we have an exact match */
1022 				count = 1;
1023 				break;
1024 			}
1025 			count++;
1026 		}
1027 		cmd++;
1028 	}
1029 
1030 	if (count > 1) {
1031 		printf("Ambiguous command '%s'; possible commands:", argv[0]);
1032 		cmd = hostapd_cli_commands;
1033 		while (cmd->cmd) {
1034 			if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
1035 			    0) {
1036 				printf(" %s", cmd->cmd);
1037 			}
1038 			cmd++;
1039 		}
1040 		printf("\n");
1041 	} else if (count == 0) {
1042 		printf("Unknown command '%s'\n", argv[0]);
1043 	} else {
1044 		match->handler(ctrl, argc - 1, &argv[1]);
1045 	}
1046 }
1047 
1048 
hostapd_cli_recv_pending(struct wpa_ctrl * ctrl,int in_read,int action_monitor)1049 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
1050 				     int action_monitor)
1051 {
1052 	int first = 1;
1053 	if (ctrl_conn == NULL)
1054 		return;
1055 	while (wpa_ctrl_pending(ctrl)) {
1056 		char buf[256];
1057 		size_t len = sizeof(buf) - 1;
1058 		if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
1059 			buf[len] = '\0';
1060 			if (action_monitor)
1061 				hostapd_cli_action_process(buf, len);
1062 			else {
1063 				if (in_read && first)
1064 					printf("\n");
1065 				first = 0;
1066 				printf("%s\n", buf);
1067 			}
1068 		} else {
1069 			printf("Could not read pending message.\n");
1070 			break;
1071 		}
1072 	}
1073 }
1074 
1075 
1076 #define max_args 10
1077 
tokenize_cmd(char * cmd,char * argv[])1078 static int tokenize_cmd(char *cmd, char *argv[])
1079 {
1080 	char *pos;
1081 	int argc = 0;
1082 
1083 	pos = cmd;
1084 	for (;;) {
1085 		while (*pos == ' ')
1086 			pos++;
1087 		if (*pos == '\0')
1088 			break;
1089 		argv[argc] = pos;
1090 		argc++;
1091 		if (argc == max_args)
1092 			break;
1093 		if (*pos == '"') {
1094 			char *pos2 = os_strrchr(pos, '"');
1095 			if (pos2)
1096 				pos = pos2 + 1;
1097 		}
1098 		while (*pos != '\0' && *pos != ' ')
1099 			pos++;
1100 		if (*pos == ' ')
1101 			*pos++ = '\0';
1102 	}
1103 
1104 	return argc;
1105 }
1106 
1107 
hostapd_cli_ping(void * eloop_ctx,void * timeout_ctx)1108 static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
1109 {
1110 	if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
1111 		printf("Connection to hostapd lost - trying to reconnect\n");
1112 		hostapd_cli_close_connection();
1113 	}
1114 	if (!ctrl_conn) {
1115 		ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1116 		if (ctrl_conn) {
1117 			printf("Connection to hostapd re-established\n");
1118 			if (wpa_ctrl_attach(ctrl_conn) == 0) {
1119 				hostapd_cli_attached = 1;
1120 			} else {
1121 				printf("Warning: Failed to attach to "
1122 				       "hostapd.\n");
1123 			}
1124 		}
1125 	}
1126 	if (ctrl_conn)
1127 		hostapd_cli_recv_pending(ctrl_conn, 1, 0);
1128 	eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1129 }
1130 
1131 
hostapd_cli_eloop_terminate(int sig,void * signal_ctx)1132 static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
1133 {
1134 	eloop_terminate();
1135 }
1136 
1137 
hostapd_cli_edit_cmd_cb(void * ctx,char * cmd)1138 static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
1139 {
1140 	char *argv[max_args];
1141 	int argc;
1142 	argc = tokenize_cmd(cmd, argv);
1143 	if (argc)
1144 		wpa_request(ctrl_conn, argc, argv);
1145 }
1146 
1147 
hostapd_cli_edit_eof_cb(void * ctx)1148 static void hostapd_cli_edit_eof_cb(void *ctx)
1149 {
1150 	eloop_terminate();
1151 }
1152 
1153 
hostapd_cli_interactive(void)1154 static void hostapd_cli_interactive(void)
1155 {
1156 	printf("\nInteractive mode\n\n");
1157 
1158 	eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
1159 	edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
1160 		  NULL, NULL, NULL, NULL);
1161 	eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1162 
1163 	eloop_run();
1164 
1165 	edit_deinit(NULL, NULL);
1166 	eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
1167 }
1168 
1169 
hostapd_cli_cleanup(void)1170 static void hostapd_cli_cleanup(void)
1171 {
1172 	hostapd_cli_close_connection();
1173 	if (pid_file)
1174 		os_daemonize_terminate(pid_file);
1175 
1176 	os_program_deinit();
1177 }
1178 
1179 
hostapd_cli_action(struct wpa_ctrl * ctrl)1180 static void hostapd_cli_action(struct wpa_ctrl *ctrl)
1181 {
1182 	fd_set rfds;
1183 	int fd, res;
1184 	struct timeval tv;
1185 	char buf[256];
1186 	size_t len;
1187 
1188 	fd = wpa_ctrl_get_fd(ctrl);
1189 
1190 	while (!hostapd_cli_quit) {
1191 		FD_ZERO(&rfds);
1192 		FD_SET(fd, &rfds);
1193 		tv.tv_sec = ping_interval;
1194 		tv.tv_usec = 0;
1195 		res = select(fd + 1, &rfds, NULL, NULL, &tv);
1196 		if (res < 0 && errno != EINTR) {
1197 			perror("select");
1198 			break;
1199 		}
1200 
1201 		if (FD_ISSET(fd, &rfds))
1202 			hostapd_cli_recv_pending(ctrl, 0, 1);
1203 		else {
1204 			len = sizeof(buf) - 1;
1205 			if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1206 					     hostapd_cli_action_process) < 0 ||
1207 			    len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
1208 				printf("hostapd did not reply to PING "
1209 				       "command - exiting\n");
1210 				break;
1211 			}
1212 		}
1213 	}
1214 }
1215 
1216 
main(int argc,char * argv[])1217 int main(int argc, char *argv[])
1218 {
1219 	int warning_displayed = 0;
1220 	int c;
1221 	int daemonize = 0;
1222 
1223 	if (os_program_init())
1224 		return -1;
1225 
1226 	for (;;) {
1227 		c = getopt(argc, argv, "a:BhG:i:p:v");
1228 		if (c < 0)
1229 			break;
1230 		switch (c) {
1231 		case 'a':
1232 			action_file = optarg;
1233 			break;
1234 		case 'B':
1235 			daemonize = 1;
1236 			break;
1237 		case 'G':
1238 			ping_interval = atoi(optarg);
1239 			break;
1240 		case 'h':
1241 			usage();
1242 			return 0;
1243 		case 'v':
1244 			printf("%s\n", hostapd_cli_version);
1245 			return 0;
1246 		case 'i':
1247 			os_free(ctrl_ifname);
1248 			ctrl_ifname = os_strdup(optarg);
1249 			break;
1250 		case 'p':
1251 			ctrl_iface_dir = optarg;
1252 			break;
1253 		default:
1254 			usage();
1255 			return -1;
1256 		}
1257 	}
1258 
1259 	interactive = (argc == optind) && (action_file == NULL);
1260 
1261 	if (interactive) {
1262 		printf("%s\n\n%s\n\n", hostapd_cli_version,
1263 		       hostapd_cli_license);
1264 	}
1265 
1266 	if (eloop_init())
1267 		return -1;
1268 
1269 	for (;;) {
1270 		if (ctrl_ifname == NULL) {
1271 			struct dirent *dent;
1272 			DIR *dir = opendir(ctrl_iface_dir);
1273 			if (dir) {
1274 				while ((dent = readdir(dir))) {
1275 					if (os_strcmp(dent->d_name, ".") == 0
1276 					    ||
1277 					    os_strcmp(dent->d_name, "..") == 0)
1278 						continue;
1279 					printf("Selected interface '%s'\n",
1280 					       dent->d_name);
1281 					ctrl_ifname = os_strdup(dent->d_name);
1282 					break;
1283 				}
1284 				closedir(dir);
1285 			}
1286 		}
1287 		ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1288 		if (ctrl_conn) {
1289 			if (warning_displayed)
1290 				printf("Connection established.\n");
1291 			break;
1292 		}
1293 
1294 		if (!interactive) {
1295 			perror("Failed to connect to hostapd - "
1296 			       "wpa_ctrl_open");
1297 			return -1;
1298 		}
1299 
1300 		if (!warning_displayed) {
1301 			printf("Could not connect to hostapd - re-trying\n");
1302 			warning_displayed = 1;
1303 		}
1304 		os_sleep(1, 0);
1305 		continue;
1306 	}
1307 
1308 	if (interactive || action_file) {
1309 		if (wpa_ctrl_attach(ctrl_conn) == 0) {
1310 			hostapd_cli_attached = 1;
1311 		} else {
1312 			printf("Warning: Failed to attach to hostapd.\n");
1313 			if (action_file)
1314 				return -1;
1315 		}
1316 	}
1317 
1318 	if (daemonize && os_daemonize(pid_file))
1319 		return -1;
1320 
1321 	if (interactive)
1322 		hostapd_cli_interactive();
1323 	else if (action_file)
1324 		hostapd_cli_action(ctrl_conn);
1325 	else
1326 		wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1327 
1328 	os_free(ctrl_ifname);
1329 	eloop_destroy();
1330 	hostapd_cli_cleanup();
1331 	return 0;
1332 }
1333