2 * hostapd - command line interface for hostapd daemon
3 * Copyright (c) 2004-2009, Jouni Malinen <j@w1.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.
23 static const char *hostapd_cli_version =
24 "hostapd_cli v" VERSION_STR "\n"
25 "Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> and contributors";
28 static const char *hostapd_cli_license =
29 "This program is free software. You can distribute it and/or modify it\n"
30 "under the terms of the GNU General Public License version 2.\n"
32 "Alternatively, this software may be distributed under the terms of the\n"
33 "BSD license. See README and COPYING for more details.\n";
35 static const char *hostapd_cli_full_license =
36 "This program is free software; you can redistribute it and/or modify\n"
37 "it under the terms of the GNU General Public License version 2 as\n"
38 "published by the Free Software Foundation.\n"
40 "This program is distributed in the hope that it will be useful,\n"
41 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
42 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
43 "GNU General Public License for more details.\n"
45 "You should have received a copy of the GNU General Public License\n"
46 "along with this program; if not, write to the Free Software\n"
47 "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
49 "Alternatively, this software may be distributed under the terms of the\n"
52 "Redistribution and use in source and binary forms, with or without\n"
53 "modification, are permitted provided that the following conditions are\n"
56 "1. Redistributions of source code must retain the above copyright\n"
57 " notice, this list of conditions and the following disclaimer.\n"
59 "2. Redistributions in binary form must reproduce the above copyright\n"
60 " notice, this list of conditions and the following disclaimer in the\n"
61 " documentation and/or other materials provided with the distribution.\n"
63 "3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
64 " names of its contributors may be used to endorse or promote products\n"
65 " derived from this software without specific prior written permission.\n"
67 "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
68 "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
69 "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
70 "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
71 "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
72 "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
73 "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
74 "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
75 "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
76 "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
77 "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
80 static const char *commands_help =
82 " mib get MIB variables (dot1x, dot11, radius)\n"
83 " sta <addr> get MIB variables for one station\n"
84 " all_sta get MIB variables for all stations\n"
85 " new_sta <addr> add a new station\n"
86 #ifdef CONFIG_IEEE80211W
87 " sa_query <addr> send SA Query to a station\n"
88 #endif /* CONFIG_IEEE80211W */
90 " wps_pin <uuid> <pin> add WPS Enrollee PIN (Device Password)\n"
91 " wps_pbc indicate button pushed to initiate PBC\n"
92 #endif /* CONFIG_WPS */
93 " help show this usage help\n"
94 " interface [ifname] show interfaces/select interface\n"
95 " level <debug level> change debug level\n"
96 " license show full hostapd_cli license\n"
97 " quit exit hostapd_cli\n";
99 static struct wpa_ctrl *ctrl_conn;
100 static int hostapd_cli_quit = 0;
101 static int hostapd_cli_attached = 0;
102 static const char *ctrl_iface_dir = "/var/run/hostapd";
103 static char *ctrl_ifname = NULL;
104 static int ping_interval = 5;
107 static void usage(void)
109 fprintf(stderr, "%s\n", hostapd_cli_version);
112 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hv] "
113 "[-G<ping interval>] \\\n"
117 " -h help (show this usage text)\n"
118 " -v shown version information\n"
119 " -p<path> path to find control sockets (default: "
120 "/var/run/hostapd)\n"
121 " -i<ifname> Interface to listen on (default: first "
122 "interface found in the\n"
129 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
137 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
138 cfile = malloc(flen);
141 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
143 ctrl_conn = wpa_ctrl_open(cfile);
149 static void hostapd_cli_close_connection(void)
151 if (ctrl_conn == NULL)
154 if (hostapd_cli_attached) {
155 wpa_ctrl_detach(ctrl_conn);
156 hostapd_cli_attached = 0;
158 wpa_ctrl_close(ctrl_conn);
163 static void hostapd_cli_msg_cb(char *msg, size_t len)
169 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
175 if (ctrl_conn == NULL) {
176 printf("Not connected to hostapd - command dropped.\n");
179 len = sizeof(buf) - 1;
180 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
183 printf("'%s' command timed out.\n", cmd);
185 } else if (ret < 0) {
186 printf("'%s' command failed.\n", cmd);
197 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
199 return _wpa_ctrl_command(ctrl, cmd, 1);
203 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
205 return wpa_ctrl_command(ctrl, "PING");
209 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
211 return wpa_ctrl_command(ctrl, "MIB");
215 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
219 printf("Invalid 'sta' command - exactly one argument, STA "
220 "address, is required.\n");
223 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
224 return wpa_ctrl_command(ctrl, buf);
228 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
233 printf("Invalid 'new_sta' command - exactly one argument, STA "
234 "address, is required.\n");
237 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
238 return wpa_ctrl_command(ctrl, buf);
242 #ifdef CONFIG_IEEE80211W
243 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
248 printf("Invalid 'sa_query' command - exactly one argument, "
249 "STA address, is required.\n");
252 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
253 return wpa_ctrl_command(ctrl, buf);
255 #endif /* CONFIG_IEEE80211W */
259 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
264 printf("Invalid 'wps_pin' command - exactly two arguments, "
265 "UUID and PIN, are required.\n");
268 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
269 return wpa_ctrl_command(ctrl, buf);
273 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
276 return wpa_ctrl_command(ctrl, "WPS_PBC");
278 #endif /* CONFIG_WPS */
281 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
282 char *addr, size_t addr_len)
284 char buf[4096], *pos;
288 if (ctrl_conn == NULL) {
289 printf("Not connected to hostapd - command dropped.\n");
292 len = sizeof(buf) - 1;
293 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
296 printf("'%s' command timed out.\n", cmd);
298 } else if (ret < 0) {
299 printf("'%s' command failed.\n", cmd);
304 if (memcmp(buf, "FAIL", 4) == 0)
309 while (*pos != '\0' && *pos != '\n')
312 os_strlcpy(addr, buf, addr_len);
317 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
320 char addr[32], cmd[64];
322 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
325 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
326 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
332 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
334 printf("%s", commands_help);
339 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
342 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
347 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
349 hostapd_cli_quit = 1;
354 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
358 printf("Invalid LEVEL command: needs one argument (debug "
362 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
363 return wpa_ctrl_command(ctrl, cmd);
367 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
372 dir = opendir(ctrl_iface_dir);
374 printf("Control interface directory '%s' could not be "
375 "openned.\n", ctrl_iface_dir);
379 printf("Available interfaces:\n");
380 while ((dent = readdir(dir))) {
381 if (strcmp(dent->d_name, ".") == 0 ||
382 strcmp(dent->d_name, "..") == 0)
384 printf("%s\n", dent->d_name);
390 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
394 hostapd_cli_list_interfaces(ctrl);
398 hostapd_cli_close_connection();
400 ctrl_ifname = strdup(argv[0]);
402 if (hostapd_cli_open_connection(ctrl_ifname)) {
403 printf("Connected to interface '%s.\n", ctrl_ifname);
404 if (wpa_ctrl_attach(ctrl_conn) == 0) {
405 hostapd_cli_attached = 1;
407 printf("Warning: Failed to attach to "
411 printf("Could not connect to interface '%s' - re-trying\n",
418 struct hostapd_cli_cmd {
420 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
423 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
424 { "ping", hostapd_cli_cmd_ping },
425 { "mib", hostapd_cli_cmd_mib },
426 { "sta", hostapd_cli_cmd_sta },
427 { "all_sta", hostapd_cli_cmd_all_sta },
428 { "new_sta", hostapd_cli_cmd_new_sta },
429 #ifdef CONFIG_IEEE80211W
430 { "sa_query", hostapd_cli_cmd_sa_query },
431 #endif /* CONFIG_IEEE80211W */
433 { "wps_pin", hostapd_cli_cmd_wps_pin },
434 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
435 #endif /* CONFIG_WPS */
436 { "help", hostapd_cli_cmd_help },
437 { "interface", hostapd_cli_cmd_interface },
438 { "level", hostapd_cli_cmd_level },
439 { "license", hostapd_cli_cmd_license },
440 { "quit", hostapd_cli_cmd_quit },
445 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
447 struct hostapd_cli_cmd *cmd, *match = NULL;
451 cmd = hostapd_cli_commands;
453 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
461 printf("Ambiguous command '%s'; possible commands:", argv[0]);
462 cmd = hostapd_cli_commands;
464 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
466 printf(" %s", cmd->cmd);
471 } else if (count == 0) {
472 printf("Unknown command '%s'\n", argv[0]);
474 match->handler(ctrl, argc - 1, &argv[1]);
479 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read)
482 if (ctrl_conn == NULL)
484 while (wpa_ctrl_pending(ctrl)) {
486 size_t len = sizeof(buf) - 1;
487 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
489 if (in_read && first)
494 printf("Could not read pending message.\n");
501 static void hostapd_cli_interactive(void)
503 const int max_args = 10;
504 char cmd[256], *res, *argv[max_args], *pos;
507 printf("\nInteractive mode\n\n");
510 hostapd_cli_recv_pending(ctrl_conn, 0);
512 alarm(ping_interval);
513 res = fgets(cmd, sizeof(cmd), stdin);
518 while (*pos != '\0') {
534 if (argc == max_args)
536 while (*pos != '\0' && *pos != ' ')
542 wpa_request(ctrl_conn, argc, argv);
543 } while (!hostapd_cli_quit);
547 static void hostapd_cli_terminate(int sig)
549 hostapd_cli_close_connection();
554 static void hostapd_cli_alarm(int sig)
556 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
557 printf("Connection to hostapd lost - trying to reconnect\n");
558 hostapd_cli_close_connection();
561 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
563 printf("Connection to hostapd re-established\n");
564 if (wpa_ctrl_attach(ctrl_conn) == 0) {
565 hostapd_cli_attached = 1;
567 printf("Warning: Failed to attach to "
573 hostapd_cli_recv_pending(ctrl_conn, 1);
574 alarm(ping_interval);
578 int main(int argc, char *argv[])
581 int warning_displayed = 0;
585 c = getopt(argc, argv, "hG:i:p:v");
590 ping_interval = atoi(optarg);
596 printf("%s\n", hostapd_cli_version);
600 ctrl_ifname = strdup(optarg);
603 ctrl_iface_dir = optarg;
611 interactive = argc == optind;
614 printf("%s\n\n%s\n\n", hostapd_cli_version,
615 hostapd_cli_license);
619 if (ctrl_ifname == NULL) {
621 DIR *dir = opendir(ctrl_iface_dir);
623 while ((dent = readdir(dir))) {
624 if (strcmp(dent->d_name, ".") == 0 ||
625 strcmp(dent->d_name, "..") == 0)
627 printf("Selected interface '%s'\n",
629 ctrl_ifname = strdup(dent->d_name);
635 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
637 if (warning_displayed)
638 printf("Connection established.\n");
643 perror("Failed to connect to hostapd - "
648 if (!warning_displayed) {
649 printf("Could not connect to hostapd - re-trying\n");
650 warning_displayed = 1;
656 signal(SIGINT, hostapd_cli_terminate);
657 signal(SIGTERM, hostapd_cli_terminate);
658 signal(SIGALRM, hostapd_cli_alarm);
661 if (wpa_ctrl_attach(ctrl_conn) == 0) {
662 hostapd_cli_attached = 1;
664 printf("Warning: Failed to attach to hostapd.\n");
666 hostapd_cli_interactive();
668 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
671 hostapd_cli_close_connection();