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