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> [timeout] 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 - at least two arguments, "
265 "UUID and PIN, are required.\n");
269 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
270 argv[0], argv[1], argv[2]);
272 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
273 return wpa_ctrl_command(ctrl, buf);
277 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
280 return wpa_ctrl_command(ctrl, "WPS_PBC");
282 #endif /* CONFIG_WPS */
285 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
286 char *addr, size_t addr_len)
288 char buf[4096], *pos;
292 if (ctrl_conn == NULL) {
293 printf("Not connected to hostapd - command dropped.\n");
296 len = sizeof(buf) - 1;
297 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
300 printf("'%s' command timed out.\n", cmd);
302 } else if (ret < 0) {
303 printf("'%s' command failed.\n", cmd);
308 if (memcmp(buf, "FAIL", 4) == 0)
313 while (*pos != '\0' && *pos != '\n')
316 os_strlcpy(addr, buf, addr_len);
321 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
324 char addr[32], cmd[64];
326 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
329 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
330 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
336 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
338 printf("%s", commands_help);
343 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
346 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
351 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
353 hostapd_cli_quit = 1;
358 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
362 printf("Invalid LEVEL command: needs one argument (debug "
366 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
367 return wpa_ctrl_command(ctrl, cmd);
371 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
376 dir = opendir(ctrl_iface_dir);
378 printf("Control interface directory '%s' could not be "
379 "openned.\n", ctrl_iface_dir);
383 printf("Available interfaces:\n");
384 while ((dent = readdir(dir))) {
385 if (strcmp(dent->d_name, ".") == 0 ||
386 strcmp(dent->d_name, "..") == 0)
388 printf("%s\n", dent->d_name);
394 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
398 hostapd_cli_list_interfaces(ctrl);
402 hostapd_cli_close_connection();
404 ctrl_ifname = strdup(argv[0]);
406 if (hostapd_cli_open_connection(ctrl_ifname)) {
407 printf("Connected to interface '%s.\n", ctrl_ifname);
408 if (wpa_ctrl_attach(ctrl_conn) == 0) {
409 hostapd_cli_attached = 1;
411 printf("Warning: Failed to attach to "
415 printf("Could not connect to interface '%s' - re-trying\n",
422 struct hostapd_cli_cmd {
424 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
427 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
428 { "ping", hostapd_cli_cmd_ping },
429 { "mib", hostapd_cli_cmd_mib },
430 { "sta", hostapd_cli_cmd_sta },
431 { "all_sta", hostapd_cli_cmd_all_sta },
432 { "new_sta", hostapd_cli_cmd_new_sta },
433 #ifdef CONFIG_IEEE80211W
434 { "sa_query", hostapd_cli_cmd_sa_query },
435 #endif /* CONFIG_IEEE80211W */
437 { "wps_pin", hostapd_cli_cmd_wps_pin },
438 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
439 #endif /* CONFIG_WPS */
440 { "help", hostapd_cli_cmd_help },
441 { "interface", hostapd_cli_cmd_interface },
442 { "level", hostapd_cli_cmd_level },
443 { "license", hostapd_cli_cmd_license },
444 { "quit", hostapd_cli_cmd_quit },
449 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
451 struct hostapd_cli_cmd *cmd, *match = NULL;
455 cmd = hostapd_cli_commands;
457 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
465 printf("Ambiguous command '%s'; possible commands:", argv[0]);
466 cmd = hostapd_cli_commands;
468 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
470 printf(" %s", cmd->cmd);
475 } else if (count == 0) {
476 printf("Unknown command '%s'\n", argv[0]);
478 match->handler(ctrl, argc - 1, &argv[1]);
483 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read)
486 if (ctrl_conn == NULL)
488 while (wpa_ctrl_pending(ctrl)) {
490 size_t len = sizeof(buf) - 1;
491 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
493 if (in_read && first)
498 printf("Could not read pending message.\n");
505 static void hostapd_cli_interactive(void)
507 const int max_args = 10;
508 char cmd[256], *res, *argv[max_args], *pos;
511 printf("\nInteractive mode\n\n");
514 hostapd_cli_recv_pending(ctrl_conn, 0);
516 alarm(ping_interval);
517 res = fgets(cmd, sizeof(cmd), stdin);
522 while (*pos != '\0') {
538 if (argc == max_args)
540 while (*pos != '\0' && *pos != ' ')
546 wpa_request(ctrl_conn, argc, argv);
547 } while (!hostapd_cli_quit);
551 static void hostapd_cli_terminate(int sig)
553 hostapd_cli_close_connection();
558 static void hostapd_cli_alarm(int sig)
560 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
561 printf("Connection to hostapd lost - trying to reconnect\n");
562 hostapd_cli_close_connection();
565 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
567 printf("Connection to hostapd re-established\n");
568 if (wpa_ctrl_attach(ctrl_conn) == 0) {
569 hostapd_cli_attached = 1;
571 printf("Warning: Failed to attach to "
577 hostapd_cli_recv_pending(ctrl_conn, 1);
578 alarm(ping_interval);
582 int main(int argc, char *argv[])
585 int warning_displayed = 0;
589 c = getopt(argc, argv, "hG:i:p:v");
594 ping_interval = atoi(optarg);
600 printf("%s\n", hostapd_cli_version);
604 ctrl_ifname = strdup(optarg);
607 ctrl_iface_dir = optarg;
615 interactive = argc == optind;
618 printf("%s\n\n%s\n\n", hostapd_cli_version,
619 hostapd_cli_license);
623 if (ctrl_ifname == NULL) {
625 DIR *dir = opendir(ctrl_iface_dir);
627 while ((dent = readdir(dir))) {
628 if (strcmp(dent->d_name, ".") == 0 ||
629 strcmp(dent->d_name, "..") == 0)
631 printf("Selected interface '%s'\n",
633 ctrl_ifname = strdup(dent->d_name);
639 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
641 if (warning_displayed)
642 printf("Connection established.\n");
647 perror("Failed to connect to hostapd - "
652 if (!warning_displayed) {
653 printf("Could not connect to hostapd - re-trying\n");
654 warning_displayed = 1;
660 signal(SIGINT, hostapd_cli_terminate);
661 signal(SIGTERM, hostapd_cli_terminate);
662 signal(SIGALRM, hostapd_cli_alarm);
665 if (wpa_ctrl_attach(ctrl_conn) == 0) {
666 hostapd_cli_attached = 1;
668 printf("Warning: Failed to attach to hostapd.\n");
670 hostapd_cli_interactive();
672 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
675 hostapd_cli_close_connection();