hostapd: remove version tag from directory
[dragonfly.git] / contrib / hostapd / hostapd_cli.c
blob870f221bb5c3ba71b8f90bfab5204703d0abd3db
1 /*
2 * hostapd - command line interface for hostapd daemon
3 * Copyright (c) 2004-2007, 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 "version.h"
22 static const char *hostapd_cli_version =
23 "hostapd_cli v" VERSION_STR "\n"
24 "Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> and contributors";
27 static const char *hostapd_cli_license =
28 "This program is free software. You can distribute it and/or modify it\n"
29 "under the terms of the GNU General Public License version 2.\n"
30 "\n"
31 "Alternatively, this software may be distributed under the terms of the\n"
32 "BSD license. See README and COPYING for more details.\n";
34 static const char *hostapd_cli_full_license =
35 "This program is free software; you can redistribute it and/or modify\n"
36 "it under the terms of the GNU General Public License version 2 as\n"
37 "published by the Free Software Foundation.\n"
38 "\n"
39 "This program is distributed in the hope that it will be useful,\n"
40 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
41 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
42 "GNU General Public License for more details.\n"
43 "\n"
44 "You should have received a copy of the GNU General Public License\n"
45 "along with this program; if not, write to the Free Software\n"
46 "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
47 "\n"
48 "Alternatively, this software may be distributed under the terms of the\n"
49 "BSD license.\n"
50 "\n"
51 "Redistribution and use in source and binary forms, with or without\n"
52 "modification, are permitted provided that the following conditions are\n"
53 "met:\n"
54 "\n"
55 "1. Redistributions of source code must retain the above copyright\n"
56 " notice, this list of conditions and the following disclaimer.\n"
57 "\n"
58 "2. Redistributions in binary form must reproduce the above copyright\n"
59 " notice, this list of conditions and the following disclaimer in the\n"
60 " documentation and/or other materials provided with the distribution.\n"
61 "\n"
62 "3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
63 " names of its contributors may be used to endorse or promote products\n"
64 " derived from this software without specific prior written permission.\n"
65 "\n"
66 "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
67 "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
68 "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
69 "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
70 "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
71 "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
72 "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
73 "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
74 "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
75 "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
76 "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
77 "\n";
79 static const char *commands_help =
80 "Commands:\n"
81 " mib get MIB variables (dot1x, dot11, radius)\n"
82 " sta <addr> get MIB variables for one station\n"
83 " all_sta get MIB variables for all stations\n"
84 " new_sta <addr> add a new station\n"
85 " help show this usage help\n"
86 " interface [ifname] show interfaces/select interface\n"
87 " level <debug level> change debug level\n"
88 " license show full hostapd_cli license\n"
89 " quit exit hostapd_cli\n";
91 static struct wpa_ctrl *ctrl_conn;
92 static int hostapd_cli_quit = 0;
93 static int hostapd_cli_attached = 0;
94 static const char *ctrl_iface_dir = "/var/run/hostapd";
95 static char *ctrl_ifname = NULL;
98 static void usage(void)
100 fprintf(stderr, "%s\n", hostapd_cli_version);
101 fprintf(stderr,
102 "\n"
103 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hv] "
104 "[command..]\n"
105 "\n"
106 "Options:\n"
107 " -h help (show this usage text)\n"
108 " -v shown version information\n"
109 " -p<path> path to find control sockets (default: "
110 "/var/run/hostapd)\n"
111 " -i<ifname> Interface to listen on (default: first "
112 "interface found in the\n"
113 " socket path)\n\n"
114 "%s",
115 commands_help);
119 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
121 char *cfile;
122 int flen;
124 if (ifname == NULL)
125 return NULL;
127 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
128 cfile = malloc(flen);
129 if (cfile == NULL)
130 return NULL;
131 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
133 ctrl_conn = wpa_ctrl_open(cfile);
134 free(cfile);
135 return ctrl_conn;
139 static void hostapd_cli_close_connection(void)
141 if (ctrl_conn == NULL)
142 return;
144 if (hostapd_cli_attached) {
145 wpa_ctrl_detach(ctrl_conn);
146 hostapd_cli_attached = 0;
148 wpa_ctrl_close(ctrl_conn);
149 ctrl_conn = NULL;
153 static void hostapd_cli_msg_cb(char *msg, size_t len)
155 printf("%s\n", msg);
159 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
161 char buf[4096];
162 size_t len;
163 int ret;
165 if (ctrl_conn == NULL) {
166 printf("Not connected to hostapd - command dropped.\n");
167 return -1;
169 len = sizeof(buf) - 1;
170 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
171 hostapd_cli_msg_cb);
172 if (ret == -2) {
173 printf("'%s' command timed out.\n", cmd);
174 return -2;
175 } else if (ret < 0) {
176 printf("'%s' command failed.\n", cmd);
177 return -1;
179 if (print) {
180 buf[len] = '\0';
181 printf("%s", buf);
183 return 0;
187 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
189 return _wpa_ctrl_command(ctrl, cmd, 1);
193 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
195 return wpa_ctrl_command(ctrl, "PING");
199 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
201 return wpa_ctrl_command(ctrl, "MIB");
205 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
207 char buf[64];
208 if (argc != 1) {
209 printf("Invalid 'sta' command - exactly one argument, STA "
210 "address, is required.\n");
211 return -1;
213 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
214 return wpa_ctrl_command(ctrl, buf);
218 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
219 char *argv[])
221 char buf[64];
222 if (argc != 1) {
223 printf("Invalid 'new_sta' command - exactly one argument, STA "
224 "address, is required.\n");
225 return -1;
227 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
228 return wpa_ctrl_command(ctrl, buf);
232 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
233 char *addr, size_t addr_len)
235 char buf[4096], *pos;
236 size_t len;
237 int ret;
239 if (ctrl_conn == NULL) {
240 printf("Not connected to hostapd - command dropped.\n");
241 return -1;
243 len = sizeof(buf) - 1;
244 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
245 hostapd_cli_msg_cb);
246 if (ret == -2) {
247 printf("'%s' command timed out.\n", cmd);
248 return -2;
249 } else if (ret < 0) {
250 printf("'%s' command failed.\n", cmd);
251 return -1;
254 buf[len] = '\0';
255 if (memcmp(buf, "FAIL", 4) == 0)
256 return -1;
257 printf("%s", buf);
259 pos = buf;
260 while (*pos != '\0' && *pos != '\n')
261 pos++;
262 *pos = '\0';
263 snprintf(addr, addr_len, "%s", buf);
264 return 0;
268 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
269 char *argv[])
271 char addr[32], cmd[64];
273 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
274 return 0;
275 do {
276 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
277 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
279 return -1;
283 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
285 printf("%s", commands_help);
286 return 0;
290 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
291 char *argv[])
293 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
294 return 0;
298 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
300 hostapd_cli_quit = 1;
301 return 0;
305 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
307 char cmd[256];
308 if (argc != 1) {
309 printf("Invalid LEVEL command: needs one argument (debug "
310 "level)\n");
311 return 0;
313 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
314 return wpa_ctrl_command(ctrl, cmd);
318 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
320 struct dirent *dent;
321 DIR *dir;
323 dir = opendir(ctrl_iface_dir);
324 if (dir == NULL) {
325 printf("Control interface directory '%s' could not be "
326 "openned.\n", ctrl_iface_dir);
327 return;
330 printf("Available interfaces:\n");
331 while ((dent = readdir(dir))) {
332 if (strcmp(dent->d_name, ".") == 0 ||
333 strcmp(dent->d_name, "..") == 0)
334 continue;
335 printf("%s\n", dent->d_name);
337 closedir(dir);
341 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
342 char *argv[])
344 if (argc < 1) {
345 hostapd_cli_list_interfaces(ctrl);
346 return 0;
349 hostapd_cli_close_connection();
350 free(ctrl_ifname);
351 ctrl_ifname = strdup(argv[0]);
353 if (hostapd_cli_open_connection(ctrl_ifname)) {
354 printf("Connected to interface '%s.\n", ctrl_ifname);
355 if (wpa_ctrl_attach(ctrl_conn) == 0) {
356 hostapd_cli_attached = 1;
357 } else {
358 printf("Warning: Failed to attach to "
359 "hostapd.\n");
361 } else {
362 printf("Could not connect to interface '%s' - re-trying\n",
363 ctrl_ifname);
365 return 0;
369 struct hostapd_cli_cmd {
370 const char *cmd;
371 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
374 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
375 { "ping", hostapd_cli_cmd_ping },
376 { "mib", hostapd_cli_cmd_mib },
377 { "sta", hostapd_cli_cmd_sta },
378 { "all_sta", hostapd_cli_cmd_all_sta },
379 { "new_sta", hostapd_cli_cmd_new_sta },
380 { "help", hostapd_cli_cmd_help },
381 { "interface", hostapd_cli_cmd_interface },
382 { "level", hostapd_cli_cmd_level },
383 { "license", hostapd_cli_cmd_license },
384 { "quit", hostapd_cli_cmd_quit },
385 { NULL, NULL }
389 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
391 struct hostapd_cli_cmd *cmd, *match = NULL;
392 int count;
394 count = 0;
395 cmd = hostapd_cli_commands;
396 while (cmd->cmd) {
397 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
398 match = cmd;
399 count++;
401 cmd++;
404 if (count > 1) {
405 printf("Ambiguous command '%s'; possible commands:", argv[0]);
406 cmd = hostapd_cli_commands;
407 while (cmd->cmd) {
408 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
409 0) {
410 printf(" %s", cmd->cmd);
412 cmd++;
414 printf("\n");
415 } else if (count == 0) {
416 printf("Unknown command '%s'\n", argv[0]);
417 } else {
418 match->handler(ctrl, argc - 1, &argv[1]);
423 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read)
425 int first = 1;
426 if (ctrl_conn == NULL)
427 return;
428 while (wpa_ctrl_pending(ctrl)) {
429 char buf[256];
430 size_t len = sizeof(buf) - 1;
431 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
432 buf[len] = '\0';
433 if (in_read && first)
434 printf("\n");
435 first = 0;
436 printf("%s\n", buf);
437 } else {
438 printf("Could not read pending message.\n");
439 break;
445 static void hostapd_cli_interactive(void)
447 const int max_args = 10;
448 char cmd[256], *res, *argv[max_args], *pos;
449 int argc;
451 printf("\nInteractive mode\n\n");
453 do {
454 hostapd_cli_recv_pending(ctrl_conn, 0);
455 printf("> ");
456 alarm(1);
457 res = fgets(cmd, sizeof(cmd), stdin);
458 alarm(0);
459 if (res == NULL)
460 break;
461 pos = cmd;
462 while (*pos != '\0') {
463 if (*pos == '\n') {
464 *pos = '\0';
465 break;
467 pos++;
469 argc = 0;
470 pos = cmd;
471 for (;;) {
472 while (*pos == ' ')
473 pos++;
474 if (*pos == '\0')
475 break;
476 argv[argc] = pos;
477 argc++;
478 if (argc == max_args)
479 break;
480 while (*pos != '\0' && *pos != ' ')
481 pos++;
482 if (*pos == ' ')
483 *pos++ = '\0';
485 if (argc)
486 wpa_request(ctrl_conn, argc, argv);
487 } while (!hostapd_cli_quit);
491 static void hostapd_cli_terminate(int sig)
493 hostapd_cli_close_connection();
494 exit(0);
498 static void hostapd_cli_alarm(int sig)
500 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
501 printf("Connection to hostapd lost - trying to reconnect\n");
502 hostapd_cli_close_connection();
504 if (!ctrl_conn) {
505 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
506 if (ctrl_conn) {
507 printf("Connection to hostapd re-established\n");
508 if (wpa_ctrl_attach(ctrl_conn) == 0) {
509 hostapd_cli_attached = 1;
510 } else {
511 printf("Warning: Failed to attach to "
512 "hostapd.\n");
516 if (ctrl_conn)
517 hostapd_cli_recv_pending(ctrl_conn, 1);
518 alarm(1);
522 int main(int argc, char *argv[])
524 int interactive;
525 int warning_displayed = 0;
526 int c;
528 for (;;) {
529 c = getopt(argc, argv, "hi:p:v");
530 if (c < 0)
531 break;
532 switch (c) {
533 case 'h':
534 usage();
535 return 0;
536 case 'v':
537 printf("%s\n", hostapd_cli_version);
538 return 0;
539 case 'i':
540 free(ctrl_ifname);
541 ctrl_ifname = strdup(optarg);
542 break;
543 case 'p':
544 ctrl_iface_dir = optarg;
545 break;
546 default:
547 usage();
548 return -1;
552 interactive = argc == optind;
554 if (interactive) {
555 printf("%s\n\n%s\n\n", hostapd_cli_version,
556 hostapd_cli_license);
559 for (;;) {
560 if (ctrl_ifname == NULL) {
561 struct dirent *dent;
562 DIR *dir = opendir(ctrl_iface_dir);
563 if (dir) {
564 while ((dent = readdir(dir))) {
565 if (strcmp(dent->d_name, ".") == 0 ||
566 strcmp(dent->d_name, "..") == 0)
567 continue;
568 printf("Selected interface '%s'\n",
569 dent->d_name);
570 ctrl_ifname = strdup(dent->d_name);
571 break;
573 closedir(dir);
576 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
577 if (ctrl_conn) {
578 if (warning_displayed)
579 printf("Connection established.\n");
580 break;
583 if (!interactive) {
584 perror("Failed to connect to hostapd - "
585 "wpa_ctrl_open");
586 return -1;
589 if (!warning_displayed) {
590 printf("Could not connect to hostapd - re-trying\n");
591 warning_displayed = 1;
593 sleep(1);
594 continue;
597 signal(SIGINT, hostapd_cli_terminate);
598 signal(SIGTERM, hostapd_cli_terminate);
599 signal(SIGALRM, hostapd_cli_alarm);
601 if (interactive) {
602 if (wpa_ctrl_attach(ctrl_conn) == 0) {
603 hostapd_cli_attached = 1;
604 } else {
605 printf("Warning: Failed to attach to hostapd.\n");
607 hostapd_cli_interactive();
608 } else
609 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
611 free(ctrl_ifname);
612 hostapd_cli_close_connection();
613 return 0;