1214503Srpaulo/* 2214503Srpaulo * hostapd - command line interface for hostapd daemon 3214503Srpaulo * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi> 4214503Srpaulo * 5214503Srpaulo * This program is free software; you can redistribute it and/or modify 6214503Srpaulo * it under the terms of the GNU General Public License version 2 as 7214503Srpaulo * published by the Free Software Foundation. 8214503Srpaulo * 9214503Srpaulo * Alternatively, this software may be distributed under the terms of BSD 10214503Srpaulo * license. 11214503Srpaulo * 12214503Srpaulo * See README and COPYING for more details. 13214503Srpaulo */ 14214503Srpaulo 15214503Srpaulo#include "includes.h" 16214503Srpaulo#include <dirent.h> 17214503Srpaulo 18214503Srpaulo#include "common/wpa_ctrl.h" 19214503Srpaulo#include "common.h" 20214503Srpaulo#include "common/version.h" 21214503Srpaulo 22214503Srpaulo 23214503Srpaulostatic const char *hostapd_cli_version = 24214503Srpaulo"hostapd_cli v" VERSION_STR "\n" 25214503Srpaulo"Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi> and contributors"; 26214503Srpaulo 27214503Srpaulo 28214503Srpaulostatic const char *hostapd_cli_license = 29214503Srpaulo"This program is free software. You can distribute it and/or modify it\n" 30214503Srpaulo"under the terms of the GNU General Public License version 2.\n" 31214503Srpaulo"\n" 32214503Srpaulo"Alternatively, this software may be distributed under the terms of the\n" 33214503Srpaulo"BSD license. See README and COPYING for more details.\n"; 34214503Srpaulo 35214503Srpaulostatic const char *hostapd_cli_full_license = 36214503Srpaulo"This program is free software; you can redistribute it and/or modify\n" 37214503Srpaulo"it under the terms of the GNU General Public License version 2 as\n" 38214503Srpaulo"published by the Free Software Foundation.\n" 39214503Srpaulo"\n" 40214503Srpaulo"This program is distributed in the hope that it will be useful,\n" 41214503Srpaulo"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" 42214503Srpaulo"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" 43214503Srpaulo"GNU General Public License for more details.\n" 44214503Srpaulo"\n" 45214503Srpaulo"You should have received a copy of the GNU General Public License\n" 46214503Srpaulo"along with this program; if not, write to the Free Software\n" 47214503Srpaulo"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n" 48214503Srpaulo"\n" 49214503Srpaulo"Alternatively, this software may be distributed under the terms of the\n" 50214503Srpaulo"BSD license.\n" 51214503Srpaulo"\n" 52214503Srpaulo"Redistribution and use in source and binary forms, with or without\n" 53214503Srpaulo"modification, are permitted provided that the following conditions are\n" 54214503Srpaulo"met:\n" 55214503Srpaulo"\n" 56214503Srpaulo"1. Redistributions of source code must retain the above copyright\n" 57214503Srpaulo" notice, this list of conditions and the following disclaimer.\n" 58214503Srpaulo"\n" 59214503Srpaulo"2. Redistributions in binary form must reproduce the above copyright\n" 60214503Srpaulo" notice, this list of conditions and the following disclaimer in the\n" 61214503Srpaulo" documentation and/or other materials provided with the distribution.\n" 62214503Srpaulo"\n" 63214503Srpaulo"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n" 64214503Srpaulo" names of its contributors may be used to endorse or promote products\n" 65214503Srpaulo" derived from this software without specific prior written permission.\n" 66214503Srpaulo"\n" 67214503Srpaulo"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n" 68214503Srpaulo"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n" 69214503Srpaulo"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n" 70214503Srpaulo"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n" 71214503Srpaulo"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n" 72214503Srpaulo"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n" 73214503Srpaulo"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n" 74214503Srpaulo"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" 75214503Srpaulo"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" 76214503Srpaulo"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n" 77214503Srpaulo"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" 78214503Srpaulo"\n"; 79214503Srpaulo 80214503Srpaulostatic const char *commands_help = 81214503Srpaulo"Commands:\n" 82214503Srpaulo" mib get MIB variables (dot1x, dot11, radius)\n" 83214503Srpaulo" sta <addr> get MIB variables for one station\n" 84214503Srpaulo" all_sta get MIB variables for all stations\n" 85214503Srpaulo" new_sta <addr> add a new station\n" 86214503Srpaulo" deauthenticate <addr> deauthenticate a station\n" 87214503Srpaulo" disassociate <addr> disassociate a station\n" 88214503Srpaulo#ifdef CONFIG_IEEE80211W 89214503Srpaulo" sa_query <addr> send SA Query to a station\n" 90214503Srpaulo#endif /* CONFIG_IEEE80211W */ 91214503Srpaulo#ifdef CONFIG_WPS 92214503Srpaulo" wps_pin <uuid> <pin> [timeout] add WPS Enrollee PIN (Device Password)\n" 93214503Srpaulo" wps_pbc indicate button pushed to initiate PBC\n" 94214503Srpaulo#ifdef CONFIG_WPS_OOB 95214503Srpaulo" wps_oob <type> <path> <method> use WPS with out-of-band (UFD)\n" 96214503Srpaulo#endif /* CONFIG_WPS_OOB */ 97214503Srpaulo" wps_ap_pin <cmd> [params..] enable/disable AP PIN\n" 98214503Srpaulo#endif /* CONFIG_WPS */ 99214503Srpaulo" help show this usage help\n" 100214503Srpaulo" interface [ifname] show interfaces/select interface\n" 101214503Srpaulo" level <debug level> change debug level\n" 102214503Srpaulo" license show full hostapd_cli license\n" 103214503Srpaulo" quit exit hostapd_cli\n"; 104214503Srpaulo 105214503Srpaulostatic struct wpa_ctrl *ctrl_conn; 106214503Srpaulostatic int hostapd_cli_quit = 0; 107214503Srpaulostatic int hostapd_cli_attached = 0; 108214503Srpaulostatic const char *ctrl_iface_dir = "/var/run/hostapd"; 109214503Srpaulostatic char *ctrl_ifname = NULL; 110214503Srpaulostatic const char *pid_file = NULL; 111214503Srpaulostatic const char *action_file = NULL; 112214503Srpaulostatic int ping_interval = 5; 113214503Srpaulo 114214503Srpaulo 115214503Srpaulostatic void usage(void) 116214503Srpaulo{ 117214503Srpaulo fprintf(stderr, "%s\n", hostapd_cli_version); 118214503Srpaulo fprintf(stderr, 119214503Srpaulo "\n" 120214503Srpaulo "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] " 121214503Srpaulo "[-a<path>] \\\n" 122214503Srpaulo " [-G<ping interval>] [command..]\n" 123214503Srpaulo "\n" 124214503Srpaulo "Options:\n" 125214503Srpaulo " -h help (show this usage text)\n" 126214503Srpaulo " -v shown version information\n" 127214503Srpaulo " -p<path> path to find control sockets (default: " 128214503Srpaulo "/var/run/hostapd)\n" 129214503Srpaulo " -a<file> run in daemon mode executing the action file " 130214503Srpaulo "based on events\n" 131214503Srpaulo " from hostapd\n" 132214503Srpaulo " -B run a daemon in the background\n" 133214503Srpaulo " -i<ifname> Interface to listen on (default: first " 134214503Srpaulo "interface found in the\n" 135214503Srpaulo " socket path)\n\n" 136214503Srpaulo "%s", 137214503Srpaulo commands_help); 138214503Srpaulo} 139214503Srpaulo 140214503Srpaulo 141214503Srpaulostatic struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname) 142214503Srpaulo{ 143214503Srpaulo char *cfile; 144214503Srpaulo int flen; 145214503Srpaulo 146214503Srpaulo if (ifname == NULL) 147214503Srpaulo return NULL; 148214503Srpaulo 149214503Srpaulo flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2; 150214503Srpaulo cfile = malloc(flen); 151214503Srpaulo if (cfile == NULL) 152214503Srpaulo return NULL; 153214503Srpaulo snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname); 154214503Srpaulo 155214503Srpaulo ctrl_conn = wpa_ctrl_open(cfile); 156214503Srpaulo free(cfile); 157214503Srpaulo return ctrl_conn; 158214503Srpaulo} 159214503Srpaulo 160214503Srpaulo 161214503Srpaulostatic void hostapd_cli_close_connection(void) 162214503Srpaulo{ 163214503Srpaulo if (ctrl_conn == NULL) 164214503Srpaulo return; 165214503Srpaulo 166214503Srpaulo if (hostapd_cli_attached) { 167214503Srpaulo wpa_ctrl_detach(ctrl_conn); 168214503Srpaulo hostapd_cli_attached = 0; 169214503Srpaulo } 170214503Srpaulo wpa_ctrl_close(ctrl_conn); 171214503Srpaulo ctrl_conn = NULL; 172214503Srpaulo} 173214503Srpaulo 174214503Srpaulo 175214503Srpaulostatic void hostapd_cli_msg_cb(char *msg, size_t len) 176214503Srpaulo{ 177214503Srpaulo printf("%s\n", msg); 178214503Srpaulo} 179214503Srpaulo 180214503Srpaulo 181214503Srpaulostatic int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print) 182214503Srpaulo{ 183214503Srpaulo char buf[4096]; 184214503Srpaulo size_t len; 185214503Srpaulo int ret; 186214503Srpaulo 187214503Srpaulo if (ctrl_conn == NULL) { 188214503Srpaulo printf("Not connected to hostapd - command dropped.\n"); 189214503Srpaulo return -1; 190214503Srpaulo } 191214503Srpaulo len = sizeof(buf) - 1; 192214503Srpaulo ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, 193214503Srpaulo hostapd_cli_msg_cb); 194214503Srpaulo if (ret == -2) { 195214503Srpaulo printf("'%s' command timed out.\n", cmd); 196214503Srpaulo return -2; 197214503Srpaulo } else if (ret < 0) { 198214503Srpaulo printf("'%s' command failed.\n", cmd); 199214503Srpaulo return -1; 200214503Srpaulo } 201214503Srpaulo if (print) { 202214503Srpaulo buf[len] = '\0'; 203214503Srpaulo printf("%s", buf); 204214503Srpaulo } 205214503Srpaulo return 0; 206214503Srpaulo} 207214503Srpaulo 208214503Srpaulo 209214503Srpaulostatic inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd) 210214503Srpaulo{ 211214503Srpaulo return _wpa_ctrl_command(ctrl, cmd, 1); 212214503Srpaulo} 213214503Srpaulo 214214503Srpaulo 215214503Srpaulostatic int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[]) 216214503Srpaulo{ 217214503Srpaulo return wpa_ctrl_command(ctrl, "PING"); 218214503Srpaulo} 219214503Srpaulo 220214503Srpaulo 221214503Srpaulostatic int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[]) 222214503Srpaulo{ 223214503Srpaulo return wpa_ctrl_command(ctrl, "MIB"); 224214503Srpaulo} 225214503Srpaulo 226214503Srpaulo 227214503Srpaulostatic int hostapd_cli_exec(const char *program, const char *arg1, 228214503Srpaulo const char *arg2) 229214503Srpaulo{ 230214503Srpaulo char *cmd; 231214503Srpaulo size_t len; 232214503Srpaulo int res; 233214503Srpaulo int ret = 0; 234214503Srpaulo 235214503Srpaulo len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3; 236214503Srpaulo cmd = os_malloc(len); 237214503Srpaulo if (cmd == NULL) 238214503Srpaulo return -1; 239214503Srpaulo res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2); 240214503Srpaulo if (res < 0 || (size_t) res >= len) { 241214503Srpaulo os_free(cmd); 242214503Srpaulo return -1; 243214503Srpaulo } 244214503Srpaulo cmd[len - 1] = '\0'; 245214503Srpaulo#ifndef _WIN32_WCE 246214503Srpaulo if (system(cmd) < 0) 247214503Srpaulo ret = -1; 248214503Srpaulo#endif /* _WIN32_WCE */ 249214503Srpaulo os_free(cmd); 250214503Srpaulo 251214503Srpaulo return ret; 252214503Srpaulo} 253214503Srpaulo 254214503Srpaulo 255214503Srpaulostatic void hostapd_cli_action_process(char *msg, size_t len) 256214503Srpaulo{ 257214503Srpaulo const char *pos; 258214503Srpaulo 259214503Srpaulo pos = msg; 260214503Srpaulo if (*pos == '<') { 261214503Srpaulo pos = os_strchr(pos, '>'); 262214503Srpaulo if (pos) 263214503Srpaulo pos++; 264214503Srpaulo else 265214503Srpaulo pos = msg; 266214503Srpaulo } 267214503Srpaulo 268214503Srpaulo hostapd_cli_exec(action_file, ctrl_ifname, pos); 269214503Srpaulo} 270214503Srpaulo 271214503Srpaulo 272214503Srpaulostatic int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) 273214503Srpaulo{ 274214503Srpaulo char buf[64]; 275214503Srpaulo if (argc != 1) { 276214503Srpaulo printf("Invalid 'sta' command - exactly one argument, STA " 277214503Srpaulo "address, is required.\n"); 278214503Srpaulo return -1; 279214503Srpaulo } 280214503Srpaulo snprintf(buf, sizeof(buf), "STA %s", argv[0]); 281214503Srpaulo return wpa_ctrl_command(ctrl, buf); 282214503Srpaulo} 283214503Srpaulo 284214503Srpaulo 285214503Srpaulostatic int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc, 286214503Srpaulo char *argv[]) 287214503Srpaulo{ 288214503Srpaulo char buf[64]; 289214503Srpaulo if (argc != 1) { 290214503Srpaulo printf("Invalid 'new_sta' command - exactly one argument, STA " 291214503Srpaulo "address, is required.\n"); 292214503Srpaulo return -1; 293214503Srpaulo } 294214503Srpaulo snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]); 295214503Srpaulo return wpa_ctrl_command(ctrl, buf); 296214503Srpaulo} 297214503Srpaulo 298214503Srpaulo 299214503Srpaulostatic int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc, 300214503Srpaulo char *argv[]) 301214503Srpaulo{ 302214503Srpaulo char buf[64]; 303214503Srpaulo if (argc < 1) { 304214503Srpaulo printf("Invalid 'deauthenticate' command - exactly one " 305214503Srpaulo "argument, STA address, is required.\n"); 306214503Srpaulo return -1; 307214503Srpaulo } 308214503Srpaulo if (argc > 1) 309214503Srpaulo os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s", 310214503Srpaulo argv[0], argv[1]); 311214503Srpaulo else 312214503Srpaulo os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]); 313214503Srpaulo return wpa_ctrl_command(ctrl, buf); 314214503Srpaulo} 315214503Srpaulo 316214503Srpaulo 317214503Srpaulostatic int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc, 318214503Srpaulo char *argv[]) 319214503Srpaulo{ 320214503Srpaulo char buf[64]; 321214503Srpaulo if (argc < 1) { 322214503Srpaulo printf("Invalid 'disassociate' command - exactly one " 323214503Srpaulo "argument, STA address, is required.\n"); 324214503Srpaulo return -1; 325214503Srpaulo } 326214503Srpaulo if (argc > 1) 327214503Srpaulo os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s", 328214503Srpaulo argv[0], argv[1]); 329214503Srpaulo else 330214503Srpaulo os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]); 331214503Srpaulo return wpa_ctrl_command(ctrl, buf); 332214503Srpaulo} 333214503Srpaulo 334214503Srpaulo 335214503Srpaulo#ifdef CONFIG_IEEE80211W 336214503Srpaulostatic int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc, 337214503Srpaulo char *argv[]) 338214503Srpaulo{ 339214503Srpaulo char buf[64]; 340214503Srpaulo if (argc != 1) { 341214503Srpaulo printf("Invalid 'sa_query' command - exactly one argument, " 342214503Srpaulo "STA address, is required.\n"); 343214503Srpaulo return -1; 344214503Srpaulo } 345214503Srpaulo snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]); 346214503Srpaulo return wpa_ctrl_command(ctrl, buf); 347214503Srpaulo} 348214503Srpaulo#endif /* CONFIG_IEEE80211W */ 349214503Srpaulo 350214503Srpaulo 351214503Srpaulo#ifdef CONFIG_WPS 352214503Srpaulostatic int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, 353214503Srpaulo char *argv[]) 354214503Srpaulo{ 355214503Srpaulo char buf[64]; 356214503Srpaulo if (argc < 2) { 357214503Srpaulo printf("Invalid 'wps_pin' command - at least two arguments, " 358214503Srpaulo "UUID and PIN, are required.\n"); 359214503Srpaulo return -1; 360214503Srpaulo } 361214503Srpaulo if (argc > 2) 362214503Srpaulo snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s", 363214503Srpaulo argv[0], argv[1], argv[2]); 364214503Srpaulo else 365214503Srpaulo snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]); 366214503Srpaulo return wpa_ctrl_command(ctrl, buf); 367214503Srpaulo} 368214503Srpaulo 369214503Srpaulo 370214503Srpaulostatic int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, 371214503Srpaulo char *argv[]) 372214503Srpaulo{ 373214503Srpaulo return wpa_ctrl_command(ctrl, "WPS_PBC"); 374214503Srpaulo} 375214503Srpaulo 376214503Srpaulo 377214503Srpaulo#ifdef CONFIG_WPS_OOB 378214503Srpaulostatic int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, 379214503Srpaulo char *argv[]) 380214503Srpaulo{ 381214503Srpaulo char cmd[256]; 382214503Srpaulo int res; 383214503Srpaulo 384214503Srpaulo if (argc != 3 && argc != 4) { 385214503Srpaulo printf("Invalid WPS_OOB command: need three or four " 386214503Srpaulo "arguments:\n" 387214503Srpaulo "- DEV_TYPE: use 'ufd' or 'nfc'\n" 388214503Srpaulo "- PATH: path of OOB device like '/mnt'\n" 389214503Srpaulo "- METHOD: OOB method 'pin-e' or 'pin-r', " 390214503Srpaulo "'cred'\n" 391214503Srpaulo "- DEV_NAME: (only for NFC) device name like " 392214503Srpaulo "'pn531'\n"); 393214503Srpaulo return -1; 394214503Srpaulo } 395214503Srpaulo 396214503Srpaulo if (argc == 3) 397214503Srpaulo res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s", 398214503Srpaulo argv[0], argv[1], argv[2]); 399214503Srpaulo else 400214503Srpaulo res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s", 401214503Srpaulo argv[0], argv[1], argv[2], argv[3]); 402214503Srpaulo if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 403214503Srpaulo printf("Too long WPS_OOB command.\n"); 404214503Srpaulo return -1; 405214503Srpaulo } 406214503Srpaulo return wpa_ctrl_command(ctrl, cmd); 407214503Srpaulo} 408214503Srpaulo#endif /* CONFIG_WPS_OOB */ 409214503Srpaulo 410214503Srpaulo 411214503Srpaulostatic int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc, 412214503Srpaulo char *argv[]) 413214503Srpaulo{ 414214503Srpaulo char buf[64]; 415214503Srpaulo if (argc < 1) { 416214503Srpaulo printf("Invalid 'wps_ap_pin' command - at least one argument " 417214503Srpaulo "is required.\n"); 418214503Srpaulo return -1; 419214503Srpaulo } 420214503Srpaulo if (argc > 2) 421214503Srpaulo snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s", 422214503Srpaulo argv[0], argv[1], argv[2]); 423214503Srpaulo else if (argc > 1) 424214503Srpaulo snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s", 425214503Srpaulo argv[0], argv[1]); 426214503Srpaulo else 427214503Srpaulo snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]); 428214503Srpaulo return wpa_ctrl_command(ctrl, buf); 429214503Srpaulo} 430214503Srpaulo#endif /* CONFIG_WPS */ 431214503Srpaulo 432214503Srpaulo 433214503Srpaulostatic int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd, 434214503Srpaulo char *addr, size_t addr_len) 435214503Srpaulo{ 436214503Srpaulo char buf[4096], *pos; 437214503Srpaulo size_t len; 438214503Srpaulo int ret; 439214503Srpaulo 440214503Srpaulo if (ctrl_conn == NULL) { 441214503Srpaulo printf("Not connected to hostapd - command dropped.\n"); 442214503Srpaulo return -1; 443214503Srpaulo } 444214503Srpaulo len = sizeof(buf) - 1; 445214503Srpaulo ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, 446214503Srpaulo hostapd_cli_msg_cb); 447214503Srpaulo if (ret == -2) { 448214503Srpaulo printf("'%s' command timed out.\n", cmd); 449214503Srpaulo return -2; 450214503Srpaulo } else if (ret < 0) { 451214503Srpaulo printf("'%s' command failed.\n", cmd); 452214503Srpaulo return -1; 453214503Srpaulo } 454214503Srpaulo 455214503Srpaulo buf[len] = '\0'; 456214503Srpaulo if (memcmp(buf, "FAIL", 4) == 0) 457214503Srpaulo return -1; 458214503Srpaulo printf("%s", buf); 459214503Srpaulo 460214503Srpaulo pos = buf; 461214503Srpaulo while (*pos != '\0' && *pos != '\n') 462214503Srpaulo pos++; 463214503Srpaulo *pos = '\0'; 464214503Srpaulo os_strlcpy(addr, buf, addr_len); 465214503Srpaulo return 0; 466214503Srpaulo} 467214503Srpaulo 468214503Srpaulo 469214503Srpaulostatic int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, 470214503Srpaulo char *argv[]) 471214503Srpaulo{ 472214503Srpaulo char addr[32], cmd[64]; 473214503Srpaulo 474214503Srpaulo if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr))) 475214503Srpaulo return 0; 476214503Srpaulo do { 477214503Srpaulo snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr); 478214503Srpaulo } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0); 479214503Srpaulo 480214503Srpaulo return -1; 481214503Srpaulo} 482214503Srpaulo 483214503Srpaulo 484214503Srpaulostatic int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[]) 485214503Srpaulo{ 486214503Srpaulo printf("%s", commands_help); 487214503Srpaulo return 0; 488214503Srpaulo} 489214503Srpaulo 490214503Srpaulo 491214503Srpaulostatic int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, 492214503Srpaulo char *argv[]) 493214503Srpaulo{ 494214503Srpaulo printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license); 495214503Srpaulo return 0; 496214503Srpaulo} 497214503Srpaulo 498214503Srpaulo 499214503Srpaulostatic int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[]) 500214503Srpaulo{ 501214503Srpaulo hostapd_cli_quit = 1; 502214503Srpaulo return 0; 503214503Srpaulo} 504214503Srpaulo 505214503Srpaulo 506214503Srpaulostatic int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) 507214503Srpaulo{ 508214503Srpaulo char cmd[256]; 509214503Srpaulo if (argc != 1) { 510214503Srpaulo printf("Invalid LEVEL command: needs one argument (debug " 511214503Srpaulo "level)\n"); 512214503Srpaulo return 0; 513214503Srpaulo } 514214503Srpaulo snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]); 515214503Srpaulo return wpa_ctrl_command(ctrl, cmd); 516214503Srpaulo} 517214503Srpaulo 518214503Srpaulo 519214503Srpaulostatic void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl) 520214503Srpaulo{ 521214503Srpaulo struct dirent *dent; 522214503Srpaulo DIR *dir; 523214503Srpaulo 524214503Srpaulo dir = opendir(ctrl_iface_dir); 525214503Srpaulo if (dir == NULL) { 526214503Srpaulo printf("Control interface directory '%s' could not be " 527214503Srpaulo "openned.\n", ctrl_iface_dir); 528214503Srpaulo return; 529214503Srpaulo } 530214503Srpaulo 531214503Srpaulo printf("Available interfaces:\n"); 532214503Srpaulo while ((dent = readdir(dir))) { 533214503Srpaulo if (strcmp(dent->d_name, ".") == 0 || 534214503Srpaulo strcmp(dent->d_name, "..") == 0) 535214503Srpaulo continue; 536214503Srpaulo printf("%s\n", dent->d_name); 537214503Srpaulo } 538214503Srpaulo closedir(dir); 539214503Srpaulo} 540214503Srpaulo 541214503Srpaulo 542214503Srpaulostatic int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, 543214503Srpaulo char *argv[]) 544214503Srpaulo{ 545214503Srpaulo if (argc < 1) { 546214503Srpaulo hostapd_cli_list_interfaces(ctrl); 547214503Srpaulo return 0; 548214503Srpaulo } 549214503Srpaulo 550214503Srpaulo hostapd_cli_close_connection(); 551214503Srpaulo free(ctrl_ifname); 552214503Srpaulo ctrl_ifname = strdup(argv[0]); 553214503Srpaulo 554214503Srpaulo if (hostapd_cli_open_connection(ctrl_ifname)) { 555214503Srpaulo printf("Connected to interface '%s.\n", ctrl_ifname); 556214503Srpaulo if (wpa_ctrl_attach(ctrl_conn) == 0) { 557214503Srpaulo hostapd_cli_attached = 1; 558214503Srpaulo } else { 559214503Srpaulo printf("Warning: Failed to attach to " 560214503Srpaulo "hostapd.\n"); 561214503Srpaulo } 562214503Srpaulo } else { 563214503Srpaulo printf("Could not connect to interface '%s' - re-trying\n", 564214503Srpaulo ctrl_ifname); 565214503Srpaulo } 566214503Srpaulo return 0; 567214503Srpaulo} 568214503Srpaulo 569214503Srpaulo 570214503Srpaulostruct hostapd_cli_cmd { 571214503Srpaulo const char *cmd; 572214503Srpaulo int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); 573214503Srpaulo}; 574214503Srpaulo 575214503Srpaulostatic struct hostapd_cli_cmd hostapd_cli_commands[] = { 576214503Srpaulo { "ping", hostapd_cli_cmd_ping }, 577214503Srpaulo { "mib", hostapd_cli_cmd_mib }, 578214503Srpaulo { "sta", hostapd_cli_cmd_sta }, 579214503Srpaulo { "all_sta", hostapd_cli_cmd_all_sta }, 580214503Srpaulo { "new_sta", hostapd_cli_cmd_new_sta }, 581214503Srpaulo { "deauthenticate", hostapd_cli_cmd_deauthenticate }, 582214503Srpaulo { "disassociate", hostapd_cli_cmd_disassociate }, 583214503Srpaulo#ifdef CONFIG_IEEE80211W 584214503Srpaulo { "sa_query", hostapd_cli_cmd_sa_query }, 585214503Srpaulo#endif /* CONFIG_IEEE80211W */ 586214503Srpaulo#ifdef CONFIG_WPS 587214503Srpaulo { "wps_pin", hostapd_cli_cmd_wps_pin }, 588214503Srpaulo { "wps_pbc", hostapd_cli_cmd_wps_pbc }, 589214503Srpaulo#ifdef CONFIG_WPS_OOB 590214503Srpaulo { "wps_oob", hostapd_cli_cmd_wps_oob }, 591214503Srpaulo#endif /* CONFIG_WPS_OOB */ 592214503Srpaulo { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin }, 593214503Srpaulo#endif /* CONFIG_WPS */ 594214503Srpaulo { "help", hostapd_cli_cmd_help }, 595214503Srpaulo { "interface", hostapd_cli_cmd_interface }, 596214503Srpaulo { "level", hostapd_cli_cmd_level }, 597214503Srpaulo { "license", hostapd_cli_cmd_license }, 598214503Srpaulo { "quit", hostapd_cli_cmd_quit }, 599214503Srpaulo { NULL, NULL } 600214503Srpaulo}; 601214503Srpaulo 602214503Srpaulo 603214503Srpaulostatic void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) 604214503Srpaulo{ 605214503Srpaulo struct hostapd_cli_cmd *cmd, *match = NULL; 606214503Srpaulo int count; 607214503Srpaulo 608214503Srpaulo count = 0; 609214503Srpaulo cmd = hostapd_cli_commands; 610214503Srpaulo while (cmd->cmd) { 611214503Srpaulo if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) { 612214503Srpaulo match = cmd; 613214503Srpaulo count++; 614214503Srpaulo } 615214503Srpaulo cmd++; 616214503Srpaulo } 617214503Srpaulo 618214503Srpaulo if (count > 1) { 619214503Srpaulo printf("Ambiguous command '%s'; possible commands:", argv[0]); 620214503Srpaulo cmd = hostapd_cli_commands; 621214503Srpaulo while (cmd->cmd) { 622214503Srpaulo if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 623214503Srpaulo 0) { 624214503Srpaulo printf(" %s", cmd->cmd); 625214503Srpaulo } 626214503Srpaulo cmd++; 627214503Srpaulo } 628214503Srpaulo printf("\n"); 629214503Srpaulo } else if (count == 0) { 630214503Srpaulo printf("Unknown command '%s'\n", argv[0]); 631214503Srpaulo } else { 632214503Srpaulo match->handler(ctrl, argc - 1, &argv[1]); 633214503Srpaulo } 634214503Srpaulo} 635214503Srpaulo 636214503Srpaulo 637214503Srpaulostatic void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read, 638214503Srpaulo int action_monitor) 639214503Srpaulo{ 640214503Srpaulo int first = 1; 641214503Srpaulo if (ctrl_conn == NULL) 642214503Srpaulo return; 643214503Srpaulo while (wpa_ctrl_pending(ctrl)) { 644214503Srpaulo char buf[256]; 645214503Srpaulo size_t len = sizeof(buf) - 1; 646214503Srpaulo if (wpa_ctrl_recv(ctrl, buf, &len) == 0) { 647214503Srpaulo buf[len] = '\0'; 648214503Srpaulo if (action_monitor) 649214503Srpaulo hostapd_cli_action_process(buf, len); 650214503Srpaulo else { 651214503Srpaulo if (in_read && first) 652214503Srpaulo printf("\n"); 653214503Srpaulo first = 0; 654214503Srpaulo printf("%s\n", buf); 655214503Srpaulo } 656214503Srpaulo } else { 657214503Srpaulo printf("Could not read pending message.\n"); 658214503Srpaulo break; 659214503Srpaulo } 660214503Srpaulo } 661214503Srpaulo} 662214503Srpaulo 663214503Srpaulo 664214503Srpaulostatic void hostapd_cli_interactive(void) 665214503Srpaulo{ 666214503Srpaulo const int max_args = 10; 667214503Srpaulo char cmd[256], *res, *argv[max_args], *pos; 668214503Srpaulo int argc; 669214503Srpaulo 670214503Srpaulo printf("\nInteractive mode\n\n"); 671214503Srpaulo 672214503Srpaulo do { 673214503Srpaulo hostapd_cli_recv_pending(ctrl_conn, 0, 0); 674214503Srpaulo printf("> "); 675214503Srpaulo alarm(ping_interval); 676214503Srpaulo res = fgets(cmd, sizeof(cmd), stdin); 677214503Srpaulo alarm(0); 678214503Srpaulo if (res == NULL) 679214503Srpaulo break; 680214503Srpaulo pos = cmd; 681214503Srpaulo while (*pos != '\0') { 682214503Srpaulo if (*pos == '\n') { 683214503Srpaulo *pos = '\0'; 684214503Srpaulo break; 685214503Srpaulo } 686214503Srpaulo pos++; 687214503Srpaulo } 688214503Srpaulo argc = 0; 689214503Srpaulo pos = cmd; 690214503Srpaulo for (;;) { 691214503Srpaulo while (*pos == ' ') 692214503Srpaulo pos++; 693214503Srpaulo if (*pos == '\0') 694214503Srpaulo break; 695214503Srpaulo argv[argc] = pos; 696214503Srpaulo argc++; 697214503Srpaulo if (argc == max_args) 698214503Srpaulo break; 699214503Srpaulo while (*pos != '\0' && *pos != ' ') 700214503Srpaulo pos++; 701214503Srpaulo if (*pos == ' ') 702214503Srpaulo *pos++ = '\0'; 703214503Srpaulo } 704214503Srpaulo if (argc) 705214503Srpaulo wpa_request(ctrl_conn, argc, argv); 706214503Srpaulo } while (!hostapd_cli_quit); 707214503Srpaulo} 708214503Srpaulo 709214503Srpaulo 710214503Srpaulostatic void hostapd_cli_cleanup(void) 711214503Srpaulo{ 712214503Srpaulo hostapd_cli_close_connection(); 713214503Srpaulo if (pid_file) 714214503Srpaulo os_daemonize_terminate(pid_file); 715214503Srpaulo 716214503Srpaulo os_program_deinit(); 717214503Srpaulo} 718214503Srpaulo 719214503Srpaulo 720214503Srpaulostatic void hostapd_cli_terminate(int sig) 721214503Srpaulo{ 722214503Srpaulo hostapd_cli_cleanup(); 723214503Srpaulo exit(0); 724214503Srpaulo} 725214503Srpaulo 726214503Srpaulo 727214503Srpaulostatic void hostapd_cli_alarm(int sig) 728214503Srpaulo{ 729214503Srpaulo if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) { 730214503Srpaulo printf("Connection to hostapd lost - trying to reconnect\n"); 731214503Srpaulo hostapd_cli_close_connection(); 732214503Srpaulo } 733214503Srpaulo if (!ctrl_conn) { 734214503Srpaulo ctrl_conn = hostapd_cli_open_connection(ctrl_ifname); 735214503Srpaulo if (ctrl_conn) { 736214503Srpaulo printf("Connection to hostapd re-established\n"); 737214503Srpaulo if (wpa_ctrl_attach(ctrl_conn) == 0) { 738214503Srpaulo hostapd_cli_attached = 1; 739214503Srpaulo } else { 740214503Srpaulo printf("Warning: Failed to attach to " 741214503Srpaulo "hostapd.\n"); 742214503Srpaulo } 743214503Srpaulo } 744214503Srpaulo } 745214503Srpaulo if (ctrl_conn) 746214503Srpaulo hostapd_cli_recv_pending(ctrl_conn, 1, 0); 747214503Srpaulo alarm(ping_interval); 748214503Srpaulo} 749214503Srpaulo 750214503Srpaulo 751214503Srpaulostatic void hostapd_cli_action(struct wpa_ctrl *ctrl) 752214503Srpaulo{ 753214503Srpaulo fd_set rfds; 754214503Srpaulo int fd, res; 755214503Srpaulo struct timeval tv; 756214503Srpaulo char buf[256]; 757214503Srpaulo size_t len; 758214503Srpaulo 759214503Srpaulo fd = wpa_ctrl_get_fd(ctrl); 760214503Srpaulo 761214503Srpaulo while (!hostapd_cli_quit) { 762214503Srpaulo FD_ZERO(&rfds); 763214503Srpaulo FD_SET(fd, &rfds); 764214503Srpaulo tv.tv_sec = ping_interval; 765214503Srpaulo tv.tv_usec = 0; 766214503Srpaulo res = select(fd + 1, &rfds, NULL, NULL, &tv); 767214503Srpaulo if (res < 0 && errno != EINTR) { 768214503Srpaulo perror("select"); 769214503Srpaulo break; 770214503Srpaulo } 771214503Srpaulo 772214503Srpaulo if (FD_ISSET(fd, &rfds)) 773214503Srpaulo hostapd_cli_recv_pending(ctrl, 0, 1); 774214503Srpaulo else { 775214503Srpaulo len = sizeof(buf) - 1; 776214503Srpaulo if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len, 777214503Srpaulo hostapd_cli_action_process) < 0 || 778214503Srpaulo len < 4 || os_memcmp(buf, "PONG", 4) != 0) { 779214503Srpaulo printf("hostapd did not reply to PING " 780214503Srpaulo "command - exiting\n"); 781214503Srpaulo break; 782214503Srpaulo } 783214503Srpaulo } 784214503Srpaulo } 785214503Srpaulo} 786214503Srpaulo 787214503Srpaulo 788214503Srpauloint main(int argc, char *argv[]) 789214503Srpaulo{ 790214503Srpaulo int interactive; 791214503Srpaulo int warning_displayed = 0; 792214503Srpaulo int c; 793214503Srpaulo int daemonize = 0; 794214503Srpaulo 795214503Srpaulo if (os_program_init()) 796214503Srpaulo return -1; 797214503Srpaulo 798214503Srpaulo for (;;) { 799214503Srpaulo c = getopt(argc, argv, "a:BhG:i:p:v"); 800214503Srpaulo if (c < 0) 801214503Srpaulo break; 802214503Srpaulo switch (c) { 803214503Srpaulo case 'a': 804214503Srpaulo action_file = optarg; 805214503Srpaulo break; 806214503Srpaulo case 'B': 807214503Srpaulo daemonize = 1; 808214503Srpaulo break; 809214503Srpaulo case 'G': 810214503Srpaulo ping_interval = atoi(optarg); 811214503Srpaulo break; 812214503Srpaulo case 'h': 813214503Srpaulo usage(); 814214503Srpaulo return 0; 815214503Srpaulo case 'v': 816214503Srpaulo printf("%s\n", hostapd_cli_version); 817214503Srpaulo return 0; 818214503Srpaulo case 'i': 819214503Srpaulo os_free(ctrl_ifname); 820214503Srpaulo ctrl_ifname = os_strdup(optarg); 821214503Srpaulo break; 822214503Srpaulo case 'p': 823214503Srpaulo ctrl_iface_dir = optarg; 824214503Srpaulo break; 825214503Srpaulo default: 826214503Srpaulo usage(); 827214503Srpaulo return -1; 828214503Srpaulo } 829214503Srpaulo } 830214503Srpaulo 831214503Srpaulo interactive = (argc == optind) && (action_file == NULL); 832214503Srpaulo 833214503Srpaulo if (interactive) { 834214503Srpaulo printf("%s\n\n%s\n\n", hostapd_cli_version, 835214503Srpaulo hostapd_cli_license); 836214503Srpaulo } 837214503Srpaulo 838214503Srpaulo for (;;) { 839214503Srpaulo if (ctrl_ifname == NULL) { 840214503Srpaulo struct dirent *dent; 841214503Srpaulo DIR *dir = opendir(ctrl_iface_dir); 842214503Srpaulo if (dir) { 843214503Srpaulo while ((dent = readdir(dir))) { 844214503Srpaulo if (os_strcmp(dent->d_name, ".") == 0 845214503Srpaulo || 846214503Srpaulo os_strcmp(dent->d_name, "..") == 0) 847214503Srpaulo continue; 848214503Srpaulo printf("Selected interface '%s'\n", 849214503Srpaulo dent->d_name); 850214503Srpaulo ctrl_ifname = os_strdup(dent->d_name); 851214503Srpaulo break; 852214503Srpaulo } 853214503Srpaulo closedir(dir); 854214503Srpaulo } 855214503Srpaulo } 856214503Srpaulo ctrl_conn = hostapd_cli_open_connection(ctrl_ifname); 857214503Srpaulo if (ctrl_conn) { 858214503Srpaulo if (warning_displayed) 859214503Srpaulo printf("Connection established.\n"); 860214503Srpaulo break; 861214503Srpaulo } 862214503Srpaulo 863214503Srpaulo if (!interactive) { 864214503Srpaulo perror("Failed to connect to hostapd - " 865214503Srpaulo "wpa_ctrl_open"); 866214503Srpaulo return -1; 867214503Srpaulo } 868214503Srpaulo 869214503Srpaulo if (!warning_displayed) { 870214503Srpaulo printf("Could not connect to hostapd - re-trying\n"); 871214503Srpaulo warning_displayed = 1; 872214503Srpaulo } 873214503Srpaulo os_sleep(1, 0); 874214503Srpaulo continue; 875214503Srpaulo } 876214503Srpaulo 877214503Srpaulo signal(SIGINT, hostapd_cli_terminate); 878214503Srpaulo signal(SIGTERM, hostapd_cli_terminate); 879214503Srpaulo signal(SIGALRM, hostapd_cli_alarm); 880214503Srpaulo 881214503Srpaulo if (interactive || action_file) { 882214503Srpaulo if (wpa_ctrl_attach(ctrl_conn) == 0) { 883214503Srpaulo hostapd_cli_attached = 1; 884214503Srpaulo } else { 885214503Srpaulo printf("Warning: Failed to attach to hostapd.\n"); 886214503Srpaulo if (action_file) 887214503Srpaulo return -1; 888214503Srpaulo } 889214503Srpaulo } 890214503Srpaulo 891214503Srpaulo if (daemonize && os_daemonize(pid_file)) 892214503Srpaulo return -1; 893214503Srpaulo 894214503Srpaulo if (interactive) 895214503Srpaulo hostapd_cli_interactive(); 896214503Srpaulo else if (action_file) 897214503Srpaulo hostapd_cli_action(ctrl_conn); 898214503Srpaulo else 899214503Srpaulo wpa_request(ctrl_conn, argc - optind, &argv[optind]); 900214503Srpaulo 901214503Srpaulo os_free(ctrl_ifname); 902214503Srpaulo hostapd_cli_cleanup(); 903214503Srpaulo return 0; 904214503Srpaulo} 905