wpa_cli.c revision 189251
1189251Ssam/* 2189251Ssam * WPA Supplicant - command line interface for wpa_supplicant daemon 3189251Ssam * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> 4189251Ssam * 5189251Ssam * This program is free software; you can redistribute it and/or modify 6189251Ssam * it under the terms of the GNU General Public License version 2 as 7189251Ssam * published by the Free Software Foundation. 8189251Ssam * 9189251Ssam * Alternatively, this software may be distributed under the terms of BSD 10189251Ssam * license. 11189251Ssam * 12189251Ssam * See README and COPYING for more details. 13189251Ssam */ 14189251Ssam 15189251Ssam#include "includes.h" 16189251Ssam 17189251Ssam#ifdef CONFIG_CTRL_IFACE 18189251Ssam 19189251Ssam#ifdef CONFIG_CTRL_IFACE_UNIX 20189251Ssam#include <dirent.h> 21189251Ssam#endif /* CONFIG_CTRL_IFACE_UNIX */ 22189251Ssam#ifdef CONFIG_READLINE 23189251Ssam#include <readline/readline.h> 24189251Ssam#include <readline/history.h> 25189251Ssam#endif /* CONFIG_READLINE */ 26189251Ssam 27189251Ssam#include "wpa_ctrl.h" 28189251Ssam#include "common.h" 29189251Ssam#include "version.h" 30189251Ssam 31189251Ssam 32189251Ssamstatic const char *wpa_cli_version = 33189251Ssam"wpa_cli v" VERSION_STR "\n" 34189251Ssam"Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> and contributors"; 35189251Ssam 36189251Ssam 37189251Ssamstatic const char *wpa_cli_license = 38189251Ssam"This program is free software. You can distribute it and/or modify it\n" 39189251Ssam"under the terms of the GNU General Public License version 2.\n" 40189251Ssam"\n" 41189251Ssam"Alternatively, this software may be distributed under the terms of the\n" 42189251Ssam"BSD license. See README and COPYING for more details.\n"; 43189251Ssam 44189251Ssamstatic const char *wpa_cli_full_license = 45189251Ssam"This program is free software; you can redistribute it and/or modify\n" 46189251Ssam"it under the terms of the GNU General Public License version 2 as\n" 47189251Ssam"published by the Free Software Foundation.\n" 48189251Ssam"\n" 49189251Ssam"This program is distributed in the hope that it will be useful,\n" 50189251Ssam"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" 51189251Ssam"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" 52189251Ssam"GNU General Public License for more details.\n" 53189251Ssam"\n" 54189251Ssam"You should have received a copy of the GNU General Public License\n" 55189251Ssam"along with this program; if not, write to the Free Software\n" 56189251Ssam"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n" 57189251Ssam"\n" 58189251Ssam"Alternatively, this software may be distributed under the terms of the\n" 59189251Ssam"BSD license.\n" 60189251Ssam"\n" 61189251Ssam"Redistribution and use in source and binary forms, with or without\n" 62189251Ssam"modification, are permitted provided that the following conditions are\n" 63189251Ssam"met:\n" 64189251Ssam"\n" 65189251Ssam"1. Redistributions of source code must retain the above copyright\n" 66189251Ssam" notice, this list of conditions and the following disclaimer.\n" 67189251Ssam"\n" 68189251Ssam"2. Redistributions in binary form must reproduce the above copyright\n" 69189251Ssam" notice, this list of conditions and the following disclaimer in the\n" 70189251Ssam" documentation and/or other materials provided with the distribution.\n" 71189251Ssam"\n" 72189251Ssam"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n" 73189251Ssam" names of its contributors may be used to endorse or promote products\n" 74189251Ssam" derived from this software without specific prior written permission.\n" 75189251Ssam"\n" 76189251Ssam"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n" 77189251Ssam"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n" 78189251Ssam"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n" 79189251Ssam"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n" 80189251Ssam"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n" 81189251Ssam"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n" 82189251Ssam"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n" 83189251Ssam"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" 84189251Ssam"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" 85189251Ssam"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n" 86189251Ssam"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" 87189251Ssam"\n"; 88189251Ssam 89189251Ssamstatic struct wpa_ctrl *ctrl_conn; 90189251Ssamstatic int wpa_cli_quit = 0; 91189251Ssamstatic int wpa_cli_attached = 0; 92189251Ssamstatic int wpa_cli_connected = 0; 93189251Ssamstatic int wpa_cli_last_id = 0; 94189251Ssamstatic const char *ctrl_iface_dir = "/var/run/wpa_supplicant"; 95189251Ssamstatic char *ctrl_ifname = NULL; 96189251Ssamstatic const char *pid_file = NULL; 97189251Ssamstatic const char *action_file = NULL; 98189251Ssamstatic int ping_interval = 5; 99189251Ssam 100189251Ssam 101189251Ssamstatic void print_help(); 102189251Ssam 103189251Ssam 104189251Ssamstatic void usage(void) 105189251Ssam{ 106189251Ssam printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] " 107189251Ssam "[-a<action file>] \\\n" 108189251Ssam " [-P<pid file>] [-g<global ctrl>] [-G<ping interval>] " 109189251Ssam "[command..]\n" 110189251Ssam " -h = help (show this usage text)\n" 111189251Ssam " -v = shown version information\n" 112189251Ssam " -a = run in daemon mode executing the action file based on " 113189251Ssam "events from\n" 114189251Ssam " wpa_supplicant\n" 115189251Ssam " -B = run a daemon in the background\n" 116189251Ssam " default path: /var/run/wpa_supplicant\n" 117189251Ssam " default interface: first interface found in socket path\n"); 118189251Ssam print_help(); 119189251Ssam} 120189251Ssam 121189251Ssam 122189251Ssamstatic struct wpa_ctrl * wpa_cli_open_connection(const char *ifname) 123189251Ssam{ 124189251Ssam#if defined(CONFIG_CTRL_IFACE_UDP) || defined(CONFIG_CTRL_IFACE_NAMED_PIPE) 125189251Ssam ctrl_conn = wpa_ctrl_open(ifname); 126189251Ssam return ctrl_conn; 127189251Ssam#else /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */ 128189251Ssam char *cfile; 129189251Ssam int flen, res; 130189251Ssam 131189251Ssam if (ifname == NULL) 132189251Ssam return NULL; 133189251Ssam 134189251Ssam flen = os_strlen(ctrl_iface_dir) + os_strlen(ifname) + 2; 135189251Ssam cfile = os_malloc(flen); 136189251Ssam if (cfile == NULL) 137189251Ssam return NULL; 138189251Ssam res = os_snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname); 139189251Ssam if (res < 0 || res >= flen) { 140189251Ssam os_free(cfile); 141189251Ssam return NULL; 142189251Ssam } 143189251Ssam 144189251Ssam ctrl_conn = wpa_ctrl_open(cfile); 145189251Ssam os_free(cfile); 146189251Ssam return ctrl_conn; 147189251Ssam#endif /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */ 148189251Ssam} 149189251Ssam 150189251Ssam 151189251Ssamstatic void wpa_cli_close_connection(void) 152189251Ssam{ 153189251Ssam if (ctrl_conn == NULL) 154189251Ssam return; 155189251Ssam 156189251Ssam if (wpa_cli_attached) { 157189251Ssam wpa_ctrl_detach(ctrl_conn); 158189251Ssam wpa_cli_attached = 0; 159189251Ssam } 160189251Ssam wpa_ctrl_close(ctrl_conn); 161189251Ssam ctrl_conn = NULL; 162189251Ssam} 163189251Ssam 164189251Ssam 165189251Ssamstatic void wpa_cli_msg_cb(char *msg, size_t len) 166189251Ssam{ 167189251Ssam printf("%s\n", msg); 168189251Ssam} 169189251Ssam 170189251Ssam 171189251Ssamstatic int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print) 172189251Ssam{ 173189251Ssam char buf[2048]; 174189251Ssam size_t len; 175189251Ssam int ret; 176189251Ssam 177189251Ssam if (ctrl_conn == NULL) { 178189251Ssam printf("Not connected to wpa_supplicant - command dropped.\n"); 179189251Ssam return -1; 180189251Ssam } 181189251Ssam len = sizeof(buf) - 1; 182189251Ssam ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, 183189251Ssam wpa_cli_msg_cb); 184189251Ssam if (ret == -2) { 185189251Ssam printf("'%s' command timed out.\n", cmd); 186189251Ssam return -2; 187189251Ssam } else if (ret < 0) { 188189251Ssam printf("'%s' command failed.\n", cmd); 189189251Ssam return -1; 190189251Ssam } 191189251Ssam if (print) { 192189251Ssam buf[len] = '\0'; 193189251Ssam printf("%s", buf); 194189251Ssam } 195189251Ssam return 0; 196189251Ssam} 197189251Ssam 198189251Ssam 199189251Ssamstatic int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd) 200189251Ssam{ 201189251Ssam return _wpa_ctrl_command(ctrl, cmd, 1); 202189251Ssam} 203189251Ssam 204189251Ssam 205189251Ssamstatic int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[]) 206189251Ssam{ 207189251Ssam int verbose = argc > 0 && os_strcmp(argv[0], "verbose") == 0; 208189251Ssam return wpa_ctrl_command(ctrl, verbose ? "STATUS-VERBOSE" : "STATUS"); 209189251Ssam} 210189251Ssam 211189251Ssam 212189251Ssamstatic int wpa_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[]) 213189251Ssam{ 214189251Ssam return wpa_ctrl_command(ctrl, "PING"); 215189251Ssam} 216189251Ssam 217189251Ssam 218189251Ssamstatic int wpa_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[]) 219189251Ssam{ 220189251Ssam return wpa_ctrl_command(ctrl, "MIB"); 221189251Ssam} 222189251Ssam 223189251Ssam 224189251Ssamstatic int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[]) 225189251Ssam{ 226189251Ssam return wpa_ctrl_command(ctrl, "PMKSA"); 227189251Ssam} 228189251Ssam 229189251Ssam 230189251Ssamstatic int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[]) 231189251Ssam{ 232189251Ssam print_help(); 233189251Ssam return 0; 234189251Ssam} 235189251Ssam 236189251Ssam 237189251Ssamstatic int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[]) 238189251Ssam{ 239189251Ssam printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license); 240189251Ssam return 0; 241189251Ssam} 242189251Ssam 243189251Ssam 244189251Ssamstatic int wpa_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[]) 245189251Ssam{ 246189251Ssam wpa_cli_quit = 1; 247189251Ssam return 0; 248189251Ssam} 249189251Ssam 250189251Ssam 251189251Ssamstatic void wpa_cli_show_variables(void) 252189251Ssam{ 253189251Ssam printf("set variables:\n" 254189251Ssam " EAPOL::heldPeriod (EAPOL state machine held period, " 255189251Ssam "in seconds)\n" 256189251Ssam " EAPOL::authPeriod (EAPOL state machine authentication " 257189251Ssam "period, in seconds)\n" 258189251Ssam " EAPOL::startPeriod (EAPOL state machine start period, in " 259189251Ssam "seconds)\n" 260189251Ssam " EAPOL::maxStart (EAPOL state machine maximum start " 261189251Ssam "attempts)\n"); 262189251Ssam printf(" dot11RSNAConfigPMKLifetime (WPA/WPA2 PMK lifetime in " 263189251Ssam "seconds)\n" 264189251Ssam " dot11RSNAConfigPMKReauthThreshold (WPA/WPA2 reauthentication" 265189251Ssam " threshold\n\tpercentage)\n" 266189251Ssam " dot11RSNAConfigSATimeout (WPA/WPA2 timeout for completing " 267189251Ssam "security\n\tassociation in seconds)\n"); 268189251Ssam} 269189251Ssam 270189251Ssam 271189251Ssamstatic int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) 272189251Ssam{ 273189251Ssam char cmd[256]; 274189251Ssam int res; 275189251Ssam 276189251Ssam if (argc == 0) { 277189251Ssam wpa_cli_show_variables(); 278189251Ssam return 0; 279189251Ssam } 280189251Ssam 281189251Ssam if (argc != 2) { 282189251Ssam printf("Invalid SET command: needs two arguments (variable " 283189251Ssam "name and value)\n"); 284189251Ssam return -1; 285189251Ssam } 286189251Ssam 287189251Ssam res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]); 288189251Ssam if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 289189251Ssam printf("Too long SET command.\n"); 290189251Ssam return -1; 291189251Ssam } 292189251Ssam return wpa_ctrl_command(ctrl, cmd); 293189251Ssam} 294189251Ssam 295189251Ssam 296189251Ssamstatic int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[]) 297189251Ssam{ 298189251Ssam return wpa_ctrl_command(ctrl, "LOGOFF"); 299189251Ssam} 300189251Ssam 301189251Ssam 302189251Ssamstatic int wpa_cli_cmd_logon(struct wpa_ctrl *ctrl, int argc, char *argv[]) 303189251Ssam{ 304189251Ssam return wpa_ctrl_command(ctrl, "LOGON"); 305189251Ssam} 306189251Ssam 307189251Ssam 308189251Ssamstatic int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc, 309189251Ssam char *argv[]) 310189251Ssam{ 311189251Ssam return wpa_ctrl_command(ctrl, "REASSOCIATE"); 312189251Ssam} 313189251Ssam 314189251Ssam 315189251Ssamstatic int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc, 316189251Ssam char *argv[]) 317189251Ssam{ 318189251Ssam char cmd[256]; 319189251Ssam int res; 320189251Ssam 321189251Ssam if (argc != 1) { 322189251Ssam printf("Invalid PREAUTH command: needs one argument " 323189251Ssam "(BSSID)\n"); 324189251Ssam return -1; 325189251Ssam } 326189251Ssam 327189251Ssam res = os_snprintf(cmd, sizeof(cmd), "PREAUTH %s", argv[0]); 328189251Ssam if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 329189251Ssam printf("Too long PREAUTH command.\n"); 330189251Ssam return -1; 331189251Ssam } 332189251Ssam return wpa_ctrl_command(ctrl, cmd); 333189251Ssam} 334189251Ssam 335189251Ssam 336189251Ssamstatic int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *argv[]) 337189251Ssam{ 338189251Ssam char cmd[256]; 339189251Ssam int res; 340189251Ssam 341189251Ssam if (argc != 1) { 342189251Ssam printf("Invalid AP_SCAN command: needs one argument (ap_scan " 343189251Ssam "value)\n"); 344189251Ssam return -1; 345189251Ssam } 346189251Ssam res = os_snprintf(cmd, sizeof(cmd), "AP_SCAN %s", argv[0]); 347189251Ssam if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 348189251Ssam printf("Too long AP_SCAN command.\n"); 349189251Ssam return -1; 350189251Ssam } 351189251Ssam return wpa_ctrl_command(ctrl, cmd); 352189251Ssam} 353189251Ssam 354189251Ssam 355189251Ssamstatic int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc, 356189251Ssam char *argv[]) 357189251Ssam{ 358189251Ssam char cmd[256]; 359189251Ssam int res; 360189251Ssam 361189251Ssam if (argc != 1) { 362189251Ssam printf("Invalid STKSTART command: needs one argument " 363189251Ssam "(Peer STA MAC address)\n"); 364189251Ssam return -1; 365189251Ssam } 366189251Ssam 367189251Ssam res = os_snprintf(cmd, sizeof(cmd), "STKSTART %s", argv[0]); 368189251Ssam if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 369189251Ssam printf("Too long STKSTART command.\n"); 370189251Ssam return -1; 371189251Ssam } 372189251Ssam return wpa_ctrl_command(ctrl, cmd); 373189251Ssam} 374189251Ssam 375189251Ssam 376189251Ssamstatic int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[]) 377189251Ssam{ 378189251Ssam char cmd[256]; 379189251Ssam int res; 380189251Ssam 381189251Ssam if (argc != 1) { 382189251Ssam printf("Invalid FT_DS command: needs one argument " 383189251Ssam "(Target AP MAC address)\n"); 384189251Ssam return -1; 385189251Ssam } 386189251Ssam 387189251Ssam res = os_snprintf(cmd, sizeof(cmd), "FT_DS %s", argv[0]); 388189251Ssam if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 389189251Ssam printf("Too long FT_DS command.\n"); 390189251Ssam return -1; 391189251Ssam } 392189251Ssam return wpa_ctrl_command(ctrl, cmd); 393189251Ssam} 394189251Ssam 395189251Ssam 396189251Ssamstatic int wpa_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[]) 397189251Ssam{ 398189251Ssam char cmd[256]; 399189251Ssam int res; 400189251Ssam 401189251Ssam if (argc == 0) { 402189251Ssam /* Any BSSID */ 403189251Ssam return wpa_ctrl_command(ctrl, "WPS_PBC"); 404189251Ssam } 405189251Ssam 406189251Ssam /* Specific BSSID */ 407189251Ssam res = os_snprintf(cmd, sizeof(cmd), "WPS_PBC %s", argv[0]); 408189251Ssam if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 409189251Ssam printf("Too long WPS_PBC command.\n"); 410189251Ssam return -1; 411189251Ssam } 412189251Ssam return wpa_ctrl_command(ctrl, cmd); 413189251Ssam} 414189251Ssam 415189251Ssam 416189251Ssamstatic int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) 417189251Ssam{ 418189251Ssam char cmd[256]; 419189251Ssam int res; 420189251Ssam 421189251Ssam if (argc == 0) { 422189251Ssam printf("Invalid WPS_PIN command: need one or two arguments:\n" 423189251Ssam "- BSSID: use 'any' to select any\n" 424189251Ssam "- PIN: optional, used only with devices that have no " 425189251Ssam "display\n"); 426189251Ssam return -1; 427189251Ssam } 428189251Ssam 429189251Ssam if (argc == 1) { 430189251Ssam /* Use dynamically generated PIN (returned as reply) */ 431189251Ssam res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s", argv[0]); 432189251Ssam if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 433189251Ssam printf("Too long WPS_PIN command.\n"); 434189251Ssam return -1; 435189251Ssam } 436189251Ssam return wpa_ctrl_command(ctrl, cmd); 437189251Ssam } 438189251Ssam 439189251Ssam /* Use hardcoded PIN from a label */ 440189251Ssam res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s", argv[0], argv[1]); 441189251Ssam if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 442189251Ssam printf("Too long WPS_PIN command.\n"); 443189251Ssam return -1; 444189251Ssam } 445189251Ssam return wpa_ctrl_command(ctrl, cmd); 446189251Ssam} 447189251Ssam 448189251Ssam 449189251Ssamstatic int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[]) 450189251Ssam{ 451189251Ssam char cmd[256]; 452189251Ssam int res; 453189251Ssam 454189251Ssam if (argc != 2) { 455189251Ssam printf("Invalid WPS_REG command: need two arguments:\n" 456189251Ssam "- BSSID: use 'any' to select any\n" 457189251Ssam "- AP PIN\n"); 458189251Ssam return -1; 459189251Ssam } 460189251Ssam 461189251Ssam res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s", argv[0], argv[1]); 462189251Ssam if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 463189251Ssam printf("Too long WPS_REG command.\n"); 464189251Ssam return -1; 465189251Ssam } 466189251Ssam return wpa_ctrl_command(ctrl, cmd); 467189251Ssam} 468189251Ssam 469189251Ssam 470189251Ssamstatic int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) 471189251Ssam{ 472189251Ssam char cmd[256]; 473189251Ssam int res; 474189251Ssam 475189251Ssam if (argc != 1) { 476189251Ssam printf("Invalid LEVEL command: needs one argument (debug " 477189251Ssam "level)\n"); 478189251Ssam return -1; 479189251Ssam } 480189251Ssam res = os_snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]); 481189251Ssam if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 482189251Ssam printf("Too long LEVEL command.\n"); 483189251Ssam return -1; 484189251Ssam } 485189251Ssam return wpa_ctrl_command(ctrl, cmd); 486189251Ssam} 487189251Ssam 488189251Ssam 489189251Ssamstatic int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[]) 490189251Ssam{ 491189251Ssam char cmd[256], *pos, *end; 492189251Ssam int i, ret; 493189251Ssam 494189251Ssam if (argc < 2) { 495189251Ssam printf("Invalid IDENTITY command: needs two arguments " 496189251Ssam "(network id and identity)\n"); 497189251Ssam return -1; 498189251Ssam } 499189251Ssam 500189251Ssam end = cmd + sizeof(cmd); 501189251Ssam pos = cmd; 502189251Ssam ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s", 503189251Ssam argv[0], argv[1]); 504189251Ssam if (ret < 0 || ret >= end - pos) { 505189251Ssam printf("Too long IDENTITY command.\n"); 506189251Ssam return -1; 507189251Ssam } 508189251Ssam pos += ret; 509189251Ssam for (i = 2; i < argc; i++) { 510189251Ssam ret = os_snprintf(pos, end - pos, " %s", argv[i]); 511189251Ssam if (ret < 0 || ret >= end - pos) { 512189251Ssam printf("Too long IDENTITY command.\n"); 513189251Ssam return -1; 514189251Ssam } 515189251Ssam pos += ret; 516189251Ssam } 517189251Ssam 518189251Ssam return wpa_ctrl_command(ctrl, cmd); 519189251Ssam} 520189251Ssam 521189251Ssam 522189251Ssamstatic int wpa_cli_cmd_password(struct wpa_ctrl *ctrl, int argc, char *argv[]) 523189251Ssam{ 524189251Ssam char cmd[256], *pos, *end; 525189251Ssam int i, ret; 526189251Ssam 527189251Ssam if (argc < 2) { 528189251Ssam printf("Invalid PASSWORD command: needs two arguments " 529189251Ssam "(network id and password)\n"); 530189251Ssam return -1; 531189251Ssam } 532189251Ssam 533189251Ssam end = cmd + sizeof(cmd); 534189251Ssam pos = cmd; 535189251Ssam ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s", 536189251Ssam argv[0], argv[1]); 537189251Ssam if (ret < 0 || ret >= end - pos) { 538189251Ssam printf("Too long PASSWORD command.\n"); 539189251Ssam return -1; 540189251Ssam } 541189251Ssam pos += ret; 542189251Ssam for (i = 2; i < argc; i++) { 543189251Ssam ret = os_snprintf(pos, end - pos, " %s", argv[i]); 544189251Ssam if (ret < 0 || ret >= end - pos) { 545189251Ssam printf("Too long PASSWORD command.\n"); 546189251Ssam return -1; 547189251Ssam } 548189251Ssam pos += ret; 549189251Ssam } 550189251Ssam 551189251Ssam return wpa_ctrl_command(ctrl, cmd); 552189251Ssam} 553189251Ssam 554189251Ssam 555189251Ssamstatic int wpa_cli_cmd_new_password(struct wpa_ctrl *ctrl, int argc, 556189251Ssam char *argv[]) 557189251Ssam{ 558189251Ssam char cmd[256], *pos, *end; 559189251Ssam int i, ret; 560189251Ssam 561189251Ssam if (argc < 2) { 562189251Ssam printf("Invalid NEW_PASSWORD command: needs two arguments " 563189251Ssam "(network id and password)\n"); 564189251Ssam return -1; 565189251Ssam } 566189251Ssam 567189251Ssam end = cmd + sizeof(cmd); 568189251Ssam pos = cmd; 569189251Ssam ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s", 570189251Ssam argv[0], argv[1]); 571189251Ssam if (ret < 0 || ret >= end - pos) { 572189251Ssam printf("Too long NEW_PASSWORD command.\n"); 573189251Ssam return -1; 574189251Ssam } 575189251Ssam pos += ret; 576189251Ssam for (i = 2; i < argc; i++) { 577189251Ssam ret = os_snprintf(pos, end - pos, " %s", argv[i]); 578189251Ssam if (ret < 0 || ret >= end - pos) { 579189251Ssam printf("Too long NEW_PASSWORD command.\n"); 580189251Ssam return -1; 581189251Ssam } 582189251Ssam pos += ret; 583189251Ssam } 584189251Ssam 585189251Ssam return wpa_ctrl_command(ctrl, cmd); 586189251Ssam} 587189251Ssam 588189251Ssam 589189251Ssamstatic int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) 590189251Ssam{ 591189251Ssam char cmd[256], *pos, *end; 592189251Ssam int i, ret; 593189251Ssam 594189251Ssam if (argc < 2) { 595189251Ssam printf("Invalid PIN command: needs two arguments " 596189251Ssam "(network id and pin)\n"); 597189251Ssam return -1; 598189251Ssam } 599189251Ssam 600189251Ssam end = cmd + sizeof(cmd); 601189251Ssam pos = cmd; 602189251Ssam ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s", 603189251Ssam argv[0], argv[1]); 604189251Ssam if (ret < 0 || ret >= end - pos) { 605189251Ssam printf("Too long PIN command.\n"); 606189251Ssam return -1; 607189251Ssam } 608189251Ssam pos += ret; 609189251Ssam for (i = 2; i < argc; i++) { 610189251Ssam ret = os_snprintf(pos, end - pos, " %s", argv[i]); 611189251Ssam if (ret < 0 || ret >= end - pos) { 612189251Ssam printf("Too long PIN command.\n"); 613189251Ssam return -1; 614189251Ssam } 615189251Ssam pos += ret; 616189251Ssam } 617189251Ssam return wpa_ctrl_command(ctrl, cmd); 618189251Ssam} 619189251Ssam 620189251Ssam 621189251Ssamstatic int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[]) 622189251Ssam{ 623189251Ssam char cmd[256], *pos, *end; 624189251Ssam int i, ret; 625189251Ssam 626189251Ssam if (argc < 2) { 627189251Ssam printf("Invalid OTP command: needs two arguments (network " 628189251Ssam "id and password)\n"); 629189251Ssam return -1; 630189251Ssam } 631189251Ssam 632189251Ssam end = cmd + sizeof(cmd); 633189251Ssam pos = cmd; 634189251Ssam ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s", 635189251Ssam argv[0], argv[1]); 636189251Ssam if (ret < 0 || ret >= end - pos) { 637189251Ssam printf("Too long OTP command.\n"); 638189251Ssam return -1; 639189251Ssam } 640189251Ssam pos += ret; 641189251Ssam for (i = 2; i < argc; i++) { 642189251Ssam ret = os_snprintf(pos, end - pos, " %s", argv[i]); 643189251Ssam if (ret < 0 || ret >= end - pos) { 644189251Ssam printf("Too long OTP command.\n"); 645189251Ssam return -1; 646189251Ssam } 647189251Ssam pos += ret; 648189251Ssam } 649189251Ssam 650189251Ssam return wpa_ctrl_command(ctrl, cmd); 651189251Ssam} 652189251Ssam 653189251Ssam 654189251Ssamstatic int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc, 655189251Ssam char *argv[]) 656189251Ssam{ 657189251Ssam char cmd[256], *pos, *end; 658189251Ssam int i, ret; 659189251Ssam 660189251Ssam if (argc < 2) { 661189251Ssam printf("Invalid PASSPHRASE command: needs two arguments " 662189251Ssam "(network id and passphrase)\n"); 663189251Ssam return -1; 664189251Ssam } 665189251Ssam 666189251Ssam end = cmd + sizeof(cmd); 667189251Ssam pos = cmd; 668189251Ssam ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s", 669189251Ssam argv[0], argv[1]); 670189251Ssam if (ret < 0 || ret >= end - pos) { 671189251Ssam printf("Too long PASSPHRASE command.\n"); 672189251Ssam return -1; 673189251Ssam } 674189251Ssam pos += ret; 675189251Ssam for (i = 2; i < argc; i++) { 676189251Ssam ret = os_snprintf(pos, end - pos, " %s", argv[i]); 677189251Ssam if (ret < 0 || ret >= end - pos) { 678189251Ssam printf("Too long PASSPHRASE command.\n"); 679189251Ssam return -1; 680189251Ssam } 681189251Ssam pos += ret; 682189251Ssam } 683189251Ssam 684189251Ssam return wpa_ctrl_command(ctrl, cmd); 685189251Ssam} 686189251Ssam 687189251Ssam 688189251Ssamstatic int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[]) 689189251Ssam{ 690189251Ssam char cmd[256], *pos, *end; 691189251Ssam int i, ret; 692189251Ssam 693189251Ssam if (argc < 2) { 694189251Ssam printf("Invalid BSSID command: needs two arguments (network " 695189251Ssam "id and BSSID)\n"); 696189251Ssam return -1; 697189251Ssam } 698189251Ssam 699189251Ssam end = cmd + sizeof(cmd); 700189251Ssam pos = cmd; 701189251Ssam ret = os_snprintf(pos, end - pos, "BSSID"); 702189251Ssam if (ret < 0 || ret >= end - pos) { 703189251Ssam printf("Too long BSSID command.\n"); 704189251Ssam return -1; 705189251Ssam } 706189251Ssam pos += ret; 707189251Ssam for (i = 0; i < argc; i++) { 708189251Ssam ret = os_snprintf(pos, end - pos, " %s", argv[i]); 709189251Ssam if (ret < 0 || ret >= end - pos) { 710189251Ssam printf("Too long BSSID command.\n"); 711189251Ssam return -1; 712189251Ssam } 713189251Ssam pos += ret; 714189251Ssam } 715189251Ssam 716189251Ssam return wpa_ctrl_command(ctrl, cmd); 717189251Ssam} 718189251Ssam 719189251Ssam 720189251Ssamstatic int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc, 721189251Ssam char *argv[]) 722189251Ssam{ 723189251Ssam return wpa_ctrl_command(ctrl, "LIST_NETWORKS"); 724189251Ssam} 725189251Ssam 726189251Ssam 727189251Ssamstatic int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc, 728189251Ssam char *argv[]) 729189251Ssam{ 730189251Ssam char cmd[32]; 731189251Ssam int res; 732189251Ssam 733189251Ssam if (argc < 1) { 734189251Ssam printf("Invalid SELECT_NETWORK command: needs one argument " 735189251Ssam "(network id)\n"); 736189251Ssam return -1; 737189251Ssam } 738189251Ssam 739189251Ssam res = os_snprintf(cmd, sizeof(cmd), "SELECT_NETWORK %s", argv[0]); 740189251Ssam if (res < 0 || (size_t) res >= sizeof(cmd)) 741189251Ssam return -1; 742189251Ssam cmd[sizeof(cmd) - 1] = '\0'; 743189251Ssam 744189251Ssam return wpa_ctrl_command(ctrl, cmd); 745189251Ssam} 746189251Ssam 747189251Ssam 748189251Ssamstatic int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc, 749189251Ssam char *argv[]) 750189251Ssam{ 751189251Ssam char cmd[32]; 752189251Ssam int res; 753189251Ssam 754189251Ssam if (argc < 1) { 755189251Ssam printf("Invalid ENABLE_NETWORK command: needs one argument " 756189251Ssam "(network id)\n"); 757189251Ssam return -1; 758189251Ssam } 759189251Ssam 760189251Ssam res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s", argv[0]); 761189251Ssam if (res < 0 || (size_t) res >= sizeof(cmd)) 762189251Ssam return -1; 763189251Ssam cmd[sizeof(cmd) - 1] = '\0'; 764189251Ssam 765189251Ssam return wpa_ctrl_command(ctrl, cmd); 766189251Ssam} 767189251Ssam 768189251Ssam 769189251Ssamstatic int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc, 770189251Ssam char *argv[]) 771189251Ssam{ 772189251Ssam char cmd[32]; 773189251Ssam int res; 774189251Ssam 775189251Ssam if (argc < 1) { 776189251Ssam printf("Invalid DISABLE_NETWORK command: needs one argument " 777189251Ssam "(network id)\n"); 778189251Ssam return -1; 779189251Ssam } 780189251Ssam 781189251Ssam res = os_snprintf(cmd, sizeof(cmd), "DISABLE_NETWORK %s", argv[0]); 782189251Ssam if (res < 0 || (size_t) res >= sizeof(cmd)) 783189251Ssam return -1; 784189251Ssam cmd[sizeof(cmd) - 1] = '\0'; 785189251Ssam 786189251Ssam return wpa_ctrl_command(ctrl, cmd); 787189251Ssam} 788189251Ssam 789189251Ssam 790189251Ssamstatic int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc, 791189251Ssam char *argv[]) 792189251Ssam{ 793189251Ssam return wpa_ctrl_command(ctrl, "ADD_NETWORK"); 794189251Ssam} 795189251Ssam 796189251Ssam 797189251Ssamstatic int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc, 798189251Ssam char *argv[]) 799189251Ssam{ 800189251Ssam char cmd[32]; 801189251Ssam int res; 802189251Ssam 803189251Ssam if (argc < 1) { 804189251Ssam printf("Invalid REMOVE_NETWORK command: needs one argument " 805189251Ssam "(network id)\n"); 806189251Ssam return -1; 807189251Ssam } 808189251Ssam 809189251Ssam res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %s", argv[0]); 810189251Ssam if (res < 0 || (size_t) res >= sizeof(cmd)) 811189251Ssam return -1; 812189251Ssam cmd[sizeof(cmd) - 1] = '\0'; 813189251Ssam 814189251Ssam return wpa_ctrl_command(ctrl, cmd); 815189251Ssam} 816189251Ssam 817189251Ssam 818189251Ssamstatic void wpa_cli_show_network_variables(void) 819189251Ssam{ 820189251Ssam printf("set_network variables:\n" 821189251Ssam " ssid (network name, SSID)\n" 822189251Ssam " psk (WPA passphrase or pre-shared key)\n" 823189251Ssam " key_mgmt (key management protocol)\n" 824189251Ssam " identity (EAP identity)\n" 825189251Ssam " password (EAP password)\n" 826189251Ssam " ...\n" 827189251Ssam "\n" 828189251Ssam "Note: Values are entered in the same format as the " 829189251Ssam "configuration file is using,\n" 830189251Ssam "i.e., strings values need to be inside double quotation " 831189251Ssam "marks.\n" 832189251Ssam "For example: set_network 1 ssid \"network name\"\n" 833189251Ssam "\n" 834189251Ssam "Please see wpa_supplicant.conf documentation for full list " 835189251Ssam "of\navailable variables.\n"); 836189251Ssam} 837189251Ssam 838189251Ssam 839189251Ssamstatic int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc, 840189251Ssam char *argv[]) 841189251Ssam{ 842189251Ssam char cmd[256]; 843189251Ssam int res; 844189251Ssam 845189251Ssam if (argc == 0) { 846189251Ssam wpa_cli_show_network_variables(); 847189251Ssam return 0; 848189251Ssam } 849189251Ssam 850189251Ssam if (argc != 3) { 851189251Ssam printf("Invalid SET_NETWORK command: needs three arguments\n" 852189251Ssam "(network id, variable name, and value)\n"); 853189251Ssam return -1; 854189251Ssam } 855189251Ssam 856189251Ssam res = os_snprintf(cmd, sizeof(cmd), "SET_NETWORK %s %s %s", 857189251Ssam argv[0], argv[1], argv[2]); 858189251Ssam if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 859189251Ssam printf("Too long SET_NETWORK command.\n"); 860189251Ssam return -1; 861189251Ssam } 862189251Ssam return wpa_ctrl_command(ctrl, cmd); 863189251Ssam} 864189251Ssam 865189251Ssam 866189251Ssamstatic int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc, 867189251Ssam char *argv[]) 868189251Ssam{ 869189251Ssam char cmd[256]; 870189251Ssam int res; 871189251Ssam 872189251Ssam if (argc == 0) { 873189251Ssam wpa_cli_show_network_variables(); 874189251Ssam return 0; 875189251Ssam } 876189251Ssam 877189251Ssam if (argc != 2) { 878189251Ssam printf("Invalid GET_NETWORK command: needs two arguments\n" 879189251Ssam "(network id and variable name)\n"); 880189251Ssam return -1; 881189251Ssam } 882189251Ssam 883189251Ssam res = os_snprintf(cmd, sizeof(cmd), "GET_NETWORK %s %s", 884189251Ssam argv[0], argv[1]); 885189251Ssam if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { 886189251Ssam printf("Too long GET_NETWORK command.\n"); 887189251Ssam return -1; 888189251Ssam } 889189251Ssam return wpa_ctrl_command(ctrl, cmd); 890189251Ssam} 891189251Ssam 892189251Ssam 893189251Ssamstatic int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc, 894189251Ssam char *argv[]) 895189251Ssam{ 896189251Ssam return wpa_ctrl_command(ctrl, "DISCONNECT"); 897189251Ssam} 898189251Ssam 899189251Ssam 900189251Ssamstatic int wpa_cli_cmd_reconnect(struct wpa_ctrl *ctrl, int argc, 901189251Ssam char *argv[]) 902189251Ssam{ 903189251Ssam return wpa_ctrl_command(ctrl, "RECONNECT"); 904189251Ssam} 905189251Ssam 906189251Ssam 907189251Ssamstatic int wpa_cli_cmd_save_config(struct wpa_ctrl *ctrl, int argc, 908189251Ssam char *argv[]) 909189251Ssam{ 910189251Ssam return wpa_ctrl_command(ctrl, "SAVE_CONFIG"); 911189251Ssam} 912189251Ssam 913189251Ssam 914189251Ssamstatic int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[]) 915189251Ssam{ 916189251Ssam return wpa_ctrl_command(ctrl, "SCAN"); 917189251Ssam} 918189251Ssam 919189251Ssam 920189251Ssamstatic int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc, 921189251Ssam char *argv[]) 922189251Ssam{ 923189251Ssam return wpa_ctrl_command(ctrl, "SCAN_RESULTS"); 924189251Ssam} 925189251Ssam 926189251Ssam 927189251Ssamstatic int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[]) 928189251Ssam{ 929189251Ssam char cmd[64]; 930189251Ssam int res; 931189251Ssam 932189251Ssam if (argc != 1) { 933189251Ssam printf("Invalid BSS command: need one argument (index or " 934189251Ssam "BSSID)\n"); 935189251Ssam return -1; 936189251Ssam } 937189251Ssam 938189251Ssam res = os_snprintf(cmd, sizeof(cmd), "BSS %s", argv[0]); 939189251Ssam if (res < 0 || (size_t) res >= sizeof(cmd)) 940189251Ssam return -1; 941189251Ssam cmd[sizeof(cmd) - 1] = '\0'; 942189251Ssam 943189251Ssam return wpa_ctrl_command(ctrl, cmd); 944189251Ssam} 945189251Ssam 946189251Ssam 947189251Ssamstatic int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc, 948189251Ssam char *argv[]) 949189251Ssam{ 950189251Ssam char cmd[64]; 951189251Ssam int res; 952189251Ssam 953189251Ssam if (argc < 1 || argc > 2) { 954189251Ssam printf("Invalid GET_CAPABILITY command: need either one or " 955189251Ssam "two arguments\n"); 956189251Ssam return -1; 957189251Ssam } 958189251Ssam 959189251Ssam if ((argc == 2) && os_strcmp(argv[1], "strict") != 0) { 960189251Ssam printf("Invalid GET_CAPABILITY command: second argument, " 961189251Ssam "if any, must be 'strict'\n"); 962189251Ssam return -1; 963189251Ssam } 964189251Ssam 965189251Ssam res = os_snprintf(cmd, sizeof(cmd), "GET_CAPABILITY %s%s", argv[0], 966189251Ssam (argc == 2) ? " strict" : ""); 967189251Ssam if (res < 0 || (size_t) res >= sizeof(cmd)) 968189251Ssam return -1; 969189251Ssam cmd[sizeof(cmd) - 1] = '\0'; 970189251Ssam 971189251Ssam return wpa_ctrl_command(ctrl, cmd); 972189251Ssam} 973189251Ssam 974189251Ssam 975189251Ssamstatic int wpa_cli_list_interfaces(struct wpa_ctrl *ctrl) 976189251Ssam{ 977189251Ssam printf("Available interfaces:\n"); 978189251Ssam return wpa_ctrl_command(ctrl, "INTERFACES"); 979189251Ssam} 980189251Ssam 981189251Ssam 982189251Ssamstatic int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[]) 983189251Ssam{ 984189251Ssam if (argc < 1) { 985189251Ssam wpa_cli_list_interfaces(ctrl); 986189251Ssam return 0; 987189251Ssam } 988189251Ssam 989189251Ssam wpa_cli_close_connection(); 990189251Ssam os_free(ctrl_ifname); 991189251Ssam ctrl_ifname = os_strdup(argv[0]); 992189251Ssam 993189251Ssam if (wpa_cli_open_connection(ctrl_ifname)) { 994189251Ssam printf("Connected to interface '%s.\n", ctrl_ifname); 995189251Ssam if (wpa_ctrl_attach(ctrl_conn) == 0) { 996189251Ssam wpa_cli_attached = 1; 997189251Ssam } else { 998189251Ssam printf("Warning: Failed to attach to " 999189251Ssam "wpa_supplicant.\n"); 1000189251Ssam } 1001189251Ssam } else { 1002189251Ssam printf("Could not connect to interface '%s' - re-trying\n", 1003189251Ssam ctrl_ifname); 1004189251Ssam } 1005189251Ssam return 0; 1006189251Ssam} 1007189251Ssam 1008189251Ssam 1009189251Ssamstatic int wpa_cli_cmd_reconfigure(struct wpa_ctrl *ctrl, int argc, 1010189251Ssam char *argv[]) 1011189251Ssam{ 1012189251Ssam return wpa_ctrl_command(ctrl, "RECONFIGURE"); 1013189251Ssam} 1014189251Ssam 1015189251Ssam 1016189251Ssamstatic int wpa_cli_cmd_terminate(struct wpa_ctrl *ctrl, int argc, 1017189251Ssam char *argv[]) 1018189251Ssam{ 1019189251Ssam return wpa_ctrl_command(ctrl, "TERMINATE"); 1020189251Ssam} 1021189251Ssam 1022189251Ssam 1023189251Ssamstatic int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc, 1024189251Ssam char *argv[]) 1025189251Ssam{ 1026189251Ssam char cmd[256]; 1027189251Ssam int res; 1028189251Ssam 1029189251Ssam if (argc < 1) { 1030189251Ssam printf("Invalid INTERFACE_ADD command: needs at least one " 1031189251Ssam "argument (interface name)\n" 1032189251Ssam "All arguments: ifname confname driver ctrl_interface " 1033189251Ssam "driver_param bridge_name\n"); 1034189251Ssam return -1; 1035189251Ssam } 1036189251Ssam 1037189251Ssam /* 1038189251Ssam * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB 1039189251Ssam * <driver_param>TAB<bridge_name> 1040189251Ssam */ 1041189251Ssam res = os_snprintf(cmd, sizeof(cmd), 1042189251Ssam "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s", 1043189251Ssam argv[0], 1044189251Ssam argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "", 1045189251Ssam argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "", 1046189251Ssam argc > 5 ? argv[5] : ""); 1047189251Ssam if (res < 0 || (size_t) res >= sizeof(cmd)) 1048189251Ssam return -1; 1049189251Ssam cmd[sizeof(cmd) - 1] = '\0'; 1050189251Ssam return wpa_ctrl_command(ctrl, cmd); 1051189251Ssam} 1052189251Ssam 1053189251Ssam 1054189251Ssamstatic int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc, 1055189251Ssam char *argv[]) 1056189251Ssam{ 1057189251Ssam char cmd[128]; 1058189251Ssam int res; 1059189251Ssam 1060189251Ssam if (argc != 1) { 1061189251Ssam printf("Invalid INTERFACE_REMOVE command: needs one argument " 1062189251Ssam "(interface name)\n"); 1063189251Ssam return -1; 1064189251Ssam } 1065189251Ssam 1066189251Ssam res = os_snprintf(cmd, sizeof(cmd), "INTERFACE_REMOVE %s", argv[0]); 1067189251Ssam if (res < 0 || (size_t) res >= sizeof(cmd)) 1068189251Ssam return -1; 1069189251Ssam cmd[sizeof(cmd) - 1] = '\0'; 1070189251Ssam return wpa_ctrl_command(ctrl, cmd); 1071189251Ssam} 1072189251Ssam 1073189251Ssam 1074189251Ssamstatic int wpa_cli_cmd_interface_list(struct wpa_ctrl *ctrl, int argc, 1075189251Ssam char *argv[]) 1076189251Ssam{ 1077189251Ssam return wpa_ctrl_command(ctrl, "INTERFACE_LIST"); 1078189251Ssam} 1079189251Ssam 1080189251Ssam 1081189251Ssamenum wpa_cli_cmd_flags { 1082189251Ssam cli_cmd_flag_none = 0x00, 1083189251Ssam cli_cmd_flag_sensitive = 0x01 1084189251Ssam}; 1085189251Ssam 1086189251Ssamstruct wpa_cli_cmd { 1087189251Ssam const char *cmd; 1088189251Ssam int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); 1089189251Ssam enum wpa_cli_cmd_flags flags; 1090189251Ssam const char *usage; 1091189251Ssam}; 1092189251Ssam 1093189251Ssamstatic struct wpa_cli_cmd wpa_cli_commands[] = { 1094189251Ssam { "status", wpa_cli_cmd_status, 1095189251Ssam cli_cmd_flag_none, 1096189251Ssam "[verbose] = get current WPA/EAPOL/EAP status" }, 1097189251Ssam { "ping", wpa_cli_cmd_ping, 1098189251Ssam cli_cmd_flag_none, 1099189251Ssam "= pings wpa_supplicant" }, 1100189251Ssam { "mib", wpa_cli_cmd_mib, 1101189251Ssam cli_cmd_flag_none, 1102189251Ssam "= get MIB variables (dot1x, dot11)" }, 1103189251Ssam { "help", wpa_cli_cmd_help, 1104189251Ssam cli_cmd_flag_none, 1105189251Ssam "= show this usage help" }, 1106189251Ssam { "interface", wpa_cli_cmd_interface, 1107189251Ssam cli_cmd_flag_none, 1108189251Ssam "[ifname] = show interfaces/select interface" }, 1109189251Ssam { "level", wpa_cli_cmd_level, 1110189251Ssam cli_cmd_flag_none, 1111189251Ssam "<debug level> = change debug level" }, 1112189251Ssam { "license", wpa_cli_cmd_license, 1113189251Ssam cli_cmd_flag_none, 1114189251Ssam "= show full wpa_cli license" }, 1115189251Ssam { "quit", wpa_cli_cmd_quit, 1116189251Ssam cli_cmd_flag_none, 1117189251Ssam "= exit wpa_cli" }, 1118189251Ssam { "set", wpa_cli_cmd_set, 1119189251Ssam cli_cmd_flag_none, 1120189251Ssam "= set variables (shows list of variables when run without " 1121189251Ssam "arguments)" }, 1122189251Ssam { "logon", wpa_cli_cmd_logon, 1123189251Ssam cli_cmd_flag_none, 1124189251Ssam "= IEEE 802.1X EAPOL state machine logon" }, 1125189251Ssam { "logoff", wpa_cli_cmd_logoff, 1126189251Ssam cli_cmd_flag_none, 1127189251Ssam "= IEEE 802.1X EAPOL state machine logoff" }, 1128189251Ssam { "pmksa", wpa_cli_cmd_pmksa, 1129189251Ssam cli_cmd_flag_none, 1130189251Ssam "= show PMKSA cache" }, 1131189251Ssam { "reassociate", wpa_cli_cmd_reassociate, 1132189251Ssam cli_cmd_flag_none, 1133189251Ssam "= force reassociation" }, 1134189251Ssam { "preauthenticate", wpa_cli_cmd_preauthenticate, 1135189251Ssam cli_cmd_flag_none, 1136189251Ssam "<BSSID> = force preauthentication" }, 1137189251Ssam { "identity", wpa_cli_cmd_identity, 1138189251Ssam cli_cmd_flag_none, 1139189251Ssam "<network id> <identity> = configure identity for an SSID" }, 1140189251Ssam { "password", wpa_cli_cmd_password, 1141189251Ssam cli_cmd_flag_sensitive, 1142189251Ssam "<network id> <password> = configure password for an SSID" }, 1143189251Ssam { "new_password", wpa_cli_cmd_new_password, 1144189251Ssam cli_cmd_flag_sensitive, 1145189251Ssam "<network id> <password> = change password for an SSID" }, 1146189251Ssam { "pin", wpa_cli_cmd_pin, 1147189251Ssam cli_cmd_flag_sensitive, 1148189251Ssam "<network id> <pin> = configure pin for an SSID" }, 1149189251Ssam { "otp", wpa_cli_cmd_otp, 1150189251Ssam cli_cmd_flag_sensitive, 1151189251Ssam "<network id> <password> = configure one-time-password for an SSID" 1152189251Ssam }, 1153189251Ssam { "passphrase", wpa_cli_cmd_passphrase, 1154189251Ssam cli_cmd_flag_sensitive, 1155189251Ssam "<network id> <passphrase> = configure private key passphrase\n" 1156189251Ssam " for an SSID" }, 1157189251Ssam { "bssid", wpa_cli_cmd_bssid, 1158189251Ssam cli_cmd_flag_none, 1159189251Ssam "<network id> <BSSID> = set preferred BSSID for an SSID" }, 1160189251Ssam { "list_networks", wpa_cli_cmd_list_networks, 1161189251Ssam cli_cmd_flag_none, 1162189251Ssam "= list configured networks" }, 1163189251Ssam { "select_network", wpa_cli_cmd_select_network, 1164189251Ssam cli_cmd_flag_none, 1165189251Ssam "<network id> = select a network (disable others)" }, 1166189251Ssam { "enable_network", wpa_cli_cmd_enable_network, 1167189251Ssam cli_cmd_flag_none, 1168189251Ssam "<network id> = enable a network" }, 1169189251Ssam { "disable_network", wpa_cli_cmd_disable_network, 1170189251Ssam cli_cmd_flag_none, 1171189251Ssam "<network id> = disable a network" }, 1172189251Ssam { "add_network", wpa_cli_cmd_add_network, 1173189251Ssam cli_cmd_flag_none, 1174189251Ssam "= add a network" }, 1175189251Ssam { "remove_network", wpa_cli_cmd_remove_network, 1176189251Ssam cli_cmd_flag_none, 1177189251Ssam "<network id> = remove a network" }, 1178189251Ssam { "set_network", wpa_cli_cmd_set_network, 1179189251Ssam cli_cmd_flag_sensitive, 1180189251Ssam "<network id> <variable> <value> = set network variables (shows\n" 1181189251Ssam " list of variables when run without arguments)" }, 1182189251Ssam { "get_network", wpa_cli_cmd_get_network, 1183189251Ssam cli_cmd_flag_none, 1184189251Ssam "<network id> <variable> = get network variables" }, 1185189251Ssam { "save_config", wpa_cli_cmd_save_config, 1186189251Ssam cli_cmd_flag_none, 1187189251Ssam "= save the current configuration" }, 1188189251Ssam { "disconnect", wpa_cli_cmd_disconnect, 1189189251Ssam cli_cmd_flag_none, 1190189251Ssam "= disconnect and wait for reassociate/reconnect command before\n" 1191189251Ssam " connecting" }, 1192189251Ssam { "reconnect", wpa_cli_cmd_reconnect, 1193189251Ssam cli_cmd_flag_none, 1194189251Ssam "= like reassociate, but only takes effect if already disconnected" 1195189251Ssam }, 1196189251Ssam { "scan", wpa_cli_cmd_scan, 1197189251Ssam cli_cmd_flag_none, 1198189251Ssam "= request new BSS scan" }, 1199189251Ssam { "scan_results", wpa_cli_cmd_scan_results, 1200189251Ssam cli_cmd_flag_none, 1201189251Ssam "= get latest scan results" }, 1202189251Ssam { "bss", wpa_cli_cmd_bss, 1203189251Ssam cli_cmd_flag_none, 1204189251Ssam "<<idx> | <bssid>> = get detailed scan result info" }, 1205189251Ssam { "get_capability", wpa_cli_cmd_get_capability, 1206189251Ssam cli_cmd_flag_none, 1207189251Ssam "<eap/pairwise/group/key_mgmt/proto/auth_alg> = get capabilies" }, 1208189251Ssam { "reconfigure", wpa_cli_cmd_reconfigure, 1209189251Ssam cli_cmd_flag_none, 1210189251Ssam "= force wpa_supplicant to re-read its configuration file" }, 1211189251Ssam { "terminate", wpa_cli_cmd_terminate, 1212189251Ssam cli_cmd_flag_none, 1213189251Ssam "= terminate wpa_supplicant" }, 1214189251Ssam { "interface_add", wpa_cli_cmd_interface_add, 1215189251Ssam cli_cmd_flag_none, 1216189251Ssam "<ifname> <confname> <driver> <ctrl_interface> <driver_param>\n" 1217189251Ssam " <bridge_name> = adds new interface, all parameters but <ifname>\n" 1218189251Ssam " are optional" }, 1219189251Ssam { "interface_remove", wpa_cli_cmd_interface_remove, 1220189251Ssam cli_cmd_flag_none, 1221189251Ssam "<ifname> = removes the interface" }, 1222189251Ssam { "interface_list", wpa_cli_cmd_interface_list, 1223189251Ssam cli_cmd_flag_none, 1224189251Ssam "= list available interfaces" }, 1225189251Ssam { "ap_scan", wpa_cli_cmd_ap_scan, 1226189251Ssam cli_cmd_flag_none, 1227189251Ssam "<value> = set ap_scan parameter" }, 1228189251Ssam { "stkstart", wpa_cli_cmd_stkstart, 1229189251Ssam cli_cmd_flag_none, 1230189251Ssam "<addr> = request STK negotiation with <addr>" }, 1231189251Ssam { "ft_ds", wpa_cli_cmd_ft_ds, 1232189251Ssam cli_cmd_flag_none, 1233189251Ssam "<addr> = request over-the-DS FT with <addr>" }, 1234189251Ssam { "wps_pbc", wpa_cli_cmd_wps_pbc, 1235189251Ssam cli_cmd_flag_none, 1236189251Ssam "[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" }, 1237189251Ssam { "wps_pin", wpa_cli_cmd_wps_pin, 1238189251Ssam cli_cmd_flag_sensitive, 1239189251Ssam "<BSSID> [PIN] = start WPS PIN method (returns PIN, if not " 1240189251Ssam "hardcoded)" }, 1241189251Ssam { "wps_reg", wpa_cli_cmd_wps_reg, 1242189251Ssam cli_cmd_flag_sensitive, 1243189251Ssam "<BSSID> <AP PIN> = start WPS Registrar to configure an AP" }, 1244189251Ssam { NULL, NULL, cli_cmd_flag_none, NULL } 1245189251Ssam}; 1246189251Ssam 1247189251Ssam 1248189251Ssam/* 1249189251Ssam * Prints command usage, lines are padded with the specified string. 1250189251Ssam */ 1251189251Ssamstatic void print_cmd_help(struct wpa_cli_cmd *cmd, const char *pad) 1252189251Ssam{ 1253189251Ssam char c; 1254189251Ssam size_t n; 1255189251Ssam 1256189251Ssam printf("%s%s ", pad, cmd->cmd); 1257189251Ssam for (n = 0; (c = cmd->usage[n]); n++) { 1258189251Ssam printf("%c", c); 1259189251Ssam if (c == '\n') 1260189251Ssam printf("%s", pad); 1261189251Ssam } 1262189251Ssam printf("\n"); 1263189251Ssam} 1264189251Ssam 1265189251Ssam 1266189251Ssamstatic void print_help(void) 1267189251Ssam{ 1268189251Ssam int n; 1269189251Ssam printf("commands:\n"); 1270189251Ssam for (n = 0; wpa_cli_commands[n].cmd; n++) 1271189251Ssam print_cmd_help(&wpa_cli_commands[n], " "); 1272189251Ssam} 1273189251Ssam 1274189251Ssam 1275189251Ssam#ifdef CONFIG_READLINE 1276189251Ssamstatic int cmd_has_sensitive_data(const char *cmd) 1277189251Ssam{ 1278189251Ssam const char *c, *delim; 1279189251Ssam int n; 1280189251Ssam size_t len; 1281189251Ssam 1282189251Ssam delim = os_strchr(cmd, ' '); 1283189251Ssam if (delim) 1284189251Ssam len = delim - cmd; 1285189251Ssam else 1286189251Ssam len = os_strlen(cmd); 1287189251Ssam 1288189251Ssam for (n = 0; (c = wpa_cli_commands[n].cmd); n++) { 1289189251Ssam if (os_strncasecmp(cmd, c, len) == 0 && len == os_strlen(c)) 1290189251Ssam return (wpa_cli_commands[n].flags & 1291189251Ssam cli_cmd_flag_sensitive); 1292189251Ssam } 1293189251Ssam return 0; 1294189251Ssam} 1295189251Ssam#endif /* CONFIG_READLINE */ 1296189251Ssam 1297189251Ssam 1298189251Ssamstatic int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) 1299189251Ssam{ 1300189251Ssam struct wpa_cli_cmd *cmd, *match = NULL; 1301189251Ssam int count; 1302189251Ssam int ret = 0; 1303189251Ssam 1304189251Ssam count = 0; 1305189251Ssam cmd = wpa_cli_commands; 1306189251Ssam while (cmd->cmd) { 1307189251Ssam if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0) 1308189251Ssam { 1309189251Ssam match = cmd; 1310189251Ssam if (os_strcasecmp(cmd->cmd, argv[0]) == 0) { 1311189251Ssam /* we have an exact match */ 1312189251Ssam count = 1; 1313189251Ssam break; 1314189251Ssam } 1315189251Ssam count++; 1316189251Ssam } 1317189251Ssam cmd++; 1318189251Ssam } 1319189251Ssam 1320189251Ssam if (count > 1) { 1321189251Ssam printf("Ambiguous command '%s'; possible commands:", argv[0]); 1322189251Ssam cmd = wpa_cli_commands; 1323189251Ssam while (cmd->cmd) { 1324189251Ssam if (os_strncasecmp(cmd->cmd, argv[0], 1325189251Ssam os_strlen(argv[0])) == 0) { 1326189251Ssam printf(" %s", cmd->cmd); 1327189251Ssam } 1328189251Ssam cmd++; 1329189251Ssam } 1330189251Ssam printf("\n"); 1331189251Ssam ret = 1; 1332189251Ssam } else if (count == 0) { 1333189251Ssam printf("Unknown command '%s'\n", argv[0]); 1334189251Ssam ret = 1; 1335189251Ssam } else { 1336189251Ssam ret = match->handler(ctrl, argc - 1, &argv[1]); 1337189251Ssam } 1338189251Ssam 1339189251Ssam return ret; 1340189251Ssam} 1341189251Ssam 1342189251Ssam 1343189251Ssamstatic int str_match(const char *a, const char *b) 1344189251Ssam{ 1345189251Ssam return os_strncmp(a, b, os_strlen(b)) == 0; 1346189251Ssam} 1347189251Ssam 1348189251Ssam 1349189251Ssamstatic int wpa_cli_exec(const char *program, const char *arg1, 1350189251Ssam const char *arg2) 1351189251Ssam{ 1352189251Ssam char *cmd; 1353189251Ssam size_t len; 1354189251Ssam int res; 1355189251Ssam int ret = 0; 1356189251Ssam 1357189251Ssam len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3; 1358189251Ssam cmd = os_malloc(len); 1359189251Ssam if (cmd == NULL) 1360189251Ssam return -1; 1361189251Ssam res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2); 1362189251Ssam if (res < 0 || (size_t) res >= len) { 1363189251Ssam os_free(cmd); 1364189251Ssam return -1; 1365189251Ssam } 1366189251Ssam cmd[len - 1] = '\0'; 1367189251Ssam#ifndef _WIN32_WCE 1368189251Ssam if (system(cmd) < 0) 1369189251Ssam ret = -1; 1370189251Ssam#endif /* _WIN32_WCE */ 1371189251Ssam os_free(cmd); 1372189251Ssam 1373189251Ssam return ret; 1374189251Ssam} 1375189251Ssam 1376189251Ssam 1377189251Ssamstatic void wpa_cli_action_process(const char *msg) 1378189251Ssam{ 1379189251Ssam const char *pos; 1380189251Ssam char *copy = NULL, *id, *pos2; 1381189251Ssam 1382189251Ssam pos = msg; 1383189251Ssam if (*pos == '<') { 1384189251Ssam /* skip priority */ 1385189251Ssam pos = os_strchr(pos, '>'); 1386189251Ssam if (pos) 1387189251Ssam pos++; 1388189251Ssam else 1389189251Ssam pos = msg; 1390189251Ssam } 1391189251Ssam 1392189251Ssam if (str_match(pos, WPA_EVENT_CONNECTED)) { 1393189251Ssam int new_id = -1; 1394189251Ssam os_unsetenv("WPA_ID"); 1395189251Ssam os_unsetenv("WPA_ID_STR"); 1396189251Ssam os_unsetenv("WPA_CTRL_DIR"); 1397189251Ssam 1398189251Ssam pos = os_strstr(pos, "[id="); 1399189251Ssam if (pos) 1400189251Ssam copy = os_strdup(pos + 4); 1401189251Ssam 1402189251Ssam if (copy) { 1403189251Ssam pos2 = id = copy; 1404189251Ssam while (*pos2 && *pos2 != ' ') 1405189251Ssam pos2++; 1406189251Ssam *pos2++ = '\0'; 1407189251Ssam new_id = atoi(id); 1408189251Ssam os_setenv("WPA_ID", id, 1); 1409189251Ssam while (*pos2 && *pos2 != '=') 1410189251Ssam pos2++; 1411189251Ssam if (*pos2 == '=') 1412189251Ssam pos2++; 1413189251Ssam id = pos2; 1414189251Ssam while (*pos2 && *pos2 != ']') 1415189251Ssam pos2++; 1416189251Ssam *pos2 = '\0'; 1417189251Ssam os_setenv("WPA_ID_STR", id, 1); 1418189251Ssam os_free(copy); 1419189251Ssam } 1420189251Ssam 1421189251Ssam os_setenv("WPA_CTRL_DIR", ctrl_iface_dir, 1); 1422189251Ssam 1423189251Ssam if (!wpa_cli_connected || new_id != wpa_cli_last_id) { 1424189251Ssam wpa_cli_connected = 1; 1425189251Ssam wpa_cli_last_id = new_id; 1426189251Ssam wpa_cli_exec(action_file, ctrl_ifname, "CONNECTED"); 1427189251Ssam } 1428189251Ssam } else if (str_match(pos, WPA_EVENT_DISCONNECTED)) { 1429189251Ssam if (wpa_cli_connected) { 1430189251Ssam wpa_cli_connected = 0; 1431189251Ssam wpa_cli_exec(action_file, ctrl_ifname, "DISCONNECTED"); 1432189251Ssam } 1433189251Ssam } else if (str_match(pos, WPA_EVENT_TERMINATING)) { 1434189251Ssam printf("wpa_supplicant is terminating - stop monitoring\n"); 1435189251Ssam wpa_cli_quit = 1; 1436189251Ssam } 1437189251Ssam} 1438189251Ssam 1439189251Ssam 1440189251Ssam#ifndef CONFIG_ANSI_C_EXTRA 1441189251Ssamstatic void wpa_cli_action_cb(char *msg, size_t len) 1442189251Ssam{ 1443189251Ssam wpa_cli_action_process(msg); 1444189251Ssam} 1445189251Ssam#endif /* CONFIG_ANSI_C_EXTRA */ 1446189251Ssam 1447189251Ssam 1448189251Ssamstatic void wpa_cli_reconnect(void) 1449189251Ssam{ 1450189251Ssam wpa_cli_close_connection(); 1451189251Ssam ctrl_conn = wpa_cli_open_connection(ctrl_ifname); 1452189251Ssam if (ctrl_conn) { 1453189251Ssam printf("Connection to wpa_supplicant re-established\n"); 1454189251Ssam if (wpa_ctrl_attach(ctrl_conn) == 0) { 1455189251Ssam wpa_cli_attached = 1; 1456189251Ssam } else { 1457189251Ssam printf("Warning: Failed to attach to " 1458189251Ssam "wpa_supplicant.\n"); 1459189251Ssam } 1460189251Ssam } 1461189251Ssam} 1462189251Ssam 1463189251Ssam 1464189251Ssamstatic void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read, 1465189251Ssam int action_monitor) 1466189251Ssam{ 1467189251Ssam int first = 1; 1468189251Ssam if (ctrl_conn == NULL) { 1469189251Ssam wpa_cli_reconnect(); 1470189251Ssam return; 1471189251Ssam } 1472189251Ssam while (wpa_ctrl_pending(ctrl) > 0) { 1473189251Ssam char buf[256]; 1474189251Ssam size_t len = sizeof(buf) - 1; 1475189251Ssam if (wpa_ctrl_recv(ctrl, buf, &len) == 0) { 1476189251Ssam buf[len] = '\0'; 1477189251Ssam if (action_monitor) 1478189251Ssam wpa_cli_action_process(buf); 1479189251Ssam else { 1480189251Ssam if (in_read && first) 1481189251Ssam printf("\n"); 1482189251Ssam first = 0; 1483189251Ssam printf("%s\n", buf); 1484189251Ssam } 1485189251Ssam } else { 1486189251Ssam printf("Could not read pending message.\n"); 1487189251Ssam break; 1488189251Ssam } 1489189251Ssam } 1490189251Ssam 1491189251Ssam if (wpa_ctrl_pending(ctrl) < 0) { 1492189251Ssam printf("Connection to wpa_supplicant lost - trying to " 1493189251Ssam "reconnect\n"); 1494189251Ssam wpa_cli_reconnect(); 1495189251Ssam } 1496189251Ssam} 1497189251Ssam 1498189251Ssam 1499189251Ssam#ifdef CONFIG_READLINE 1500189251Ssamstatic char * wpa_cli_cmd_gen(const char *text, int state) 1501189251Ssam{ 1502189251Ssam static int i, len; 1503189251Ssam const char *cmd; 1504189251Ssam 1505189251Ssam if (state == 0) { 1506189251Ssam i = 0; 1507189251Ssam len = os_strlen(text); 1508189251Ssam } 1509189251Ssam 1510189251Ssam while ((cmd = wpa_cli_commands[i].cmd)) { 1511189251Ssam i++; 1512189251Ssam if (os_strncasecmp(cmd, text, len) == 0) 1513189251Ssam return os_strdup(cmd); 1514189251Ssam } 1515189251Ssam 1516189251Ssam return NULL; 1517189251Ssam} 1518189251Ssam 1519189251Ssam 1520189251Ssamstatic char * wpa_cli_dummy_gen(const char *text, int state) 1521189251Ssam{ 1522189251Ssam return NULL; 1523189251Ssam} 1524189251Ssam 1525189251Ssam 1526189251Ssamstatic char ** wpa_cli_completion(const char *text, int start, int end) 1527189251Ssam{ 1528189251Ssam return rl_completion_matches(text, start == 0 ? 1529189251Ssam wpa_cli_cmd_gen : wpa_cli_dummy_gen); 1530189251Ssam} 1531189251Ssam#endif /* CONFIG_READLINE */ 1532189251Ssam 1533189251Ssam 1534189251Ssamstatic void wpa_cli_interactive(void) 1535189251Ssam{ 1536189251Ssam#define max_args 10 1537189251Ssam char cmdbuf[256], *cmd, *argv[max_args], *pos; 1538189251Ssam int argc; 1539189251Ssam#ifdef CONFIG_READLINE 1540189251Ssam char *home, *hfile = NULL; 1541189251Ssam#endif /* CONFIG_READLINE */ 1542189251Ssam 1543189251Ssam printf("\nInteractive mode\n\n"); 1544189251Ssam 1545189251Ssam#ifdef CONFIG_READLINE 1546189251Ssam rl_attempted_completion_function = wpa_cli_completion; 1547189251Ssam home = getenv("HOME"); 1548189251Ssam if (home) { 1549189251Ssam const char *fname = ".wpa_cli_history"; 1550189251Ssam int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1; 1551189251Ssam hfile = os_malloc(hfile_len); 1552189251Ssam if (hfile) { 1553189251Ssam int res; 1554189251Ssam res = os_snprintf(hfile, hfile_len, "%s/%s", home, 1555189251Ssam fname); 1556189251Ssam if (res >= 0 && res < hfile_len) { 1557189251Ssam hfile[hfile_len - 1] = '\0'; 1558189251Ssam read_history(hfile); 1559189251Ssam stifle_history(100); 1560189251Ssam } 1561189251Ssam } 1562189251Ssam } 1563189251Ssam#endif /* CONFIG_READLINE */ 1564189251Ssam 1565189251Ssam do { 1566189251Ssam wpa_cli_recv_pending(ctrl_conn, 0, 0); 1567189251Ssam#ifndef CONFIG_NATIVE_WINDOWS 1568189251Ssam alarm(ping_interval); 1569189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */ 1570189251Ssam#ifdef CONFIG_READLINE 1571189251Ssam cmd = readline("> "); 1572189251Ssam if (cmd && *cmd) { 1573189251Ssam HIST_ENTRY *h; 1574189251Ssam while (next_history()) 1575189251Ssam ; 1576189251Ssam h = previous_history(); 1577189251Ssam if (h == NULL || os_strcmp(cmd, h->line) != 0) 1578189251Ssam add_history(cmd); 1579189251Ssam next_history(); 1580189251Ssam } 1581189251Ssam#else /* CONFIG_READLINE */ 1582189251Ssam printf("> "); 1583189251Ssam cmd = fgets(cmdbuf, sizeof(cmdbuf), stdin); 1584189251Ssam#endif /* CONFIG_READLINE */ 1585189251Ssam#ifndef CONFIG_NATIVE_WINDOWS 1586189251Ssam alarm(0); 1587189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */ 1588189251Ssam if (cmd == NULL) 1589189251Ssam break; 1590189251Ssam wpa_cli_recv_pending(ctrl_conn, 0, 0); 1591189251Ssam pos = cmd; 1592189251Ssam while (*pos != '\0') { 1593189251Ssam if (*pos == '\n') { 1594189251Ssam *pos = '\0'; 1595189251Ssam break; 1596189251Ssam } 1597189251Ssam pos++; 1598189251Ssam } 1599189251Ssam argc = 0; 1600189251Ssam pos = cmd; 1601189251Ssam for (;;) { 1602189251Ssam while (*pos == ' ') 1603189251Ssam pos++; 1604189251Ssam if (*pos == '\0') 1605189251Ssam break; 1606189251Ssam argv[argc] = pos; 1607189251Ssam argc++; 1608189251Ssam if (argc == max_args) 1609189251Ssam break; 1610189251Ssam if (*pos == '"') { 1611189251Ssam char *pos2 = os_strrchr(pos, '"'); 1612189251Ssam if (pos2) 1613189251Ssam pos = pos2 + 1; 1614189251Ssam } 1615189251Ssam while (*pos != '\0' && *pos != ' ') 1616189251Ssam pos++; 1617189251Ssam if (*pos == ' ') 1618189251Ssam *pos++ = '\0'; 1619189251Ssam } 1620189251Ssam if (argc) 1621189251Ssam wpa_request(ctrl_conn, argc, argv); 1622189251Ssam 1623189251Ssam if (cmd != cmdbuf) 1624189251Ssam os_free(cmd); 1625189251Ssam } while (!wpa_cli_quit); 1626189251Ssam 1627189251Ssam#ifdef CONFIG_READLINE 1628189251Ssam if (hfile) { 1629189251Ssam /* Save command history, excluding lines that may contain 1630189251Ssam * passwords. */ 1631189251Ssam HIST_ENTRY *h; 1632189251Ssam history_set_pos(0); 1633189251Ssam while ((h = current_history())) { 1634189251Ssam char *p = h->line; 1635189251Ssam while (*p == ' ' || *p == '\t') 1636189251Ssam p++; 1637189251Ssam if (cmd_has_sensitive_data(p)) { 1638189251Ssam h = remove_history(where_history()); 1639189251Ssam if (h) { 1640189251Ssam os_free(h->line); 1641189251Ssam os_free(h->data); 1642189251Ssam os_free(h); 1643189251Ssam } else 1644189251Ssam next_history(); 1645189251Ssam } else 1646189251Ssam next_history(); 1647189251Ssam } 1648189251Ssam write_history(hfile); 1649189251Ssam os_free(hfile); 1650189251Ssam } 1651189251Ssam#endif /* CONFIG_READLINE */ 1652189251Ssam} 1653189251Ssam 1654189251Ssam 1655189251Ssamstatic void wpa_cli_action(struct wpa_ctrl *ctrl) 1656189251Ssam{ 1657189251Ssam#ifdef CONFIG_ANSI_C_EXTRA 1658189251Ssam /* TODO: ANSI C version(?) */ 1659189251Ssam printf("Action processing not supported in ANSI C build.\n"); 1660189251Ssam#else /* CONFIG_ANSI_C_EXTRA */ 1661189251Ssam fd_set rfds; 1662189251Ssam int fd, res; 1663189251Ssam struct timeval tv; 1664189251Ssam char buf[256]; /* note: large enough to fit in unsolicited messages */ 1665189251Ssam size_t len; 1666189251Ssam 1667189251Ssam fd = wpa_ctrl_get_fd(ctrl); 1668189251Ssam 1669189251Ssam while (!wpa_cli_quit) { 1670189251Ssam FD_ZERO(&rfds); 1671189251Ssam FD_SET(fd, &rfds); 1672189251Ssam tv.tv_sec = ping_interval; 1673189251Ssam tv.tv_usec = 0; 1674189251Ssam res = select(fd + 1, &rfds, NULL, NULL, &tv); 1675189251Ssam if (res < 0 && errno != EINTR) { 1676189251Ssam perror("select"); 1677189251Ssam break; 1678189251Ssam } 1679189251Ssam 1680189251Ssam if (FD_ISSET(fd, &rfds)) 1681189251Ssam wpa_cli_recv_pending(ctrl, 0, 1); 1682189251Ssam else { 1683189251Ssam /* verify that connection is still working */ 1684189251Ssam len = sizeof(buf) - 1; 1685189251Ssam if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len, 1686189251Ssam wpa_cli_action_cb) < 0 || 1687189251Ssam len < 4 || os_memcmp(buf, "PONG", 4) != 0) { 1688189251Ssam printf("wpa_supplicant did not reply to PING " 1689189251Ssam "command - exiting\n"); 1690189251Ssam break; 1691189251Ssam } 1692189251Ssam } 1693189251Ssam } 1694189251Ssam#endif /* CONFIG_ANSI_C_EXTRA */ 1695189251Ssam} 1696189251Ssam 1697189251Ssam 1698189251Ssamstatic void wpa_cli_cleanup(void) 1699189251Ssam{ 1700189251Ssam wpa_cli_close_connection(); 1701189251Ssam if (pid_file) 1702189251Ssam os_daemonize_terminate(pid_file); 1703189251Ssam 1704189251Ssam os_program_deinit(); 1705189251Ssam} 1706189251Ssam 1707189251Ssamstatic void wpa_cli_terminate(int sig) 1708189251Ssam{ 1709189251Ssam wpa_cli_cleanup(); 1710189251Ssam exit(0); 1711189251Ssam} 1712189251Ssam 1713189251Ssam 1714189251Ssam#ifndef CONFIG_NATIVE_WINDOWS 1715189251Ssamstatic void wpa_cli_alarm(int sig) 1716189251Ssam{ 1717189251Ssam if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) { 1718189251Ssam printf("Connection to wpa_supplicant lost - trying to " 1719189251Ssam "reconnect\n"); 1720189251Ssam wpa_cli_close_connection(); 1721189251Ssam } 1722189251Ssam if (!ctrl_conn) 1723189251Ssam wpa_cli_reconnect(); 1724189251Ssam if (ctrl_conn) 1725189251Ssam wpa_cli_recv_pending(ctrl_conn, 1, 0); 1726189251Ssam alarm(ping_interval); 1727189251Ssam} 1728189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */ 1729189251Ssam 1730189251Ssam 1731189251Ssamstatic char * wpa_cli_get_default_ifname(void) 1732189251Ssam{ 1733189251Ssam char *ifname = NULL; 1734189251Ssam 1735189251Ssam#ifdef CONFIG_CTRL_IFACE_UNIX 1736189251Ssam struct dirent *dent; 1737189251Ssam DIR *dir = opendir(ctrl_iface_dir); 1738189251Ssam if (!dir) 1739189251Ssam return NULL; 1740189251Ssam while ((dent = readdir(dir))) { 1741189251Ssam#ifdef _DIRENT_HAVE_D_TYPE 1742189251Ssam /* 1743189251Ssam * Skip the file if it is not a socket. Also accept 1744189251Ssam * DT_UNKNOWN (0) in case the C library or underlying 1745189251Ssam * file system does not support d_type. 1746189251Ssam */ 1747189251Ssam if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN) 1748189251Ssam continue; 1749189251Ssam#endif /* _DIRENT_HAVE_D_TYPE */ 1750189251Ssam if (os_strcmp(dent->d_name, ".") == 0 || 1751189251Ssam os_strcmp(dent->d_name, "..") == 0) 1752189251Ssam continue; 1753189251Ssam printf("Selected interface '%s'\n", dent->d_name); 1754189251Ssam ifname = os_strdup(dent->d_name); 1755189251Ssam break; 1756189251Ssam } 1757189251Ssam closedir(dir); 1758189251Ssam#endif /* CONFIG_CTRL_IFACE_UNIX */ 1759189251Ssam 1760189251Ssam#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 1761189251Ssam char buf[2048], *pos; 1762189251Ssam size_t len; 1763189251Ssam struct wpa_ctrl *ctrl; 1764189251Ssam int ret; 1765189251Ssam 1766189251Ssam ctrl = wpa_ctrl_open(NULL); 1767189251Ssam if (ctrl == NULL) 1768189251Ssam return NULL; 1769189251Ssam 1770189251Ssam len = sizeof(buf) - 1; 1771189251Ssam ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL); 1772189251Ssam if (ret >= 0) { 1773189251Ssam buf[len] = '\0'; 1774189251Ssam pos = os_strchr(buf, '\n'); 1775189251Ssam if (pos) 1776189251Ssam *pos = '\0'; 1777189251Ssam ifname = os_strdup(buf); 1778189251Ssam } 1779189251Ssam wpa_ctrl_close(ctrl); 1780189251Ssam#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 1781189251Ssam 1782189251Ssam return ifname; 1783189251Ssam} 1784189251Ssam 1785189251Ssam 1786189251Ssamint main(int argc, char *argv[]) 1787189251Ssam{ 1788189251Ssam int interactive; 1789189251Ssam int warning_displayed = 0; 1790189251Ssam int c; 1791189251Ssam int daemonize = 0; 1792189251Ssam int ret = 0; 1793189251Ssam const char *global = NULL; 1794189251Ssam 1795189251Ssam if (os_program_init()) 1796189251Ssam return -1; 1797189251Ssam 1798189251Ssam for (;;) { 1799189251Ssam c = getopt(argc, argv, "a:Bg:G:hi:p:P:v"); 1800189251Ssam if (c < 0) 1801189251Ssam break; 1802189251Ssam switch (c) { 1803189251Ssam case 'a': 1804189251Ssam action_file = optarg; 1805189251Ssam break; 1806189251Ssam case 'B': 1807189251Ssam daemonize = 1; 1808189251Ssam break; 1809189251Ssam case 'g': 1810189251Ssam global = optarg; 1811189251Ssam break; 1812189251Ssam case 'G': 1813189251Ssam ping_interval = atoi(optarg); 1814189251Ssam break; 1815189251Ssam case 'h': 1816189251Ssam usage(); 1817189251Ssam return 0; 1818189251Ssam case 'v': 1819189251Ssam printf("%s\n", wpa_cli_version); 1820189251Ssam return 0; 1821189251Ssam case 'i': 1822189251Ssam os_free(ctrl_ifname); 1823189251Ssam ctrl_ifname = os_strdup(optarg); 1824189251Ssam break; 1825189251Ssam case 'p': 1826189251Ssam ctrl_iface_dir = optarg; 1827189251Ssam break; 1828189251Ssam case 'P': 1829189251Ssam pid_file = optarg; 1830189251Ssam break; 1831189251Ssam default: 1832189251Ssam usage(); 1833189251Ssam return -1; 1834189251Ssam } 1835189251Ssam } 1836189251Ssam 1837189251Ssam interactive = (argc == optind) && (action_file == NULL); 1838189251Ssam 1839189251Ssam if (interactive) 1840189251Ssam printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license); 1841189251Ssam 1842189251Ssam if (global) { 1843189251Ssam#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 1844189251Ssam ctrl_conn = wpa_ctrl_open(NULL); 1845189251Ssam#else /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 1846189251Ssam ctrl_conn = wpa_ctrl_open(global); 1847189251Ssam#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 1848189251Ssam if (ctrl_conn == NULL) { 1849189251Ssam perror("Failed to connect to wpa_supplicant - " 1850189251Ssam "wpa_ctrl_open"); 1851189251Ssam return -1; 1852189251Ssam } 1853189251Ssam } 1854189251Ssam 1855189251Ssam for (; !global;) { 1856189251Ssam if (ctrl_ifname == NULL) 1857189251Ssam ctrl_ifname = wpa_cli_get_default_ifname(); 1858189251Ssam ctrl_conn = wpa_cli_open_connection(ctrl_ifname); 1859189251Ssam if (ctrl_conn) { 1860189251Ssam if (warning_displayed) 1861189251Ssam printf("Connection established.\n"); 1862189251Ssam break; 1863189251Ssam } 1864189251Ssam 1865189251Ssam if (!interactive) { 1866189251Ssam perror("Failed to connect to wpa_supplicant - " 1867189251Ssam "wpa_ctrl_open"); 1868189251Ssam return -1; 1869189251Ssam } 1870189251Ssam 1871189251Ssam if (!warning_displayed) { 1872189251Ssam printf("Could not connect to wpa_supplicant - " 1873189251Ssam "re-trying\n"); 1874189251Ssam warning_displayed = 1; 1875189251Ssam } 1876189251Ssam os_sleep(1, 0); 1877189251Ssam continue; 1878189251Ssam } 1879189251Ssam 1880189251Ssam#ifndef _WIN32_WCE 1881189251Ssam signal(SIGINT, wpa_cli_terminate); 1882189251Ssam signal(SIGTERM, wpa_cli_terminate); 1883189251Ssam#endif /* _WIN32_WCE */ 1884189251Ssam#ifndef CONFIG_NATIVE_WINDOWS 1885189251Ssam signal(SIGALRM, wpa_cli_alarm); 1886189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */ 1887189251Ssam 1888189251Ssam if (interactive || action_file) { 1889189251Ssam if (wpa_ctrl_attach(ctrl_conn) == 0) { 1890189251Ssam wpa_cli_attached = 1; 1891189251Ssam } else { 1892189251Ssam printf("Warning: Failed to attach to " 1893189251Ssam "wpa_supplicant.\n"); 1894189251Ssam if (!interactive) 1895189251Ssam return -1; 1896189251Ssam } 1897189251Ssam } 1898189251Ssam 1899189251Ssam if (daemonize && os_daemonize(pid_file)) 1900189251Ssam return -1; 1901189251Ssam 1902189251Ssam if (interactive) 1903189251Ssam wpa_cli_interactive(); 1904189251Ssam else if (action_file) 1905189251Ssam wpa_cli_action(ctrl_conn); 1906189251Ssam else 1907189251Ssam ret = wpa_request(ctrl_conn, argc - optind, &argv[optind]); 1908189251Ssam 1909189251Ssam os_free(ctrl_ifname); 1910189251Ssam wpa_cli_cleanup(); 1911189251Ssam 1912189251Ssam return ret; 1913189251Ssam} 1914189251Ssam 1915189251Ssam#else /* CONFIG_CTRL_IFACE */ 1916189251Ssamint main(int argc, char *argv[]) 1917189251Ssam{ 1918189251Ssam printf("CONFIG_CTRL_IFACE not defined - wpa_cli disabled\n"); 1919189251Ssam return -1; 1920189251Ssam} 1921189251Ssam#endif /* CONFIG_CTRL_IFACE */ 1922