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