2 * hostapd - command line interface for hostapd daemon
3 * Copyright (c) 2004-2010, 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.
18 #include "common/wpa_ctrl.h"
20 #include "common/version.h"
23 static const char *hostapd_cli_version =
24 "hostapd_cli v" VERSION_STR "\n"
25 "Copyright (c) 2004-2010, 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"
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 static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
250 printf("Invalid 'deauthenticate' command - exactly one "
251 "argument, STA address, is required.\n");
255 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
258 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
259 return wpa_ctrl_command(ctrl, buf);
263 static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
268 printf("Invalid 'disassociate' command - exactly one "
269 "argument, STA address, is required.\n");
273 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
276 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
277 return wpa_ctrl_command(ctrl, buf);
281 #ifdef CONFIG_IEEE80211W
282 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
287 printf("Invalid 'sa_query' command - exactly one argument, "
288 "STA address, is required.\n");
291 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
292 return wpa_ctrl_command(ctrl, buf);
294 #endif /* CONFIG_IEEE80211W */
298 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
303 printf("Invalid 'wps_pin' command - at least two arguments, "
304 "UUID and PIN, are required.\n");
308 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
309 argv[0], argv[1], argv[2]);
311 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
312 return wpa_ctrl_command(ctrl, buf);
316 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
319 return wpa_ctrl_command(ctrl, "WPS_PBC");
323 #ifdef CONFIG_WPS_OOB
324 static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
330 if (argc != 3 && argc != 4) {
331 printf("Invalid WPS_OOB command: need three or four "
333 "- DEV_TYPE: use 'ufd' or 'nfc'\n"
334 "- PATH: path of OOB device like '/mnt'\n"
335 "- METHOD: OOB method 'pin-e' or 'pin-r', "
337 "- DEV_NAME: (only for NFC) device name like "
343 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
344 argv[0], argv[1], argv[2]);
346 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
347 argv[0], argv[1], argv[2], argv[3]);
348 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
349 printf("Too long WPS_OOB command.\n");
352 return wpa_ctrl_command(ctrl, cmd);
354 #endif /* CONFIG_WPS_OOB */
355 #endif /* CONFIG_WPS */
358 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
359 char *addr, size_t addr_len)
361 char buf[4096], *pos;
365 if (ctrl_conn == NULL) {
366 printf("Not connected to hostapd - command dropped.\n");
369 len = sizeof(buf) - 1;
370 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
373 printf("'%s' command timed out.\n", cmd);
375 } else if (ret < 0) {
376 printf("'%s' command failed.\n", cmd);
381 if (memcmp(buf, "FAIL", 4) == 0)
386 while (*pos != '\0' && *pos != '\n')
389 os_strlcpy(addr, buf, addr_len);
394 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
397 char addr[32], cmd[64];
399 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
402 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
403 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
409 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
411 printf("%s", commands_help);
416 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
419 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
424 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
426 hostapd_cli_quit = 1;
431 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
435 printf("Invalid LEVEL command: needs one argument (debug "
439 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
440 return wpa_ctrl_command(ctrl, cmd);
444 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
449 dir = opendir(ctrl_iface_dir);
451 printf("Control interface directory '%s' could not be "
452 "openned.\n", ctrl_iface_dir);
456 printf("Available interfaces:\n");
457 while ((dent = readdir(dir))) {
458 if (strcmp(dent->d_name, ".") == 0 ||
459 strcmp(dent->d_name, "..") == 0)
461 printf("%s\n", dent->d_name);
467 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
471 hostapd_cli_list_interfaces(ctrl);
475 hostapd_cli_close_connection();
477 ctrl_ifname = strdup(argv[0]);
479 if (hostapd_cli_open_connection(ctrl_ifname)) {
480 printf("Connected to interface '%s.\n", ctrl_ifname);
481 if (wpa_ctrl_attach(ctrl_conn) == 0) {
482 hostapd_cli_attached = 1;
484 printf("Warning: Failed to attach to "
488 printf("Could not connect to interface '%s' - re-trying\n",
495 struct hostapd_cli_cmd {
497 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
500 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
501 { "ping", hostapd_cli_cmd_ping },
502 { "mib", hostapd_cli_cmd_mib },
503 { "sta", hostapd_cli_cmd_sta },
504 { "all_sta", hostapd_cli_cmd_all_sta },
505 { "new_sta", hostapd_cli_cmd_new_sta },
506 { "deauthenticate", hostapd_cli_cmd_deauthenticate },
507 { "disassociate", hostapd_cli_cmd_disassociate },
508 #ifdef CONFIG_IEEE80211W
509 { "sa_query", hostapd_cli_cmd_sa_query },
510 #endif /* CONFIG_IEEE80211W */
512 { "wps_pin", hostapd_cli_cmd_wps_pin },
513 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
514 #ifdef CONFIG_WPS_OOB
515 { "wps_oob", hostapd_cli_cmd_wps_oob },
516 #endif /* CONFIG_WPS_OOB */
517 #endif /* CONFIG_WPS */
518 { "help", hostapd_cli_cmd_help },
519 { "interface", hostapd_cli_cmd_interface },
520 { "level", hostapd_cli_cmd_level },
521 { "license", hostapd_cli_cmd_license },
522 { "quit", hostapd_cli_cmd_quit },
527 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
529 struct hostapd_cli_cmd *cmd, *match = NULL;
533 cmd = hostapd_cli_commands;
535 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
543 printf("Ambiguous command '%s'; possible commands:", argv[0]);
544 cmd = hostapd_cli_commands;
546 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
548 printf(" %s", cmd->cmd);
553 } else if (count == 0) {
554 printf("Unknown command '%s'\n", argv[0]);
556 match->handler(ctrl, argc - 1, &argv[1]);
561 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read)
564 if (ctrl_conn == NULL)
566 while (wpa_ctrl_pending(ctrl)) {
568 size_t len = sizeof(buf) - 1;
569 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
571 if (in_read && first)
576 printf("Could not read pending message.\n");
583 static void hostapd_cli_interactive(void)
585 const int max_args = 10;
586 char cmd[256], *res, *argv[max_args], *pos;
589 printf("\nInteractive mode\n\n");
592 hostapd_cli_recv_pending(ctrl_conn, 0);
594 alarm(ping_interval);
595 res = fgets(cmd, sizeof(cmd), stdin);
600 while (*pos != '\0') {
616 if (argc == max_args)
618 while (*pos != '\0' && *pos != ' ')
624 wpa_request(ctrl_conn, argc, argv);
625 } while (!hostapd_cli_quit);
629 static void hostapd_cli_terminate(int sig)
631 hostapd_cli_close_connection();
636 static void hostapd_cli_alarm(int sig)
638 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
639 printf("Connection to hostapd lost - trying to reconnect\n");
640 hostapd_cli_close_connection();
643 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
645 printf("Connection to hostapd re-established\n");
646 if (wpa_ctrl_attach(ctrl_conn) == 0) {
647 hostapd_cli_attached = 1;
649 printf("Warning: Failed to attach to "
655 hostapd_cli_recv_pending(ctrl_conn, 1);
656 alarm(ping_interval);
660 int main(int argc, char *argv[])
663 int warning_displayed = 0;
666 if (os_program_init())
670 c = getopt(argc, argv, "hG:i:p:v");
675 ping_interval = atoi(optarg);
681 printf("%s\n", hostapd_cli_version);
685 ctrl_ifname = strdup(optarg);
688 ctrl_iface_dir = optarg;
696 interactive = argc == optind;
699 printf("%s\n\n%s\n\n", hostapd_cli_version,
700 hostapd_cli_license);
704 if (ctrl_ifname == NULL) {
706 DIR *dir = opendir(ctrl_iface_dir);
708 while ((dent = readdir(dir))) {
709 if (strcmp(dent->d_name, ".") == 0 ||
710 strcmp(dent->d_name, "..") == 0)
712 printf("Selected interface '%s'\n",
714 ctrl_ifname = strdup(dent->d_name);
720 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
722 if (warning_displayed)
723 printf("Connection established.\n");
728 perror("Failed to connect to hostapd - "
733 if (!warning_displayed) {
734 printf("Could not connect to hostapd - re-trying\n");
735 warning_displayed = 1;
741 signal(SIGINT, hostapd_cli_terminate);
742 signal(SIGTERM, hostapd_cli_terminate);
743 signal(SIGALRM, hostapd_cli_alarm);
746 if (wpa_ctrl_attach(ctrl_conn) == 0) {
747 hostapd_cli_attached = 1;
749 printf("Warning: Failed to attach to hostapd.\n");
751 hostapd_cli_interactive();
753 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
756 hostapd_cli_close_connection();