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