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
12 * See README and COPYING for more details.
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"
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"
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"
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"
48 "Alternatively, this software may be distributed under the terms of the\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"
55 "1. Redistributions of source code must retain the above copyright\n"
56 " notice, this list of conditions and the following disclaimer.\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"
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"
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"
79 static const char *commands_help
=
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
);
103 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hv] "
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"
119 static struct wpa_ctrl
* hostapd_cli_open_connection(const char *ifname
)
127 flen
= strlen(ctrl_iface_dir
) + strlen(ifname
) + 2;
128 cfile
= malloc(flen
);
131 snprintf(cfile
, flen
, "%s/%s", ctrl_iface_dir
, ifname
);
133 ctrl_conn
= wpa_ctrl_open(cfile
);
139 static void hostapd_cli_close_connection(void)
141 if (ctrl_conn
== NULL
)
144 if (hostapd_cli_attached
) {
145 wpa_ctrl_detach(ctrl_conn
);
146 hostapd_cli_attached
= 0;
148 wpa_ctrl_close(ctrl_conn
);
153 static void hostapd_cli_msg_cb(char *msg
, size_t len
)
159 static int _wpa_ctrl_command(struct wpa_ctrl
*ctrl
, char *cmd
, int print
)
165 if (ctrl_conn
== NULL
) {
166 printf("Not connected to hostapd - command dropped.\n");
169 len
= sizeof(buf
) - 1;
170 ret
= wpa_ctrl_request(ctrl
, cmd
, strlen(cmd
), buf
, &len
,
173 printf("'%s' command timed out.\n", cmd
);
175 } else if (ret
< 0) {
176 printf("'%s' command failed.\n", cmd
);
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
[])
209 printf("Invalid 'sta' command - exactly one argument, STA "
210 "address, is required.\n");
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
,
223 printf("Invalid 'new_sta' command - exactly one argument, STA "
224 "address, is required.\n");
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
;
239 if (ctrl_conn
== NULL
) {
240 printf("Not connected to hostapd - command dropped.\n");
243 len
= sizeof(buf
) - 1;
244 ret
= wpa_ctrl_request(ctrl
, cmd
, strlen(cmd
), buf
, &len
,
247 printf("'%s' command timed out.\n", cmd
);
249 } else if (ret
< 0) {
250 printf("'%s' command failed.\n", cmd
);
255 if (memcmp(buf
, "FAIL", 4) == 0)
260 while (*pos
!= '\0' && *pos
!= '\n')
263 snprintf(addr
, addr_len
, "%s", buf
);
268 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl
*ctrl
, int argc
,
271 char addr
[32], cmd
[64];
273 if (wpa_ctrl_command_sta(ctrl
, "STA-FIRST", addr
, sizeof(addr
)))
276 snprintf(cmd
, sizeof(cmd
), "STA-NEXT %s", addr
);
277 } while (wpa_ctrl_command_sta(ctrl
, cmd
, addr
, sizeof(addr
)) == 0);
283 static int hostapd_cli_cmd_help(struct wpa_ctrl
*ctrl
, int argc
, char *argv
[])
285 printf("%s", commands_help
);
290 static int hostapd_cli_cmd_license(struct wpa_ctrl
*ctrl
, int argc
,
293 printf("%s\n\n%s\n", hostapd_cli_version
, hostapd_cli_full_license
);
298 static int hostapd_cli_cmd_quit(struct wpa_ctrl
*ctrl
, int argc
, char *argv
[])
300 hostapd_cli_quit
= 1;
305 static int hostapd_cli_cmd_level(struct wpa_ctrl
*ctrl
, int argc
, char *argv
[])
309 printf("Invalid LEVEL command: needs one argument (debug "
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
)
323 dir
= opendir(ctrl_iface_dir
);
325 printf("Control interface directory '%s' could not be "
326 "openned.\n", ctrl_iface_dir
);
330 printf("Available interfaces:\n");
331 while ((dent
= readdir(dir
))) {
332 if (strcmp(dent
->d_name
, ".") == 0 ||
333 strcmp(dent
->d_name
, "..") == 0)
335 printf("%s\n", dent
->d_name
);
341 static int hostapd_cli_cmd_interface(struct wpa_ctrl
*ctrl
, int argc
,
345 hostapd_cli_list_interfaces(ctrl
);
349 hostapd_cli_close_connection();
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;
358 printf("Warning: Failed to attach to "
362 printf("Could not connect to interface '%s' - re-trying\n",
369 struct hostapd_cli_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
},
389 static void wpa_request(struct wpa_ctrl
*ctrl
, int argc
, char *argv
[])
391 struct hostapd_cli_cmd
*cmd
, *match
= NULL
;
395 cmd
= hostapd_cli_commands
;
397 if (strncasecmp(cmd
->cmd
, argv
[0], strlen(argv
[0])) == 0) {
405 printf("Ambiguous command '%s'; possible commands:", argv
[0]);
406 cmd
= hostapd_cli_commands
;
408 if (strncasecmp(cmd
->cmd
, argv
[0], strlen(argv
[0])) ==
410 printf(" %s", cmd
->cmd
);
415 } else if (count
== 0) {
416 printf("Unknown command '%s'\n", argv
[0]);
418 match
->handler(ctrl
, argc
- 1, &argv
[1]);
423 static void hostapd_cli_recv_pending(struct wpa_ctrl
*ctrl
, int in_read
)
426 if (ctrl_conn
== NULL
)
428 while (wpa_ctrl_pending(ctrl
)) {
430 size_t len
= sizeof(buf
) - 1;
431 if (wpa_ctrl_recv(ctrl
, buf
, &len
) == 0) {
433 if (in_read
&& first
)
438 printf("Could not read pending message.\n");
445 static void hostapd_cli_interactive(void)
447 const int max_args
= 10;
448 char cmd
[256], *res
, *argv
[max_args
], *pos
;
451 printf("\nInteractive mode\n\n");
454 hostapd_cli_recv_pending(ctrl_conn
, 0);
457 res
= fgets(cmd
, sizeof(cmd
), stdin
);
462 while (*pos
!= '\0') {
478 if (argc
== max_args
)
480 while (*pos
!= '\0' && *pos
!= ' ')
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();
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();
505 ctrl_conn
= hostapd_cli_open_connection(ctrl_ifname
);
507 printf("Connection to hostapd re-established\n");
508 if (wpa_ctrl_attach(ctrl_conn
) == 0) {
509 hostapd_cli_attached
= 1;
511 printf("Warning: Failed to attach to "
517 hostapd_cli_recv_pending(ctrl_conn
, 1);
522 int main(int argc
, char *argv
[])
525 int warning_displayed
= 0;
529 c
= getopt(argc
, argv
, "hi:p:v");
537 printf("%s\n", hostapd_cli_version
);
541 ctrl_ifname
= strdup(optarg
);
544 ctrl_iface_dir
= optarg
;
552 interactive
= argc
== optind
;
555 printf("%s\n\n%s\n\n", hostapd_cli_version
,
556 hostapd_cli_license
);
560 if (ctrl_ifname
== NULL
) {
562 DIR *dir
= opendir(ctrl_iface_dir
);
564 while ((dent
= readdir(dir
))) {
565 if (strcmp(dent
->d_name
, ".") == 0 ||
566 strcmp(dent
->d_name
, "..") == 0)
568 printf("Selected interface '%s'\n",
570 ctrl_ifname
= strdup(dent
->d_name
);
576 ctrl_conn
= hostapd_cli_open_connection(ctrl_ifname
);
578 if (warning_displayed
)
579 printf("Connection established.\n");
584 perror("Failed to connect to hostapd - "
589 if (!warning_displayed
) {
590 printf("Could not connect to hostapd - re-trying\n");
591 warning_displayed
= 1;
597 signal(SIGINT
, hostapd_cli_terminate
);
598 signal(SIGTERM
, hostapd_cli_terminate
);
599 signal(SIGALRM
, hostapd_cli_alarm
);
602 if (wpa_ctrl_attach(ctrl_conn
) == 0) {
603 hostapd_cli_attached
= 1;
605 printf("Warning: Failed to attach to hostapd.\n");
607 hostapd_cli_interactive();
609 wpa_request(ctrl_conn
, argc
- optind
, &argv
[optind
]);
612 hostapd_cli_close_connection();