Home | History | Annotate | Download | only in hostapd
      1 /*
      2  * hostapd - command line interface for hostapd daemon
      3  * Copyright (c) 2004-2012, 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 "   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 
    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 
    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 
    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 
    169 static void hostapd_cli_msg_cb(char *msg, size_t len)
    170 {
    171 	printf("%s\n", msg);
    172 }
    173 
    174 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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
    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
    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 
    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 
    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 
    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
    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
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    958 static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
    959 {
    960 	eloop_terminate();
    961 }
    962 
    963 
    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 
    974 static void hostapd_cli_edit_eof_cb(void *ctx)
    975 {
    976 	eloop_terminate();
    977 }
    978 
    979 
    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 
    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 
   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 
   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