2 * hostapd - command line interface for hostapd daemon
3 * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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.
22 #include "hostapd_ctrl.h"
26 static const char *hostapd_cli_version =
27 "hostapd_cli v" VERSION_STR "\n"
28 "Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi> and contributors";
31 static const char *hostapd_cli_license =
32 "This program is free software. You can distribute it and/or modify it\n"
33 "under the terms of the GNU General Public License version 2.\n"
35 "Alternatively, this software may be distributed under the terms of the\n"
36 "BSD license. See README and COPYING for more details.\n";
38 static const char *hostapd_cli_full_license =
39 "This program is free software; you can redistribute it and/or modify\n"
40 "it under the terms of the GNU General Public License version 2 as\n"
41 "published by the Free Software Foundation.\n"
43 "This program is distributed in the hope that it will be useful,\n"
44 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
45 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
46 "GNU General Public License for more details.\n"
48 "You should have received a copy of the GNU General Public License\n"
49 "along with this program; if not, write to the Free Software\n"
50 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
52 "Alternatively, this software may be distributed under the terms of the\n"
55 "Redistribution and use in source and binary forms, with or without\n"
56 "modification, are permitted provided that the following conditions are\n"
59 "1. Redistributions of source code must retain the above copyright\n"
60 " notice, this list of conditions and the following disclaimer.\n"
62 "2. Redistributions in binary form must reproduce the above copyright\n"
63 " notice, this list of conditions and the following disclaimer in the\n"
64 " documentation and/or other materials provided with the distribution.\n"
66 "3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
67 " names of its contributors may be used to endorse or promote products\n"
68 " derived from this software without specific prior written permission.\n"
70 "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
71 "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
72 "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
73 "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
74 "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
75 "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
76 "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
77 "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
78 "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
79 "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
80 "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
83 static const char *commands_help =
85 " mib = get MIB variables (dot1x, dot11, radius)\n"
86 " sta <addr> = get MIB vatiables for one station\n"
87 " all_sta = get MIB variables for all stations\n"
88 " help = show this usage help\n"
89 " interface [ifname] = show interfaces/select interface\n"
90 " level <debug level> = change debug level\n"
91 " license = show full hostapd_cli license\n"
92 " quit = exit hostapd_cli\n";
94 static struct hostapd_ctrl *ctrl_conn;
95 static int hostapd_cli_quit = 0;
96 static int hostapd_cli_attached = 0;
97 static const char *ctrl_iface_dir = "/var/run/hostapd";
98 static char *ctrl_ifname = NULL;
101 static void usage(void)
103 printf("hostapd_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hv] "
105 " -h = help (show this usage text)\n"
106 " -v = shown version information\n"
107 " default path: /var/run/hostapd\n"
108 " default interface: first interface found in socket path\n"
114 static struct hostapd_ctrl * hostapd_cli_open_connection(const char *ifname)
122 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
123 cfile = malloc(flen);
126 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
128 ctrl_conn = hostapd_ctrl_open(cfile);
134 static void hostapd_cli_close_connection(void)
136 if (ctrl_conn == NULL)
139 if (hostapd_cli_attached) {
140 hostapd_ctrl_detach(ctrl_conn);
141 hostapd_cli_attached = 0;
143 hostapd_ctrl_close(ctrl_conn);
148 static void hostapd_cli_msg_cb(char *msg, size_t len)
154 static int _hostapd_ctrl_command(struct hostapd_ctrl *ctrl, char *cmd,
161 if (ctrl_conn == NULL) {
162 printf("Not connected to hostapd - command dropped.\n");
165 len = sizeof(buf) - 1;
166 ret = hostapd_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
169 printf("'%s' command timed out.\n", cmd);
171 } else if (ret < 0) {
172 printf("'%s' command failed.\n", cmd);
183 static inline int hostapd_ctrl_command(struct hostapd_ctrl *ctrl, char *cmd)
185 return _hostapd_ctrl_command(ctrl, cmd, 1);
189 static int hostapd_cli_cmd_ping(struct hostapd_ctrl *ctrl, int argc,
192 return hostapd_ctrl_command(ctrl, "PING");
196 static int hostapd_cli_cmd_mib(struct hostapd_ctrl *ctrl, int argc,
199 return hostapd_ctrl_command(ctrl, "MIB");
203 static int hostapd_cli_cmd_sta(struct hostapd_ctrl *ctrl, int argc,
208 printf("Invalid 'sta' command - exactly one argument, STA "
209 "address, is required.\n");
212 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
213 return hostapd_ctrl_command(ctrl, buf);
217 static int hostapd_ctrl_command_sta(struct hostapd_ctrl *ctrl, char *cmd,
218 char *addr, size_t addr_len)
220 char buf[4096], *pos;
224 if (ctrl_conn == NULL) {
225 printf("Not connected to hostapd - command dropped.\n");
228 len = sizeof(buf) - 1;
229 ret = hostapd_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
232 printf("'%s' command timed out.\n", cmd);
234 } else if (ret < 0) {
235 printf("'%s' command failed.\n", cmd);
240 if (memcmp(buf, "FAIL", 4) == 0)
245 while (*pos != '\0' && *pos != '\n')
248 snprintf(addr, addr_len, "%s", buf);
253 static int hostapd_cli_cmd_all_sta(struct hostapd_ctrl *ctrl, int argc,
256 char addr[32], cmd[64];
258 if (hostapd_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
261 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
262 } while (hostapd_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
268 static int hostapd_cli_cmd_help(struct hostapd_ctrl *ctrl, int argc,
271 printf("%s", commands_help);
276 static int hostapd_cli_cmd_license(struct hostapd_ctrl *ctrl, int argc,
279 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
284 static int hostapd_cli_cmd_quit(struct hostapd_ctrl *ctrl, int argc,
287 hostapd_cli_quit = 1;
292 static int hostapd_cli_cmd_level(struct hostapd_ctrl *ctrl, int argc,
297 printf("Invalid LEVEL command: needs one argument (debug "
301 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
302 return hostapd_ctrl_command(ctrl, cmd);
306 static void hostapd_cli_list_interfaces(struct hostapd_ctrl *ctrl)
311 dir = opendir(ctrl_iface_dir);
313 printf("Control interface directory '%s' could not be "
314 "openned.\n", ctrl_iface_dir);
318 printf("Available interfaces:\n");
319 while ((dent = readdir(dir))) {
320 if (strcmp(dent->d_name, ".") == 0 ||
321 strcmp(dent->d_name, "..") == 0)
323 printf("%s\n", dent->d_name);
329 static int hostapd_cli_cmd_interface(struct hostapd_ctrl *ctrl, int argc,
333 hostapd_cli_list_interfaces(ctrl);
337 hostapd_cli_close_connection();
339 ctrl_ifname = strdup(argv[0]);
341 if (hostapd_cli_open_connection(ctrl_ifname)) {
342 printf("Connected to interface '%s.\n", ctrl_ifname);
343 if (hostapd_ctrl_attach(ctrl_conn) == 0) {
344 hostapd_cli_attached = 1;
346 printf("Warning: Failed to attach to "
350 printf("Could not connect to interface '%s' - re-trying\n",
357 struct hostapd_cli_cmd {
359 int (*handler)(struct hostapd_ctrl *ctrl, int argc, char *argv[]);
362 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
363 { "ping", hostapd_cli_cmd_ping },
364 { "mib", hostapd_cli_cmd_mib },
365 { "sta", hostapd_cli_cmd_sta },
366 { "all_sta", hostapd_cli_cmd_all_sta },
367 { "help", hostapd_cli_cmd_help },
368 { "interface", hostapd_cli_cmd_interface },
369 { "level", hostapd_cli_cmd_level },
370 { "license", hostapd_cli_cmd_license },
371 { "quit", hostapd_cli_cmd_quit },
376 static void wpa_request(struct hostapd_ctrl *ctrl, int argc, char *argv[])
378 struct hostapd_cli_cmd *cmd, *match = NULL;
382 cmd = hostapd_cli_commands;
384 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
392 printf("Ambiguous command '%s'; possible commands:", argv[0]);
393 cmd = hostapd_cli_commands;
395 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
397 printf(" %s", cmd->cmd);
402 } else if (count == 0) {
403 printf("Unknown command '%s'\n", argv[0]);
405 match->handler(ctrl, argc - 1, &argv[1]);
410 static void hostapd_cli_recv_pending(struct hostapd_ctrl *ctrl, int in_read)
413 if (ctrl_conn == NULL)
415 while (hostapd_ctrl_pending(ctrl)) {
417 size_t len = sizeof(buf) - 1;
418 if (hostapd_ctrl_recv(ctrl, buf, &len) == 0) {
420 if (in_read && first)
425 printf("Could not read pending message.\n");
432 static void hostapd_cli_interactive(void)
434 const int max_args = 10;
435 char cmd[256], *res, *argv[max_args], *pos;
438 printf("\nInteractive mode\n\n");
441 hostapd_cli_recv_pending(ctrl_conn, 0);
444 res = fgets(cmd, sizeof(cmd), stdin);
449 while (*pos != '\0') {
465 if (argc == max_args)
467 while (*pos != '\0' && *pos != ' ')
473 wpa_request(ctrl_conn, argc, argv);
474 } while (!hostapd_cli_quit);
478 static void hostapd_cli_terminate(int sig)
480 hostapd_cli_close_connection();
485 static void hostapd_cli_alarm(int sig)
487 if (ctrl_conn && _hostapd_ctrl_command(ctrl_conn, "PING", 0)) {
488 printf("Connection to hostapd lost - trying to reconnect\n");
489 hostapd_cli_close_connection();
492 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
494 printf("Connection to hostapd re-established\n");
495 if (hostapd_ctrl_attach(ctrl_conn) == 0) {
496 hostapd_cli_attached = 1;
498 printf("Warning: Failed to attach to "
504 hostapd_cli_recv_pending(ctrl_conn, 1);
509 int main(int argc, char *argv[])
512 int warning_displayed = 0;
516 c = getopt(argc, argv, "hi:p:v");
524 printf("%s\n", hostapd_cli_version);
527 ctrl_ifname = strdup(optarg);
530 ctrl_iface_dir = optarg;
538 interactive = argc == optind;
541 printf("%s\n\n%s\n\n", hostapd_cli_version,
542 hostapd_cli_license);
546 if (ctrl_ifname == NULL) {
548 DIR *dir = opendir(ctrl_iface_dir);
550 while ((dent = readdir(dir))) {
551 if (strcmp(dent->d_name, ".") == 0 ||
552 strcmp(dent->d_name, "..") == 0)
554 printf("Selected interface '%s'\n",
556 ctrl_ifname = strdup(dent->d_name);
562 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
564 if (warning_displayed)
565 printf("Connection established.\n");
570 perror("Failed to connect to hostapd - "
571 "hostapd_ctrl_open");
575 if (!warning_displayed) {
576 printf("Could not connect to hostapd - re-trying\n");
577 warning_displayed = 1;
583 signal(SIGINT, hostapd_cli_terminate);
584 signal(SIGTERM, hostapd_cli_terminate);
585 signal(SIGALRM, hostapd_cli_alarm);
588 if (hostapd_ctrl_attach(ctrl_conn) == 0) {
589 hostapd_cli_attached = 1;
591 printf("Warning: Failed to attach to hostapd.\n");
593 hostapd_cli_interactive();
595 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
598 hostapd_cli_close_connection();