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