Sync usage with man page.
[netbsd-mini2440.git] / dist / wpa / hostapd / hostapd_cli.c
blob0dfbbc15b7d9e96dac134e5712c97a4151a95122
1 /*
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
10 * license.
12 * See README and COPYING for more details.
15 #include "includes.h"
16 #include <dirent.h>
18 #include "wpa_ctrl.h"
19 #include "common.h"
20 #include "version.h"
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"
31 "\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"
39 "\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"
44 "\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"
48 "\n"
49 "Alternatively, this software may be distributed under the terms of the\n"
50 "BSD license.\n"
51 "\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"
54 "met:\n"
55 "\n"
56 "1. Redistributions of source code must retain the above copyright\n"
57 " notice, this list of conditions and the following disclaimer.\n"
58 "\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"
62 "\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"
66 "\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"
78 "\n";
80 static const char *commands_help =
81 "Commands:\n"
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 " help show this usage help\n"
87 " interface [ifname] show interfaces/select interface\n"
88 " level <debug level> change debug level\n"
89 " license show full hostapd_cli license\n"
90 " quit exit hostapd_cli\n";
92 static struct wpa_ctrl *ctrl_conn;
93 static int hostapd_cli_quit = 0;
94 static int hostapd_cli_attached = 0;
95 static const char *ctrl_iface_dir = "/var/run/hostapd";
96 static char *ctrl_ifname = NULL;
99 static void usage(void)
101 fprintf(stderr, "%s\n", hostapd_cli_version);
102 fprintf(stderr,
103 "\n"
104 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hv] "
105 "[command..]\n"
106 "\n"
107 "Options:\n"
108 " -h help (show this usage text)\n"
109 " -v shown version information\n"
110 " -p<path> path to find control sockets (default: "
111 "/var/run/hostapd)\n"
112 " -i<ifname> Interface to listen on (default: first "
113 "interface found in the\n"
114 " socket path)\n\n"
115 "%s",
116 commands_help);
120 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
122 char *cfile;
123 int flen;
125 if (ifname == NULL)
126 return NULL;
128 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
129 cfile = malloc(flen);
130 if (cfile == NULL)
131 return NULL;
132 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
134 ctrl_conn = wpa_ctrl_open(cfile);
135 free(cfile);
136 return ctrl_conn;
140 static void hostapd_cli_close_connection(void)
142 if (ctrl_conn == NULL)
143 return;
145 if (hostapd_cli_attached) {
146 wpa_ctrl_detach(ctrl_conn);
147 hostapd_cli_attached = 0;
149 wpa_ctrl_close(ctrl_conn);
150 ctrl_conn = NULL;
154 static void hostapd_cli_msg_cb(char *msg, size_t len)
156 printf("%s\n", msg);
160 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
162 char buf[4096];
163 size_t len;
164 int ret;
166 if (ctrl_conn == NULL) {
167 printf("Not connected to hostapd - command dropped.\n");
168 return -1;
170 len = sizeof(buf) - 1;
171 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
172 hostapd_cli_msg_cb);
173 if (ret == -2) {
174 printf("'%s' command timed out.\n", cmd);
175 return -2;
176 } else if (ret < 0) {
177 printf("'%s' command failed.\n", cmd);
178 return -1;
180 if (print) {
181 buf[len] = '\0';
182 printf("%s", buf);
184 return 0;
188 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
190 return _wpa_ctrl_command(ctrl, cmd, 1);
194 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
196 return wpa_ctrl_command(ctrl, "PING");
200 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
202 return wpa_ctrl_command(ctrl, "MIB");
206 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
208 char buf[64];
209 if (argc != 1) {
210 printf("Invalid 'sta' command - exactly one argument, STA "
211 "address, is required.\n");
212 return -1;
214 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
215 return wpa_ctrl_command(ctrl, buf);
219 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
220 char *argv[])
222 char buf[64];
223 if (argc != 1) {
224 printf("Invalid 'new_sta' command - exactly one argument, STA "
225 "address, is required.\n");
226 return -1;
228 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
229 return wpa_ctrl_command(ctrl, buf);
233 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
234 char *addr, size_t addr_len)
236 char buf[4096], *pos;
237 size_t len;
238 int ret;
240 if (ctrl_conn == NULL) {
241 printf("Not connected to hostapd - command dropped.\n");
242 return -1;
244 len = sizeof(buf) - 1;
245 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
246 hostapd_cli_msg_cb);
247 if (ret == -2) {
248 printf("'%s' command timed out.\n", cmd);
249 return -2;
250 } else if (ret < 0) {
251 printf("'%s' command failed.\n", cmd);
252 return -1;
255 buf[len] = '\0';
256 if (memcmp(buf, "FAIL", 4) == 0)
257 return -1;
258 printf("%s", buf);
260 pos = buf;
261 while (*pos != '\0' && *pos != '\n')
262 pos++;
263 *pos = '\0';
264 os_strlcpy(addr, buf, addr_len);
265 return 0;
269 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
270 char *argv[])
272 char addr[32], cmd[64];
274 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
275 return 0;
276 do {
277 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
278 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
280 return -1;
284 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
286 printf("%s", commands_help);
287 return 0;
291 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
292 char *argv[])
294 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
295 return 0;
299 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
301 hostapd_cli_quit = 1;
302 return 0;
306 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
308 char cmd[256];
309 if (argc != 1) {
310 printf("Invalid LEVEL command: needs one argument (debug "
311 "level)\n");
312 return 0;
314 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
315 return wpa_ctrl_command(ctrl, cmd);
319 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
321 struct dirent *dent;
322 DIR *dir;
324 dir = opendir(ctrl_iface_dir);
325 if (dir == NULL) {
326 printf("Control interface directory '%s' could not be "
327 "openned.\n", ctrl_iface_dir);
328 return;
331 printf("Available interfaces:\n");
332 while ((dent = readdir(dir))) {
333 if (strcmp(dent->d_name, ".") == 0 ||
334 strcmp(dent->d_name, "..") == 0)
335 continue;
336 printf("%s\n", dent->d_name);
338 closedir(dir);
342 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
343 char *argv[])
345 if (argc < 1) {
346 hostapd_cli_list_interfaces(ctrl);
347 return 0;
350 hostapd_cli_close_connection();
351 free(ctrl_ifname);
352 ctrl_ifname = strdup(argv[0]);
354 if (hostapd_cli_open_connection(ctrl_ifname)) {
355 printf("Connected to interface '%s.\n", ctrl_ifname);
356 if (wpa_ctrl_attach(ctrl_conn) == 0) {
357 hostapd_cli_attached = 1;
358 } else {
359 printf("Warning: Failed to attach to "
360 "hostapd.\n");
362 } else {
363 printf("Could not connect to interface '%s' - re-trying\n",
364 ctrl_ifname);
366 return 0;
370 struct hostapd_cli_cmd {
371 const char *cmd;
372 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
375 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
376 { "ping", hostapd_cli_cmd_ping },
377 { "mib", hostapd_cli_cmd_mib },
378 { "sta", hostapd_cli_cmd_sta },
379 { "all_sta", hostapd_cli_cmd_all_sta },
380 { "new_sta", hostapd_cli_cmd_new_sta },
381 { "help", hostapd_cli_cmd_help },
382 { "interface", hostapd_cli_cmd_interface },
383 { "level", hostapd_cli_cmd_level },
384 { "license", hostapd_cli_cmd_license },
385 { "quit", hostapd_cli_cmd_quit },
386 { NULL, NULL }
390 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
392 struct hostapd_cli_cmd *cmd, *match = NULL;
393 int count;
395 count = 0;
396 cmd = hostapd_cli_commands;
397 while (cmd->cmd) {
398 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
399 match = cmd;
400 count++;
402 cmd++;
405 if (count > 1) {
406 printf("Ambiguous command '%s'; possible commands:", argv[0]);
407 cmd = hostapd_cli_commands;
408 while (cmd->cmd) {
409 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
410 0) {
411 printf(" %s", cmd->cmd);
413 cmd++;
415 printf("\n");
416 } else if (count == 0) {
417 printf("Unknown command '%s'\n", argv[0]);
418 } else {
419 match->handler(ctrl, argc - 1, &argv[1]);
424 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read)
426 int first = 1;
427 if (ctrl_conn == NULL)
428 return;
429 while (wpa_ctrl_pending(ctrl)) {
430 char buf[256];
431 size_t len = sizeof(buf) - 1;
432 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
433 buf[len] = '\0';
434 if (in_read && first)
435 printf("\n");
436 first = 0;
437 printf("%s\n", buf);
438 } else {
439 printf("Could not read pending message.\n");
440 break;
446 static void hostapd_cli_interactive(void)
448 #define max_args 10
449 char cmd[256], *res, *argv[max_args], *pos;
450 int argc;
452 printf("\nInteractive mode\n\n");
454 do {
455 hostapd_cli_recv_pending(ctrl_conn, 0);
456 printf("> ");
457 alarm(1);
458 res = fgets(cmd, sizeof(cmd), stdin);
459 alarm(0);
460 if (res == NULL)
461 break;
462 pos = cmd;
463 while (*pos != '\0') {
464 if (*pos == '\n') {
465 *pos = '\0';
466 break;
468 pos++;
470 argc = 0;
471 pos = cmd;
472 for (;;) {
473 while (*pos == ' ')
474 pos++;
475 if (*pos == '\0')
476 break;
477 argv[argc] = pos;
478 argc++;
479 if (argc == max_args)
480 break;
481 while (*pos != '\0' && *pos != ' ')
482 pos++;
483 if (*pos == ' ')
484 *pos++ = '\0';
486 if (argc)
487 wpa_request(ctrl_conn, argc, argv);
488 } while (!hostapd_cli_quit);
492 static void hostapd_cli_terminate(int sig)
494 hostapd_cli_close_connection();
495 exit(0);
499 static void hostapd_cli_alarm(int sig)
501 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
502 printf("Connection to hostapd lost - trying to reconnect\n");
503 hostapd_cli_close_connection();
505 if (!ctrl_conn) {
506 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
507 if (ctrl_conn) {
508 printf("Connection to hostapd re-established\n");
509 if (wpa_ctrl_attach(ctrl_conn) == 0) {
510 hostapd_cli_attached = 1;
511 } else {
512 printf("Warning: Failed to attach to "
513 "hostapd.\n");
517 if (ctrl_conn)
518 hostapd_cli_recv_pending(ctrl_conn, 1);
519 alarm(1);
523 int main(int argc, char *argv[])
525 int interactive;
526 int warning_displayed = 0;
527 int c;
529 for (;;) {
530 c = getopt(argc, argv, "hi:p:v");
531 if (c < 0)
532 break;
533 switch (c) {
534 case 'h':
535 usage();
536 return 0;
537 case 'v':
538 printf("%s\n", hostapd_cli_version);
539 return 0;
540 case 'i':
541 free(ctrl_ifname);
542 ctrl_ifname = strdup(optarg);
543 break;
544 case 'p':
545 ctrl_iface_dir = optarg;
546 break;
547 default:
548 usage();
549 return -1;
553 interactive = argc == optind;
555 if (interactive) {
556 printf("%s\n\n%s\n\n", hostapd_cli_version,
557 hostapd_cli_license);
560 for (;;) {
561 if (ctrl_ifname == NULL) {
562 struct dirent *dent;
563 DIR *dir = opendir(ctrl_iface_dir);
564 if (dir) {
565 while ((dent = readdir(dir))) {
566 if (strcmp(dent->d_name, ".") == 0 ||
567 strcmp(dent->d_name, "..") == 0)
568 continue;
569 printf("Selected interface '%s'\n",
570 dent->d_name);
571 ctrl_ifname = strdup(dent->d_name);
572 break;
574 closedir(dir);
577 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
578 if (ctrl_conn) {
579 if (warning_displayed)
580 printf("Connection established.\n");
581 break;
584 if (!interactive) {
585 perror("Failed to connect to hostapd - "
586 "wpa_ctrl_open");
587 return -1;
590 if (!warning_displayed) {
591 printf("Could not connect to hostapd - re-trying\n");
592 warning_displayed = 1;
594 sleep(1);
595 continue;
598 signal(SIGINT, hostapd_cli_terminate);
599 signal(SIGTERM, hostapd_cli_terminate);
600 signal(SIGALRM, hostapd_cli_alarm);
602 if (interactive) {
603 if (wpa_ctrl_attach(ctrl_conn) == 0) {
604 hostapd_cli_attached = 1;
605 } else {
606 printf("Warning: Failed to attach to hostapd.\n");
608 hostapd_cli_interactive();
609 } else
610 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
612 free(ctrl_ifname);
613 hostapd_cli_close_connection();
614 return 0;