2 * hostapd - command line interface for hostapd daemon
3 * Copyright (c) 2004-2008, 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-2008, 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"
87 " wps_pin <uuid> <pin> add WPS Enrollee PIN (Device Password)\n"
88 " wps_pbc indicate button pushed to initiate PBC\n"
89 #endif /* CONFIG_WPS */
90 " help show this usage help\n"
91 " interface [ifname] show interfaces/select interface\n"
92 " level <debug level> change debug level\n"
93 " license show full hostapd_cli license\n"
94 " quit exit hostapd_cli\n";
96 static struct wpa_ctrl *ctrl_conn;
97 static int hostapd_cli_quit = 0;
98 static int hostapd_cli_attached = 0;
99 static const char *ctrl_iface_dir = "/var/run/hostapd";
100 static char *ctrl_ifname = NULL;
103 static void usage(void)
105 fprintf(stderr, "%s\n", hostapd_cli_version);
108 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hv] "
112 " -h help (show this usage text)\n"
113 " -v shown version information\n"
114 " -p<path> path to find control sockets (default: "
115 "/var/run/hostapd)\n"
116 " -i<ifname> Interface to listen on (default: first "
117 "interface found in the\n"
124 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
132 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
133 cfile = malloc(flen);
136 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
138 ctrl_conn = wpa_ctrl_open(cfile);
144 static void hostapd_cli_close_connection(void)
146 if (ctrl_conn == NULL)
149 if (hostapd_cli_attached) {
150 wpa_ctrl_detach(ctrl_conn);
151 hostapd_cli_attached = 0;
153 wpa_ctrl_close(ctrl_conn);
158 static void hostapd_cli_msg_cb(char *msg, size_t len)
164 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
170 if (ctrl_conn == NULL) {
171 printf("Not connected to hostapd - command dropped.\n");
174 len = sizeof(buf) - 1;
175 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
178 printf("'%s' command timed out.\n", cmd);
180 } else if (ret < 0) {
181 printf("'%s' command failed.\n", cmd);
192 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
194 return _wpa_ctrl_command(ctrl, cmd, 1);
198 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
200 return wpa_ctrl_command(ctrl, "PING");
204 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
206 return wpa_ctrl_command(ctrl, "MIB");
210 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
214 printf("Invalid 'sta' command - exactly one argument, STA "
215 "address, is required.\n");
218 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
219 return wpa_ctrl_command(ctrl, buf);
223 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
228 printf("Invalid 'new_sta' command - exactly one argument, STA "
229 "address, is required.\n");
232 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
233 return wpa_ctrl_command(ctrl, buf);
238 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
243 printf("Invalid 'wps_pin' command - exactly two arguments, "
244 "UUID and PIN, are required.\n");
247 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
248 return wpa_ctrl_command(ctrl, buf);
252 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
255 return wpa_ctrl_command(ctrl, "WPS_PBC");
257 #endif /* CONFIG_WPS */
260 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
261 char *addr, size_t addr_len)
263 char buf[4096], *pos;
267 if (ctrl_conn == NULL) {
268 printf("Not connected to hostapd - command dropped.\n");
271 len = sizeof(buf) - 1;
272 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
275 printf("'%s' command timed out.\n", cmd);
277 } else if (ret < 0) {
278 printf("'%s' command failed.\n", cmd);
283 if (memcmp(buf, "FAIL", 4) == 0)
288 while (*pos != '\0' && *pos != '\n')
291 os_strlcpy(addr, buf, addr_len);
296 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
299 char addr[32], cmd[64];
301 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
304 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
305 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
311 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
313 printf("%s", commands_help);
318 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
321 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
326 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
328 hostapd_cli_quit = 1;
333 static int hostapd_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 void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
351 dir = opendir(ctrl_iface_dir);
353 printf("Control interface directory '%s' could not be "
354 "openned.\n", ctrl_iface_dir);
358 printf("Available interfaces:\n");
359 while ((dent = readdir(dir))) {
360 if (strcmp(dent->d_name, ".") == 0 ||
361 strcmp(dent->d_name, "..") == 0)
363 printf("%s\n", dent->d_name);
369 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
373 hostapd_cli_list_interfaces(ctrl);
377 hostapd_cli_close_connection();
379 ctrl_ifname = strdup(argv[0]);
381 if (hostapd_cli_open_connection(ctrl_ifname)) {
382 printf("Connected to interface '%s.\n", ctrl_ifname);
383 if (wpa_ctrl_attach(ctrl_conn) == 0) {
384 hostapd_cli_attached = 1;
386 printf("Warning: Failed to attach to "
390 printf("Could not connect to interface '%s' - re-trying\n",
397 struct hostapd_cli_cmd {
399 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
402 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
403 { "ping", hostapd_cli_cmd_ping },
404 { "mib", hostapd_cli_cmd_mib },
405 { "sta", hostapd_cli_cmd_sta },
406 { "all_sta", hostapd_cli_cmd_all_sta },
407 { "new_sta", hostapd_cli_cmd_new_sta },
409 { "wps_pin", hostapd_cli_cmd_wps_pin },
410 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
411 #endif /* CONFIG_WPS */
412 { "help", hostapd_cli_cmd_help },
413 { "interface", hostapd_cli_cmd_interface },
414 { "level", hostapd_cli_cmd_level },
415 { "license", hostapd_cli_cmd_license },
416 { "quit", hostapd_cli_cmd_quit },
421 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
423 struct hostapd_cli_cmd *cmd, *match = NULL;
427 cmd = hostapd_cli_commands;
429 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
437 printf("Ambiguous command '%s'; possible commands:", argv[0]);
438 cmd = hostapd_cli_commands;
440 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
442 printf(" %s", cmd->cmd);
447 } else if (count == 0) {
448 printf("Unknown command '%s'\n", argv[0]);
450 match->handler(ctrl, argc - 1, &argv[1]);
455 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read)
458 if (ctrl_conn == NULL)
460 while (wpa_ctrl_pending(ctrl)) {
462 size_t len = sizeof(buf) - 1;
463 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
465 if (in_read && first)
470 printf("Could not read pending message.\n");
477 static void hostapd_cli_interactive(void)
479 const int max_args = 10;
480 char cmd[256], *res, *argv[max_args], *pos;
483 printf("\nInteractive mode\n\n");
486 hostapd_cli_recv_pending(ctrl_conn, 0);
489 res = fgets(cmd, sizeof(cmd), stdin);
494 while (*pos != '\0') {
510 if (argc == max_args)
512 while (*pos != '\0' && *pos != ' ')
518 wpa_request(ctrl_conn, argc, argv);
519 } while (!hostapd_cli_quit);
523 static void hostapd_cli_terminate(int sig)
525 hostapd_cli_close_connection();
530 static void hostapd_cli_alarm(int sig)
532 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
533 printf("Connection to hostapd lost - trying to reconnect\n");
534 hostapd_cli_close_connection();
537 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
539 printf("Connection to hostapd re-established\n");
540 if (wpa_ctrl_attach(ctrl_conn) == 0) {
541 hostapd_cli_attached = 1;
543 printf("Warning: Failed to attach to "
549 hostapd_cli_recv_pending(ctrl_conn, 1);
554 int main(int argc, char *argv[])
557 int warning_displayed = 0;
561 c = getopt(argc, argv, "hi:p:v");
569 printf("%s\n", hostapd_cli_version);
573 ctrl_ifname = strdup(optarg);
576 ctrl_iface_dir = optarg;
584 interactive = argc == optind;
587 printf("%s\n\n%s\n\n", hostapd_cli_version,
588 hostapd_cli_license);
592 if (ctrl_ifname == NULL) {
594 DIR *dir = opendir(ctrl_iface_dir);
596 while ((dent = readdir(dir))) {
597 if (strcmp(dent->d_name, ".") == 0 ||
598 strcmp(dent->d_name, "..") == 0)
600 printf("Selected interface '%s'\n",
602 ctrl_ifname = strdup(dent->d_name);
608 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
610 if (warning_displayed)
611 printf("Connection established.\n");
616 perror("Failed to connect to hostapd - "
621 if (!warning_displayed) {
622 printf("Could not connect to hostapd - re-trying\n");
623 warning_displayed = 1;
629 signal(SIGINT, hostapd_cli_terminate);
630 signal(SIGTERM, hostapd_cli_terminate);
631 signal(SIGALRM, hostapd_cli_alarm);
634 if (wpa_ctrl_attach(ctrl_conn) == 0) {
635 hostapd_cli_attached = 1;
637 printf("Warning: Failed to attach to hostapd.\n");
639 hostapd_cli_interactive();
641 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
644 hostapd_cli_close_connection();