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"
93 " wps_oob <type> <path> <method> use WPS with out-of-band (UFD)\n"
94 #endif /* CONFIG_WPS_OOB */
95 #endif /* CONFIG_WPS */
96 " help show this usage help\n"
97 " interface [ifname] show interfaces/select interface\n"
98 " level <debug level> change debug level\n"
99 " license show full hostapd_cli license\n"
100 " quit exit hostapd_cli\n";
102 static struct wpa_ctrl *ctrl_conn;
103 static int hostapd_cli_quit = 0;
104 static int hostapd_cli_attached = 0;
105 static const char *ctrl_iface_dir = "/var/run/hostapd";
106 static char *ctrl_ifname = NULL;
107 static int ping_interval = 5;
110 static void usage(void)
112 fprintf(stderr, "%s\n", hostapd_cli_version);
115 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hv] "
116 "[-G<ping interval>] \\\n"
120 " -h help (show this usage text)\n"
121 " -v shown version information\n"
122 " -p<path> path to find control sockets (default: "
123 "/var/run/hostapd)\n"
124 " -i<ifname> Interface to listen on (default: first "
125 "interface found in the\n"
132 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
140 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
141 cfile = malloc(flen);
144 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
146 ctrl_conn = wpa_ctrl_open(cfile);
152 static void hostapd_cli_close_connection(void)
154 if (ctrl_conn == NULL)
157 if (hostapd_cli_attached) {
158 wpa_ctrl_detach(ctrl_conn);
159 hostapd_cli_attached = 0;
161 wpa_ctrl_close(ctrl_conn);
166 static void hostapd_cli_msg_cb(char *msg, size_t len)
172 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
178 if (ctrl_conn == NULL) {
179 printf("Not connected to hostapd - command dropped.\n");
182 len = sizeof(buf) - 1;
183 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
186 printf("'%s' command timed out.\n", cmd);
188 } else if (ret < 0) {
189 printf("'%s' command failed.\n", cmd);
200 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
202 return _wpa_ctrl_command(ctrl, cmd, 1);
206 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
208 return wpa_ctrl_command(ctrl, "PING");
212 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
214 return wpa_ctrl_command(ctrl, "MIB");
218 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
222 printf("Invalid 'sta' command - exactly one argument, STA "
223 "address, is required.\n");
226 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
227 return wpa_ctrl_command(ctrl, buf);
231 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
236 printf("Invalid 'new_sta' command - exactly one argument, STA "
237 "address, is required.\n");
240 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
241 return wpa_ctrl_command(ctrl, buf);
245 #ifdef CONFIG_IEEE80211W
246 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
251 printf("Invalid 'sa_query' command - exactly one argument, "
252 "STA address, is required.\n");
255 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
256 return wpa_ctrl_command(ctrl, buf);
258 #endif /* CONFIG_IEEE80211W */
262 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
267 printf("Invalid 'wps_pin' command - exactly two arguments, "
268 "UUID and PIN, are required.\n");
271 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
272 return wpa_ctrl_command(ctrl, buf);
276 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
279 return wpa_ctrl_command(ctrl, "WPS_PBC");
283 #ifdef CONFIG_WPS_OOB
284 static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
290 if (argc != 3 && argc != 4) {
291 printf("Invalid WPS_OOB command: need three or four "
293 "- DEV_TYPE: use 'ufd' or 'nfc'\n"
294 "- PATH: path of OOB device like '/mnt'\n"
295 "- METHOD: OOB method 'pin-e' or 'pin-r', "
297 "- DEV_NAME: (only for NFC) device name like "
303 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
304 argv[0], argv[1], argv[2]);
306 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
307 argv[0], argv[1], argv[2], argv[3]);
308 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
309 printf("Too long WPS_OOB command.\n");
312 return wpa_ctrl_command(ctrl, cmd);
314 #endif /* CONFIG_WPS_OOB */
315 #endif /* CONFIG_WPS */
318 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
319 char *addr, size_t addr_len)
321 char buf[4096], *pos;
325 if (ctrl_conn == NULL) {
326 printf("Not connected to hostapd - command dropped.\n");
329 len = sizeof(buf) - 1;
330 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
333 printf("'%s' command timed out.\n", cmd);
335 } else if (ret < 0) {
336 printf("'%s' command failed.\n", cmd);
341 if (memcmp(buf, "FAIL", 4) == 0)
346 while (*pos != '\0' && *pos != '\n')
349 os_strlcpy(addr, buf, addr_len);
354 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
357 char addr[32], cmd[64];
359 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
362 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
363 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
369 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
371 printf("%s", commands_help);
376 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
379 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
384 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
386 hostapd_cli_quit = 1;
391 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
395 printf("Invalid LEVEL command: needs one argument (debug "
399 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
400 return wpa_ctrl_command(ctrl, cmd);
404 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
409 dir = opendir(ctrl_iface_dir);
411 printf("Control interface directory '%s' could not be "
412 "openned.\n", ctrl_iface_dir);
416 printf("Available interfaces:\n");
417 while ((dent = readdir(dir))) {
418 if (strcmp(dent->d_name, ".") == 0 ||
419 strcmp(dent->d_name, "..") == 0)
421 printf("%s\n", dent->d_name);
427 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
431 hostapd_cli_list_interfaces(ctrl);
435 hostapd_cli_close_connection();
437 ctrl_ifname = strdup(argv[0]);
439 if (hostapd_cli_open_connection(ctrl_ifname)) {
440 printf("Connected to interface '%s.\n", ctrl_ifname);
441 if (wpa_ctrl_attach(ctrl_conn) == 0) {
442 hostapd_cli_attached = 1;
444 printf("Warning: Failed to attach to "
448 printf("Could not connect to interface '%s' - re-trying\n",
455 struct hostapd_cli_cmd {
457 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
460 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
461 { "ping", hostapd_cli_cmd_ping },
462 { "mib", hostapd_cli_cmd_mib },
463 { "sta", hostapd_cli_cmd_sta },
464 { "all_sta", hostapd_cli_cmd_all_sta },
465 { "new_sta", hostapd_cli_cmd_new_sta },
466 #ifdef CONFIG_IEEE80211W
467 { "sa_query", hostapd_cli_cmd_sa_query },
468 #endif /* CONFIG_IEEE80211W */
470 { "wps_pin", hostapd_cli_cmd_wps_pin },
471 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
472 #ifdef CONFIG_WPS_OOB
473 { "wps_oob", hostapd_cli_cmd_wps_oob },
474 #endif /* CONFIG_WPS_OOB */
475 #endif /* CONFIG_WPS */
476 { "help", hostapd_cli_cmd_help },
477 { "interface", hostapd_cli_cmd_interface },
478 { "level", hostapd_cli_cmd_level },
479 { "license", hostapd_cli_cmd_license },
480 { "quit", hostapd_cli_cmd_quit },
485 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
487 struct hostapd_cli_cmd *cmd, *match = NULL;
491 cmd = hostapd_cli_commands;
493 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
501 printf("Ambiguous command '%s'; possible commands:", argv[0]);
502 cmd = hostapd_cli_commands;
504 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
506 printf(" %s", cmd->cmd);
511 } else if (count == 0) {
512 printf("Unknown command '%s'\n", argv[0]);
514 match->handler(ctrl, argc - 1, &argv[1]);
519 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read)
522 if (ctrl_conn == NULL)
524 while (wpa_ctrl_pending(ctrl)) {
526 size_t len = sizeof(buf) - 1;
527 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
529 if (in_read && first)
534 printf("Could not read pending message.\n");
541 static void hostapd_cli_interactive(void)
543 const int max_args = 10;
544 char cmd[256], *res, *argv[max_args], *pos;
547 printf("\nInteractive mode\n\n");
550 hostapd_cli_recv_pending(ctrl_conn, 0);
552 alarm(ping_interval);
553 res = fgets(cmd, sizeof(cmd), stdin);
558 while (*pos != '\0') {
574 if (argc == max_args)
576 while (*pos != '\0' && *pos != ' ')
582 wpa_request(ctrl_conn, argc, argv);
583 } while (!hostapd_cli_quit);
587 static void hostapd_cli_terminate(int sig)
589 hostapd_cli_close_connection();
594 static void hostapd_cli_alarm(int sig)
596 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
597 printf("Connection to hostapd lost - trying to reconnect\n");
598 hostapd_cli_close_connection();
601 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
603 printf("Connection to hostapd re-established\n");
604 if (wpa_ctrl_attach(ctrl_conn) == 0) {
605 hostapd_cli_attached = 1;
607 printf("Warning: Failed to attach to "
613 hostapd_cli_recv_pending(ctrl_conn, 1);
614 alarm(ping_interval);
618 int main(int argc, char *argv[])
621 int warning_displayed = 0;
625 c = getopt(argc, argv, "hG:i:p:v");
630 ping_interval = atoi(optarg);
636 printf("%s\n", hostapd_cli_version);
640 ctrl_ifname = strdup(optarg);
643 ctrl_iface_dir = optarg;
651 interactive = argc == optind;
654 printf("%s\n\n%s\n\n", hostapd_cli_version,
655 hostapd_cli_license);
659 if (ctrl_ifname == NULL) {
661 DIR *dir = opendir(ctrl_iface_dir);
663 while ((dent = readdir(dir))) {
664 if (strcmp(dent->d_name, ".") == 0 ||
665 strcmp(dent->d_name, "..") == 0)
667 printf("Selected interface '%s'\n",
669 ctrl_ifname = strdup(dent->d_name);
675 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
677 if (warning_displayed)
678 printf("Connection established.\n");
683 perror("Failed to connect to hostapd - "
688 if (!warning_displayed) {
689 printf("Could not connect to hostapd - re-trying\n");
690 warning_displayed = 1;
696 signal(SIGINT, hostapd_cli_terminate);
697 signal(SIGTERM, hostapd_cli_terminate);
698 signal(SIGALRM, hostapd_cli_alarm);
701 if (wpa_ctrl_attach(ctrl_conn) == 0) {
702 hostapd_cli_attached = 1;
704 printf("Warning: Failed to attach to hostapd.\n");
706 hostapd_cli_interactive();
708 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
711 hostapd_cli_close_connection();