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