nl80211: Fix a typo
[hostap-gosc2009.git] / hostapd / hostapd_cli.c
blob964c64dd219922f0092fcb391ae62d0a6334ed05
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 "common/wpa_ctrl.h"
19 #include "common.h"
20 #include "common/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 #ifdef CONFIG_WPS_OOB
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);
113 fprintf(stderr,
114 "\n"
115 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hv] "
116 "[-G<ping interval>] \\\n"
117 " [command..]\n"
118 "\n"
119 "Options:\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"
126 " socket path)\n\n"
127 "%s",
128 commands_help);
132 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
134 char *cfile;
135 int flen;
137 if (ifname == NULL)
138 return NULL;
140 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
141 cfile = malloc(flen);
142 if (cfile == NULL)
143 return NULL;
144 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
146 ctrl_conn = wpa_ctrl_open(cfile);
147 free(cfile);
148 return ctrl_conn;
152 static void hostapd_cli_close_connection(void)
154 if (ctrl_conn == NULL)
155 return;
157 if (hostapd_cli_attached) {
158 wpa_ctrl_detach(ctrl_conn);
159 hostapd_cli_attached = 0;
161 wpa_ctrl_close(ctrl_conn);
162 ctrl_conn = NULL;
166 static void hostapd_cli_msg_cb(char *msg, size_t len)
168 printf("%s\n", msg);
172 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
174 char buf[4096];
175 size_t len;
176 int ret;
178 if (ctrl_conn == NULL) {
179 printf("Not connected to hostapd - command dropped.\n");
180 return -1;
182 len = sizeof(buf) - 1;
183 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
184 hostapd_cli_msg_cb);
185 if (ret == -2) {
186 printf("'%s' command timed out.\n", cmd);
187 return -2;
188 } else if (ret < 0) {
189 printf("'%s' command failed.\n", cmd);
190 return -1;
192 if (print) {
193 buf[len] = '\0';
194 printf("%s", buf);
196 return 0;
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[])
220 char buf[64];
221 if (argc != 1) {
222 printf("Invalid 'sta' command - exactly one argument, STA "
223 "address, is required.\n");
224 return -1;
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,
232 char *argv[])
234 char buf[64];
235 if (argc != 1) {
236 printf("Invalid 'new_sta' command - exactly one argument, STA "
237 "address, is required.\n");
238 return -1;
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,
247 char *argv[])
249 char buf[64];
250 if (argc != 1) {
251 printf("Invalid 'sa_query' command - exactly one argument, "
252 "STA address, is required.\n");
253 return -1;
255 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
256 return wpa_ctrl_command(ctrl, buf);
258 #endif /* CONFIG_IEEE80211W */
261 #ifdef CONFIG_WPS
262 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
263 char *argv[])
265 char buf[64];
266 if (argc < 2) {
267 printf("Invalid 'wps_pin' command - at least two arguments, "
268 "UUID and PIN, are required.\n");
269 return -1;
271 if (argc > 2)
272 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
273 argv[0], argv[1], argv[2]);
274 else
275 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
276 return wpa_ctrl_command(ctrl, buf);
280 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
281 char *argv[])
283 return wpa_ctrl_command(ctrl, "WPS_PBC");
287 #ifdef CONFIG_WPS_OOB
288 static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
289 char *argv[])
291 char cmd[256];
292 int res;
294 if (argc != 3 && argc != 4) {
295 printf("Invalid WPS_OOB command: need three or four "
296 "arguments:\n"
297 "- DEV_TYPE: use 'ufd' or 'nfc'\n"
298 "- PATH: path of OOB device like '/mnt'\n"
299 "- METHOD: OOB method 'pin-e' or 'pin-r', "
300 "'cred'\n"
301 "- DEV_NAME: (only for NFC) device name like "
302 "'pn531'\n");
303 return -1;
306 if (argc == 3)
307 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
308 argv[0], argv[1], argv[2]);
309 else
310 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
311 argv[0], argv[1], argv[2], argv[3]);
312 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
313 printf("Too long WPS_OOB command.\n");
314 return -1;
316 return wpa_ctrl_command(ctrl, cmd);
318 #endif /* CONFIG_WPS_OOB */
319 #endif /* CONFIG_WPS */
322 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
323 char *addr, size_t addr_len)
325 char buf[4096], *pos;
326 size_t len;
327 int ret;
329 if (ctrl_conn == NULL) {
330 printf("Not connected to hostapd - command dropped.\n");
331 return -1;
333 len = sizeof(buf) - 1;
334 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
335 hostapd_cli_msg_cb);
336 if (ret == -2) {
337 printf("'%s' command timed out.\n", cmd);
338 return -2;
339 } else if (ret < 0) {
340 printf("'%s' command failed.\n", cmd);
341 return -1;
344 buf[len] = '\0';
345 if (memcmp(buf, "FAIL", 4) == 0)
346 return -1;
347 printf("%s", buf);
349 pos = buf;
350 while (*pos != '\0' && *pos != '\n')
351 pos++;
352 *pos = '\0';
353 os_strlcpy(addr, buf, addr_len);
354 return 0;
358 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
359 char *argv[])
361 char addr[32], cmd[64];
363 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
364 return 0;
365 do {
366 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
367 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
369 return -1;
373 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
375 printf("%s", commands_help);
376 return 0;
380 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
381 char *argv[])
383 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
384 return 0;
388 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
390 hostapd_cli_quit = 1;
391 return 0;
395 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
397 char cmd[256];
398 if (argc != 1) {
399 printf("Invalid LEVEL command: needs one argument (debug "
400 "level)\n");
401 return 0;
403 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
404 return wpa_ctrl_command(ctrl, cmd);
408 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
410 struct dirent *dent;
411 DIR *dir;
413 dir = opendir(ctrl_iface_dir);
414 if (dir == NULL) {
415 printf("Control interface directory '%s' could not be "
416 "openned.\n", ctrl_iface_dir);
417 return;
420 printf("Available interfaces:\n");
421 while ((dent = readdir(dir))) {
422 if (strcmp(dent->d_name, ".") == 0 ||
423 strcmp(dent->d_name, "..") == 0)
424 continue;
425 printf("%s\n", dent->d_name);
427 closedir(dir);
431 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
432 char *argv[])
434 if (argc < 1) {
435 hostapd_cli_list_interfaces(ctrl);
436 return 0;
439 hostapd_cli_close_connection();
440 free(ctrl_ifname);
441 ctrl_ifname = strdup(argv[0]);
443 if (hostapd_cli_open_connection(ctrl_ifname)) {
444 printf("Connected to interface '%s.\n", ctrl_ifname);
445 if (wpa_ctrl_attach(ctrl_conn) == 0) {
446 hostapd_cli_attached = 1;
447 } else {
448 printf("Warning: Failed to attach to "
449 "hostapd.\n");
451 } else {
452 printf("Could not connect to interface '%s' - re-trying\n",
453 ctrl_ifname);
455 return 0;
459 struct hostapd_cli_cmd {
460 const char *cmd;
461 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
464 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
465 { "ping", hostapd_cli_cmd_ping },
466 { "mib", hostapd_cli_cmd_mib },
467 { "sta", hostapd_cli_cmd_sta },
468 { "all_sta", hostapd_cli_cmd_all_sta },
469 { "new_sta", hostapd_cli_cmd_new_sta },
470 #ifdef CONFIG_IEEE80211W
471 { "sa_query", hostapd_cli_cmd_sa_query },
472 #endif /* CONFIG_IEEE80211W */
473 #ifdef CONFIG_WPS
474 { "wps_pin", hostapd_cli_cmd_wps_pin },
475 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
476 #ifdef CONFIG_WPS_OOB
477 { "wps_oob", hostapd_cli_cmd_wps_oob },
478 #endif /* CONFIG_WPS_OOB */
479 #endif /* CONFIG_WPS */
480 { "help", hostapd_cli_cmd_help },
481 { "interface", hostapd_cli_cmd_interface },
482 { "level", hostapd_cli_cmd_level },
483 { "license", hostapd_cli_cmd_license },
484 { "quit", hostapd_cli_cmd_quit },
485 { NULL, NULL }
489 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
491 struct hostapd_cli_cmd *cmd, *match = NULL;
492 int count;
494 count = 0;
495 cmd = hostapd_cli_commands;
496 while (cmd->cmd) {
497 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
498 match = cmd;
499 count++;
501 cmd++;
504 if (count > 1) {
505 printf("Ambiguous command '%s'; possible commands:", argv[0]);
506 cmd = hostapd_cli_commands;
507 while (cmd->cmd) {
508 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
509 0) {
510 printf(" %s", cmd->cmd);
512 cmd++;
514 printf("\n");
515 } else if (count == 0) {
516 printf("Unknown command '%s'\n", argv[0]);
517 } else {
518 match->handler(ctrl, argc - 1, &argv[1]);
523 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read)
525 int first = 1;
526 if (ctrl_conn == NULL)
527 return;
528 while (wpa_ctrl_pending(ctrl)) {
529 char buf[256];
530 size_t len = sizeof(buf) - 1;
531 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
532 buf[len] = '\0';
533 if (in_read && first)
534 printf("\n");
535 first = 0;
536 printf("%s\n", buf);
537 } else {
538 printf("Could not read pending message.\n");
539 break;
545 static void hostapd_cli_interactive(void)
547 const int max_args = 10;
548 char cmd[256], *res, *argv[max_args], *pos;
549 int argc;
551 printf("\nInteractive mode\n\n");
553 do {
554 hostapd_cli_recv_pending(ctrl_conn, 0);
555 printf("> ");
556 alarm(ping_interval);
557 res = fgets(cmd, sizeof(cmd), stdin);
558 alarm(0);
559 if (res == NULL)
560 break;
561 pos = cmd;
562 while (*pos != '\0') {
563 if (*pos == '\n') {
564 *pos = '\0';
565 break;
567 pos++;
569 argc = 0;
570 pos = cmd;
571 for (;;) {
572 while (*pos == ' ')
573 pos++;
574 if (*pos == '\0')
575 break;
576 argv[argc] = pos;
577 argc++;
578 if (argc == max_args)
579 break;
580 while (*pos != '\0' && *pos != ' ')
581 pos++;
582 if (*pos == ' ')
583 *pos++ = '\0';
585 if (argc)
586 wpa_request(ctrl_conn, argc, argv);
587 } while (!hostapd_cli_quit);
591 static void hostapd_cli_terminate(int sig)
593 hostapd_cli_close_connection();
594 exit(0);
598 static void hostapd_cli_alarm(int sig)
600 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
601 printf("Connection to hostapd lost - trying to reconnect\n");
602 hostapd_cli_close_connection();
604 if (!ctrl_conn) {
605 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
606 if (ctrl_conn) {
607 printf("Connection to hostapd re-established\n");
608 if (wpa_ctrl_attach(ctrl_conn) == 0) {
609 hostapd_cli_attached = 1;
610 } else {
611 printf("Warning: Failed to attach to "
612 "hostapd.\n");
616 if (ctrl_conn)
617 hostapd_cli_recv_pending(ctrl_conn, 1);
618 alarm(ping_interval);
622 int main(int argc, char *argv[])
624 int interactive;
625 int warning_displayed = 0;
626 int c;
628 if (os_program_init())
629 return -1;
631 for (;;) {
632 c = getopt(argc, argv, "hG:i:p:v");
633 if (c < 0)
634 break;
635 switch (c) {
636 case 'G':
637 ping_interval = atoi(optarg);
638 break;
639 case 'h':
640 usage();
641 return 0;
642 case 'v':
643 printf("%s\n", hostapd_cli_version);
644 return 0;
645 case 'i':
646 free(ctrl_ifname);
647 ctrl_ifname = strdup(optarg);
648 break;
649 case 'p':
650 ctrl_iface_dir = optarg;
651 break;
652 default:
653 usage();
654 return -1;
658 interactive = argc == optind;
660 if (interactive) {
661 printf("%s\n\n%s\n\n", hostapd_cli_version,
662 hostapd_cli_license);
665 for (;;) {
666 if (ctrl_ifname == NULL) {
667 struct dirent *dent;
668 DIR *dir = opendir(ctrl_iface_dir);
669 if (dir) {
670 while ((dent = readdir(dir))) {
671 if (strcmp(dent->d_name, ".") == 0 ||
672 strcmp(dent->d_name, "..") == 0)
673 continue;
674 printf("Selected interface '%s'\n",
675 dent->d_name);
676 ctrl_ifname = strdup(dent->d_name);
677 break;
679 closedir(dir);
682 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
683 if (ctrl_conn) {
684 if (warning_displayed)
685 printf("Connection established.\n");
686 break;
689 if (!interactive) {
690 perror("Failed to connect to hostapd - "
691 "wpa_ctrl_open");
692 return -1;
695 if (!warning_displayed) {
696 printf("Could not connect to hostapd - re-trying\n");
697 warning_displayed = 1;
699 sleep(1);
700 continue;
703 signal(SIGINT, hostapd_cli_terminate);
704 signal(SIGTERM, hostapd_cli_terminate);
705 signal(SIGALRM, hostapd_cli_alarm);
707 if (interactive) {
708 if (wpa_ctrl_attach(ctrl_conn) == 0) {
709 hostapd_cli_attached = 1;
710 } else {
711 printf("Warning: Failed to attach to hostapd.\n");
713 hostapd_cli_interactive();
714 } else
715 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
717 free(ctrl_ifname);
718 hostapd_cli_close_connection();
719 os_program_deinit();
720 return 0;