Actually hook powernow.4 into the build.
[dragonfly.git] / contrib / hostapd / hostapd / hostapd_cli.c
blobc2ecd4e23cae838ea1d524bbff2bc707194fc99e
1 /*
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
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-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"
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 #ifdef CONFIG_IEEE80211W
87 " sa_query <addr> send SA Query to a station\n"
88 #endif /* CONFIG_IEEE80211W */
89 #ifdef CONFIG_WPS
90 " wps_pin <uuid> <pin> [timeout] add WPS Enrollee PIN (Device Password)\n"
91 " wps_pbc indicate button pushed to initiate PBC\n"
92 #endif /* CONFIG_WPS */
93 " help show this usage help\n"
94 " interface [ifname] show interfaces/select interface\n"
95 " level <debug level> change debug level\n"
96 " license show full hostapd_cli license\n"
97 " quit exit hostapd_cli\n";
99 static struct wpa_ctrl *ctrl_conn;
100 static int hostapd_cli_quit = 0;
101 static int hostapd_cli_attached = 0;
102 static const char *ctrl_iface_dir = "/var/run/hostapd";
103 static char *ctrl_ifname = NULL;
104 static int ping_interval = 5;
107 static void usage(void)
109 fprintf(stderr, "%s\n", hostapd_cli_version);
110 fprintf(stderr,
111 "\n"
112 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hv] "
113 "[-G<ping interval>] \\\n"
114 " [command..]\n"
115 "\n"
116 "Options:\n"
117 " -h help (show this usage text)\n"
118 " -v shown version information\n"
119 " -p<path> path to find control sockets (default: "
120 "/var/run/hostapd)\n"
121 " -i<ifname> Interface to listen on (default: first "
122 "interface found in the\n"
123 " socket path)\n\n"
124 "%s",
125 commands_help);
129 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
131 char *cfile;
132 int flen;
134 if (ifname == NULL)
135 return NULL;
137 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
138 cfile = malloc(flen);
139 if (cfile == NULL)
140 return NULL;
141 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
143 ctrl_conn = wpa_ctrl_open(cfile);
144 free(cfile);
145 return ctrl_conn;
149 static void hostapd_cli_close_connection(void)
151 if (ctrl_conn == NULL)
152 return;
154 if (hostapd_cli_attached) {
155 wpa_ctrl_detach(ctrl_conn);
156 hostapd_cli_attached = 0;
158 wpa_ctrl_close(ctrl_conn);
159 ctrl_conn = NULL;
163 static void hostapd_cli_msg_cb(char *msg, size_t len)
165 printf("%s\n", msg);
169 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
171 char buf[4096];
172 size_t len;
173 int ret;
175 if (ctrl_conn == NULL) {
176 printf("Not connected to hostapd - command dropped.\n");
177 return -1;
179 len = sizeof(buf) - 1;
180 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
181 hostapd_cli_msg_cb);
182 if (ret == -2) {
183 printf("'%s' command timed out.\n", cmd);
184 return -2;
185 } else if (ret < 0) {
186 printf("'%s' command failed.\n", cmd);
187 return -1;
189 if (print) {
190 buf[len] = '\0';
191 printf("%s", buf);
193 return 0;
197 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
199 return _wpa_ctrl_command(ctrl, cmd, 1);
203 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
205 return wpa_ctrl_command(ctrl, "PING");
209 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
211 return wpa_ctrl_command(ctrl, "MIB");
215 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
217 char buf[64];
218 if (argc != 1) {
219 printf("Invalid 'sta' command - exactly one argument, STA "
220 "address, is required.\n");
221 return -1;
223 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
224 return wpa_ctrl_command(ctrl, buf);
228 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
229 char *argv[])
231 char buf[64];
232 if (argc != 1) {
233 printf("Invalid 'new_sta' command - exactly one argument, STA "
234 "address, is required.\n");
235 return -1;
237 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
238 return wpa_ctrl_command(ctrl, buf);
242 #ifdef CONFIG_IEEE80211W
243 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
244 char *argv[])
246 char buf[64];
247 if (argc != 1) {
248 printf("Invalid 'sa_query' command - exactly one argument, "
249 "STA address, is required.\n");
250 return -1;
252 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
253 return wpa_ctrl_command(ctrl, buf);
255 #endif /* CONFIG_IEEE80211W */
258 #ifdef CONFIG_WPS
259 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
260 char *argv[])
262 char buf[64];
263 if (argc < 2) {
264 printf("Invalid 'wps_pin' command - at least two arguments, "
265 "UUID and PIN, are required.\n");
266 return -1;
268 if (argc > 2)
269 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
270 argv[0], argv[1], argv[2]);
271 else
272 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
273 return wpa_ctrl_command(ctrl, buf);
277 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
278 char *argv[])
280 return wpa_ctrl_command(ctrl, "WPS_PBC");
282 #endif /* CONFIG_WPS */
285 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
286 char *addr, size_t addr_len)
288 char buf[4096], *pos;
289 size_t len;
290 int ret;
292 if (ctrl_conn == NULL) {
293 printf("Not connected to hostapd - command dropped.\n");
294 return -1;
296 len = sizeof(buf) - 1;
297 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
298 hostapd_cli_msg_cb);
299 if (ret == -2) {
300 printf("'%s' command timed out.\n", cmd);
301 return -2;
302 } else if (ret < 0) {
303 printf("'%s' command failed.\n", cmd);
304 return -1;
307 buf[len] = '\0';
308 if (memcmp(buf, "FAIL", 4) == 0)
309 return -1;
310 printf("%s", buf);
312 pos = buf;
313 while (*pos != '\0' && *pos != '\n')
314 pos++;
315 *pos = '\0';
316 os_strlcpy(addr, buf, addr_len);
317 return 0;
321 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
322 char *argv[])
324 char addr[32], cmd[64];
326 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
327 return 0;
328 do {
329 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
330 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
332 return -1;
336 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
338 printf("%s", commands_help);
339 return 0;
343 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
344 char *argv[])
346 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
347 return 0;
351 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
353 hostapd_cli_quit = 1;
354 return 0;
358 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
360 char cmd[256];
361 if (argc != 1) {
362 printf("Invalid LEVEL command: needs one argument (debug "
363 "level)\n");
364 return 0;
366 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
367 return wpa_ctrl_command(ctrl, cmd);
371 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
373 struct dirent *dent;
374 DIR *dir;
376 dir = opendir(ctrl_iface_dir);
377 if (dir == NULL) {
378 printf("Control interface directory '%s' could not be "
379 "openned.\n", ctrl_iface_dir);
380 return;
383 printf("Available interfaces:\n");
384 while ((dent = readdir(dir))) {
385 if (strcmp(dent->d_name, ".") == 0 ||
386 strcmp(dent->d_name, "..") == 0)
387 continue;
388 printf("%s\n", dent->d_name);
390 closedir(dir);
394 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
395 char *argv[])
397 if (argc < 1) {
398 hostapd_cli_list_interfaces(ctrl);
399 return 0;
402 hostapd_cli_close_connection();
403 free(ctrl_ifname);
404 ctrl_ifname = strdup(argv[0]);
406 if (hostapd_cli_open_connection(ctrl_ifname)) {
407 printf("Connected to interface '%s.\n", ctrl_ifname);
408 if (wpa_ctrl_attach(ctrl_conn) == 0) {
409 hostapd_cli_attached = 1;
410 } else {
411 printf("Warning: Failed to attach to "
412 "hostapd.\n");
414 } else {
415 printf("Could not connect to interface '%s' - re-trying\n",
416 ctrl_ifname);
418 return 0;
422 struct hostapd_cli_cmd {
423 const char *cmd;
424 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
427 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
428 { "ping", hostapd_cli_cmd_ping },
429 { "mib", hostapd_cli_cmd_mib },
430 { "sta", hostapd_cli_cmd_sta },
431 { "all_sta", hostapd_cli_cmd_all_sta },
432 { "new_sta", hostapd_cli_cmd_new_sta },
433 #ifdef CONFIG_IEEE80211W
434 { "sa_query", hostapd_cli_cmd_sa_query },
435 #endif /* CONFIG_IEEE80211W */
436 #ifdef CONFIG_WPS
437 { "wps_pin", hostapd_cli_cmd_wps_pin },
438 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
439 #endif /* CONFIG_WPS */
440 { "help", hostapd_cli_cmd_help },
441 { "interface", hostapd_cli_cmd_interface },
442 { "level", hostapd_cli_cmd_level },
443 { "license", hostapd_cli_cmd_license },
444 { "quit", hostapd_cli_cmd_quit },
445 { NULL, NULL }
449 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
451 struct hostapd_cli_cmd *cmd, *match = NULL;
452 int count;
454 count = 0;
455 cmd = hostapd_cli_commands;
456 while (cmd->cmd) {
457 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
458 match = cmd;
459 count++;
461 cmd++;
464 if (count > 1) {
465 printf("Ambiguous command '%s'; possible commands:", argv[0]);
466 cmd = hostapd_cli_commands;
467 while (cmd->cmd) {
468 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
469 0) {
470 printf(" %s", cmd->cmd);
472 cmd++;
474 printf("\n");
475 } else if (count == 0) {
476 printf("Unknown command '%s'\n", argv[0]);
477 } else {
478 match->handler(ctrl, argc - 1, &argv[1]);
483 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read)
485 int first = 1;
486 if (ctrl_conn == NULL)
487 return;
488 while (wpa_ctrl_pending(ctrl)) {
489 char buf[256];
490 size_t len = sizeof(buf) - 1;
491 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
492 buf[len] = '\0';
493 if (in_read && first)
494 printf("\n");
495 first = 0;
496 printf("%s\n", buf);
497 } else {
498 printf("Could not read pending message.\n");
499 break;
505 static void hostapd_cli_interactive(void)
507 const int max_args = 10;
508 char cmd[256], *res, *argv[max_args], *pos;
509 int argc;
511 printf("\nInteractive mode\n\n");
513 do {
514 hostapd_cli_recv_pending(ctrl_conn, 0);
515 printf("> ");
516 alarm(ping_interval);
517 res = fgets(cmd, sizeof(cmd), stdin);
518 alarm(0);
519 if (res == NULL)
520 break;
521 pos = cmd;
522 while (*pos != '\0') {
523 if (*pos == '\n') {
524 *pos = '\0';
525 break;
527 pos++;
529 argc = 0;
530 pos = cmd;
531 for (;;) {
532 while (*pos == ' ')
533 pos++;
534 if (*pos == '\0')
535 break;
536 argv[argc] = pos;
537 argc++;
538 if (argc == max_args)
539 break;
540 while (*pos != '\0' && *pos != ' ')
541 pos++;
542 if (*pos == ' ')
543 *pos++ = '\0';
545 if (argc)
546 wpa_request(ctrl_conn, argc, argv);
547 } while (!hostapd_cli_quit);
551 static void hostapd_cli_terminate(int sig)
553 hostapd_cli_close_connection();
554 exit(0);
558 static void hostapd_cli_alarm(int sig)
560 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
561 printf("Connection to hostapd lost - trying to reconnect\n");
562 hostapd_cli_close_connection();
564 if (!ctrl_conn) {
565 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
566 if (ctrl_conn) {
567 printf("Connection to hostapd re-established\n");
568 if (wpa_ctrl_attach(ctrl_conn) == 0) {
569 hostapd_cli_attached = 1;
570 } else {
571 printf("Warning: Failed to attach to "
572 "hostapd.\n");
576 if (ctrl_conn)
577 hostapd_cli_recv_pending(ctrl_conn, 1);
578 alarm(ping_interval);
582 int main(int argc, char *argv[])
584 int interactive;
585 int warning_displayed = 0;
586 int c;
588 for (;;) {
589 c = getopt(argc, argv, "hG:i:p:v");
590 if (c < 0)
591 break;
592 switch (c) {
593 case 'G':
594 ping_interval = atoi(optarg);
595 break;
596 case 'h':
597 usage();
598 return 0;
599 case 'v':
600 printf("%s\n", hostapd_cli_version);
601 return 0;
602 case 'i':
603 free(ctrl_ifname);
604 ctrl_ifname = strdup(optarg);
605 break;
606 case 'p':
607 ctrl_iface_dir = optarg;
608 break;
609 default:
610 usage();
611 return -1;
615 interactive = argc == optind;
617 if (interactive) {
618 printf("%s\n\n%s\n\n", hostapd_cli_version,
619 hostapd_cli_license);
622 for (;;) {
623 if (ctrl_ifname == NULL) {
624 struct dirent *dent;
625 DIR *dir = opendir(ctrl_iface_dir);
626 if (dir) {
627 while ((dent = readdir(dir))) {
628 if (strcmp(dent->d_name, ".") == 0 ||
629 strcmp(dent->d_name, "..") == 0)
630 continue;
631 printf("Selected interface '%s'\n",
632 dent->d_name);
633 ctrl_ifname = strdup(dent->d_name);
634 break;
636 closedir(dir);
639 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
640 if (ctrl_conn) {
641 if (warning_displayed)
642 printf("Connection established.\n");
643 break;
646 if (!interactive) {
647 perror("Failed to connect to hostapd - "
648 "wpa_ctrl_open");
649 return -1;
652 if (!warning_displayed) {
653 printf("Could not connect to hostapd - re-trying\n");
654 warning_displayed = 1;
656 sleep(1);
657 continue;
660 signal(SIGINT, hostapd_cli_terminate);
661 signal(SIGTERM, hostapd_cli_terminate);
662 signal(SIGALRM, hostapd_cli_alarm);
664 if (interactive) {
665 if (wpa_ctrl_attach(ctrl_conn) == 0) {
666 hostapd_cli_attached = 1;
667 } else {
668 printf("Warning: Failed to attach to hostapd.\n");
670 hostapd_cli_interactive();
671 } else
672 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
674 free(ctrl_ifname);
675 hostapd_cli_close_connection();
676 return 0;