2 * WPA Supplicant - command line interface for wpa_supplicant daemon
3 * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
21 #ifdef CONFIG_READLINE
22 #include <readline/readline.h>
23 #include <readline/history.h>
24 #endif /* CONFIG_READLINE */
27 #ifdef CONFIG_NATIVE_WINDOWS
29 #endif /* CONFIG_NATIVE_WINDOWS */
33 static const char *wpa_cli_version =
34 "wpa_cli v" VERSION_STR "\n"
35 "Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi> and contributors";
38 static const char *wpa_cli_license =
39 "This program is free software. You can distribute it and/or modify it\n"
40 "under the terms of the GNU General Public License version 2.\n"
42 "Alternatively, this software may be distributed under the terms of the\n"
43 "BSD license. See README and COPYING for more details.\n";
45 static const char *wpa_cli_full_license =
46 "This program is free software; you can redistribute it and/or modify\n"
47 "it under the terms of the GNU General Public License version 2 as\n"
48 "published by the Free Software Foundation.\n"
50 "This program is distributed in the hope that it will be useful,\n"
51 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
52 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
53 "GNU General Public License for more details.\n"
55 "You should have received a copy of the GNU General Public License\n"
56 "along with this program; if not, write to the Free Software\n"
57 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
59 "Alternatively, this software may be distributed under the terms of the\n"
62 "Redistribution and use in source and binary forms, with or without\n"
63 "modification, are permitted provided that the following conditions are\n"
66 "1. Redistributions of source code must retain the above copyright\n"
67 " notice, this list of conditions and the following disclaimer.\n"
69 "2. Redistributions in binary form must reproduce the above copyright\n"
70 " notice, this list of conditions and the following disclaimer in the\n"
71 " documentation and/or other materials provided with the distribution.\n"
73 "3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
74 " names of its contributors may be used to endorse or promote products\n"
75 " derived from this software without specific prior written permission.\n"
77 "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
78 "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
79 "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
80 "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
81 "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
82 "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
83 "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
84 "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
85 "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
86 "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
87 "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
90 static const char *commands_help =
92 " status [verbose] = get current WPA/EAPOL/EAP status\n"
93 " mib = get MIB variables (dot1x, dot11)\n"
94 " help = show this usage help\n"
95 " interface [ifname] = show interfaces/select interface\n"
96 " level <debug level> = change debug level\n"
97 " license = show full wpa_cli license\n"
98 " logoff = IEEE 802.1X EAPOL state machine logoff\n"
99 " logon = IEEE 802.1X EAPOL state machine logon\n"
100 " set = set variables (shows list of variables when run without arguments)\n"
101 " pmksa = show PMKSA cache\n"
102 " reassociate = force reassociation\n"
103 " reconfigure = force wpa_supplicant to re-read its configuration file\n"
104 " preauthenticate <BSSID> = force preauthentication\n"
105 " identity <network id> <identity> = configure identity for an SSID\n"
106 " password <network id> <password> = configure password for an SSID\n"
107 " otp <network id> <password> = configure one-time-password for an SSID\n"
108 " terminate = terminate wpa_supplicant\n"
109 " quit = exit wpa_cli\n";
111 static struct wpa_ctrl *ctrl_conn;
112 static int wpa_cli_quit = 0;
113 static int wpa_cli_attached = 0;
114 static const char *ctrl_iface_dir = "/var/run/wpa_supplicant";
115 static char *ctrl_ifname = NULL;
118 static void usage(void)
120 printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hv] "
122 " -h = help (show this usage text)\n"
123 " -v = shown version information\n"
124 " default path: /var/run/wpa_supplicant\n"
125 " default interface: first interface found in socket path\n"
131 static struct wpa_ctrl * wpa_cli_open_connection(const char *ifname)
133 #ifdef CONFIG_CTRL_IFACE_UDP
134 ctrl_conn = wpa_ctrl_open("");
136 #else /* CONFIG_CTRL_IFACE_UDP */
143 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
144 cfile = malloc(flen);
147 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
149 ctrl_conn = wpa_ctrl_open(cfile);
152 #endif /* CONFIG_CTRL_IFACE_UDP */
156 static void wpa_cli_close_connection(void)
158 if (ctrl_conn == NULL)
161 if (wpa_cli_attached) {
162 wpa_ctrl_detach(ctrl_conn);
163 wpa_cli_attached = 0;
165 wpa_ctrl_close(ctrl_conn);
170 static void wpa_cli_msg_cb(char *msg, size_t len)
176 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
182 if (ctrl_conn == NULL) {
183 printf("Not connected to wpa_supplicant - command dropped.\n");
186 len = sizeof(buf) - 1;
187 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
190 printf("'%s' command timed out.\n", cmd);
192 } else if (ret < 0) {
193 printf("'%s' command failed.\n", cmd);
204 static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
206 return _wpa_ctrl_command(ctrl, cmd, 1);
210 static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
212 int verbose = argc > 0 && strcmp(argv[0], "verbose") == 0;
213 return wpa_ctrl_command(ctrl, verbose ? "STATUS-VERBOSE" : "STATUS");
217 static int wpa_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
219 return wpa_ctrl_command(ctrl, "PING");
223 static int wpa_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
225 return wpa_ctrl_command(ctrl, "MIB");
229 static int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
231 return wpa_ctrl_command(ctrl, "PMKSA");
235 static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
237 printf("%s", commands_help);
242 static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[])
244 printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license);
249 static int wpa_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
256 static void wpa_cli_show_variables(void)
258 printf("set variables:\n"
259 " EAPOL::heldPeriod (EAPOL state machine held period, "
261 " EAPOL::authPeriod (EAPOL state machine authentication "
262 "period, in seconds)\n"
263 " EAPOL::startPeriod (EAPOL state machine start period, in "
265 " EAPOL::maxStart (EAPOL state machine maximum start "
270 static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
275 wpa_cli_show_variables();
280 printf("Invalid SET command: needs two arguments (variable "
281 "name and value)\n");
285 if (snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]) >=
287 printf("Too long SET command.\n");
290 return wpa_ctrl_command(ctrl, cmd);
294 static int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[])
296 return wpa_ctrl_command(ctrl, "LOGOFF");
300 static int wpa_cli_cmd_logon(struct wpa_ctrl *ctrl, int argc, char *argv[])
302 return wpa_ctrl_command(ctrl, "LOGON");
306 static int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc,
309 return wpa_ctrl_command(ctrl, "REASSOCIATE");
313 static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc,
319 printf("Invalid PREAUTH command: needs one argument "
324 if (snprintf(cmd, sizeof(cmd), "PREAUTH %s", argv[0]) >=
326 printf("Too long PREAUTH command.\n");
329 return wpa_ctrl_command(ctrl, cmd);
333 static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
337 printf("Invalid LEVEL command: needs one argument (debug "
341 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
342 return wpa_ctrl_command(ctrl, cmd);
346 static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[])
348 char cmd[256], *pos, *end;
352 printf("Invalid IDENTITY command: needs two arguments "
353 "(network id and identity)\n");
357 end = cmd + sizeof(cmd);
359 pos += snprintf(pos, end - pos, "CTRL-RSP-IDENTITY-%s:%s",
361 for (i = 2; i < argc; i++)
362 pos += snprintf(pos, end - pos, " %s", argv[i]);
364 return wpa_ctrl_command(ctrl, cmd);
368 static int wpa_cli_cmd_password(struct wpa_ctrl *ctrl, int argc, char *argv[])
370 char cmd[256], *pos, *end;
374 printf("Invalid PASSWORD command: needs two arguments "
375 "(network id and password)\n");
379 end = cmd + sizeof(cmd);
381 pos += snprintf(pos, end - pos, "CTRL-RSP-PASSWORD-%s:%s",
383 for (i = 2; i < argc; i++)
384 pos += snprintf(pos, end - pos, " %s", argv[i]);
386 return wpa_ctrl_command(ctrl, cmd);
390 static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[])
392 char cmd[256], *pos, *end;
396 printf("Invalid OTP command: needs two arguments (network "
397 "id and password)\n");
401 end = cmd + sizeof(cmd);
403 pos += snprintf(pos, end - pos, "CTRL-RSP-OTP-%s:%s",
405 for (i = 2; i < argc; i++)
406 pos += snprintf(pos, end - pos, " %s", argv[i]);
408 return wpa_ctrl_command(ctrl, cmd);
412 static void wpa_cli_list_interfaces(struct wpa_ctrl *ctrl)
417 dir = opendir(ctrl_iface_dir);
419 printf("Control interface directory '%s' could not be "
420 "openned.\n", ctrl_iface_dir);
424 printf("Available interfaces:\n");
425 while ((dent = readdir(dir))) {
426 if (strcmp(dent->d_name, ".") == 0 ||
427 strcmp(dent->d_name, "..") == 0)
429 printf("%s\n", dent->d_name);
435 static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[])
438 wpa_cli_list_interfaces(ctrl);
442 wpa_cli_close_connection();
444 ctrl_ifname = strdup(argv[0]);
446 if (wpa_cli_open_connection(ctrl_ifname)) {
447 printf("Connected to interface '%s.\n", ctrl_ifname);
448 if (wpa_ctrl_attach(ctrl_conn) == 0) {
449 wpa_cli_attached = 1;
451 printf("Warning: Failed to attach to "
452 "wpa_supplicant.\n");
455 printf("Could not connect to interface '%s' - re-trying\n",
462 static int wpa_cli_cmd_reconfigure(struct wpa_ctrl *ctrl, int argc,
465 return wpa_ctrl_command(ctrl, "RECONFIGURE");
469 static int wpa_cli_cmd_terminate(struct wpa_ctrl *ctrl, int argc,
472 return wpa_ctrl_command(ctrl, "TERMINATE");
478 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
481 static struct wpa_cli_cmd wpa_cli_commands[] = {
482 { "status", wpa_cli_cmd_status },
483 { "ping", wpa_cli_cmd_ping },
484 { "mib", wpa_cli_cmd_mib },
485 { "help", wpa_cli_cmd_help },
486 { "interface", wpa_cli_cmd_interface },
487 { "level", wpa_cli_cmd_level },
488 { "license", wpa_cli_cmd_license },
489 { "quit", wpa_cli_cmd_quit },
490 { "set", wpa_cli_cmd_set },
491 { "logon", wpa_cli_cmd_logon },
492 { "logoff", wpa_cli_cmd_logoff },
493 { "pmksa", wpa_cli_cmd_pmksa },
494 { "reassociate", wpa_cli_cmd_reassociate },
495 { "preauthenticate", wpa_cli_cmd_preauthenticate },
496 { "identity", wpa_cli_cmd_identity },
497 { "password", wpa_cli_cmd_password },
498 { "otp", wpa_cli_cmd_otp },
499 { "reconfigure", wpa_cli_cmd_reconfigure },
500 { "terminate", wpa_cli_cmd_terminate },
505 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
507 struct wpa_cli_cmd *cmd, *match = NULL;
511 cmd = wpa_cli_commands;
513 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
521 printf("Ambiguous command '%s'; possible commands:", argv[0]);
522 cmd = wpa_cli_commands;
524 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
526 printf(" %s", cmd->cmd);
531 } else if (count == 0) {
532 printf("Unknown command '%s'\n", argv[0]);
534 match->handler(ctrl, argc - 1, &argv[1]);
539 static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read)
542 if (ctrl_conn == NULL)
544 while (wpa_ctrl_pending(ctrl)) {
546 size_t len = sizeof(buf) - 1;
547 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
549 if (in_read && first)
554 printf("Could not read pending message.\n");
561 #ifdef CONFIG_READLINE
562 static char * wpa_cli_cmd_gen(const char *text, int state)
572 while ((cmd = wpa_cli_commands[i].cmd)) {
574 if (strncasecmp(cmd, text, len) == 0)
582 static char * wpa_cli_dummy_gen(const char *text, int state)
588 static char ** wpa_cli_completion(const char *text, int start, int end)
590 return rl_completion_matches(text, start == 0 ?
591 wpa_cli_cmd_gen : wpa_cli_dummy_gen);
593 #endif /* CONFIG_READLINE */
596 static void wpa_cli_interactive(void)
599 char cmdbuf[256], *cmd, *argv[max_args], *pos;
601 #ifdef CONFIG_READLINE
602 char *home, *hfile = NULL;
603 #endif /* CONFIG_READLINE */
605 printf("\nInteractive mode\n\n");
607 #ifdef CONFIG_READLINE
608 rl_attempted_completion_function = wpa_cli_completion;
609 home = getenv("HOME");
611 const char *fname = ".wpa_cli_history";
612 int hfile_len = strlen(home) + 1 + strlen(fname) + 1;
613 hfile = malloc(hfile_len);
615 snprintf(hfile, hfile_len, "%s/%s", home, fname);
620 #endif /* CONFIG_READLINE */
623 wpa_cli_recv_pending(ctrl_conn, 0);
624 #ifndef CONFIG_NATIVE_WINDOWS
626 #endif /* CONFIG_NATIVE_WINDOWS */
627 #ifdef CONFIG_READLINE
628 cmd = readline("> ");
631 while (next_history())
633 h = previous_history();
634 if (h == NULL || strcmp(cmd, h->line) != 0)
638 #else /* CONFIG_READLINE */
640 cmd = fgets(cmdbuf, sizeof(cmdbuf), stdin);
641 #endif /* CONFIG_READLINE */
642 #ifndef CONFIG_NATIVE_WINDOWS
644 #endif /* CONFIG_NATIVE_WINDOWS */
648 while (*pos != '\0') {
664 if (argc == max_args)
666 while (*pos != '\0' && *pos != ' ')
672 wpa_request(ctrl_conn, argc, argv);
676 } while (!wpa_cli_quit);
678 #ifdef CONFIG_READLINE
680 /* Save command history, excluding lines that may contain
687 while (*p == ' ' || *p == '\t')
689 if (strncasecmp(p, "pa", 2) == 0 ||
690 strncasecmp(p, "o", 1) == 0) {
691 h = remove_history(where_history());
697 h = current_history();
702 write_history(hfile);
705 #endif /* CONFIG_READLINE */
709 static void wpa_cli_terminate(int sig)
711 wpa_cli_close_connection();
716 #ifndef CONFIG_NATIVE_WINDOWS
717 static void wpa_cli_alarm(int sig)
719 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
720 printf("Connection to wpa_supplicant lost - trying to "
722 wpa_cli_close_connection();
725 ctrl_conn = wpa_cli_open_connection(ctrl_ifname);
727 printf("Connection to wpa_supplicant "
729 if (wpa_ctrl_attach(ctrl_conn) == 0) {
730 wpa_cli_attached = 1;
732 printf("Warning: Failed to attach to "
733 "wpa_supplicant.\n");
738 wpa_cli_recv_pending(ctrl_conn, 1);
741 #endif /* CONFIG_NATIVE_WINDOWS */
744 int main(int argc, char *argv[])
747 int warning_displayed = 0;
750 #ifdef CONFIG_NATIVE_WINDOWS
752 if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
753 printf("Could not find a usable WinSock.dll\n");
756 #endif /* CONFIG_NATIVE_WINDOWS */
759 c = getopt(argc, argv, "hi:p:v");
767 printf("%s\n", wpa_cli_version);
770 ctrl_ifname = strdup(optarg);
773 ctrl_iface_dir = optarg;
781 interactive = argc == optind;
784 printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license);
787 if (ctrl_ifname == NULL) {
789 DIR *dir = opendir(ctrl_iface_dir);
791 while ((dent = readdir(dir))) {
792 if (strcmp(dent->d_name, ".") == 0 ||
793 strcmp(dent->d_name, "..") == 0)
795 printf("Selected interface '%s'\n",
797 ctrl_ifname = strdup(dent->d_name);
803 ctrl_conn = wpa_cli_open_connection(ctrl_ifname);
805 if (warning_displayed)
806 printf("Connection established.\n");
811 perror("Failed to connect to wpa_supplicant - "
816 if (!warning_displayed) {
817 printf("Could not connect to wpa_supplicant - "
819 warning_displayed = 1;
825 signal(SIGINT, wpa_cli_terminate);
826 signal(SIGTERM, wpa_cli_terminate);
827 #ifndef CONFIG_NATIVE_WINDOWS
828 signal(SIGALRM, wpa_cli_alarm);
829 #endif /* CONFIG_NATIVE_WINDOWS */
832 if (wpa_ctrl_attach(ctrl_conn) == 0) {
833 wpa_cli_attached = 1;
835 printf("Warning: Failed to attach to "
836 "wpa_supplicant.\n");
838 wpa_cli_interactive();
840 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
843 wpa_cli_close_connection();
845 #ifdef CONFIG_NATIVE_WINDOWS
847 #endif /* CONFIG_NATIVE_WINDOWS */