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