blob: a48d773259e6c5692569269afb19a9c62d2884e7 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * hostapd - command line interface for hostapd daemon
3 * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
4 *
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.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "includes.h"
16#include <dirent.h>
17
18#include "common/wpa_ctrl.h"
19#include "common.h"
20#include "common/version.h"
21
22
23static const char *hostapd_cli_version =
24"hostapd_cli v" VERSION_STR "\n"
25"Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi> and contributors";
26
27
28static 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";
34
35static 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";
79
80static 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" deauthenticate <addr> deauthenticate a station\n"
87" disassociate <addr> disassociate a station\n"
88#ifdef CONFIG_IEEE80211W
89" sa_query <addr> send SA Query to a station\n"
90#endif /* CONFIG_IEEE80211W */
91#ifdef CONFIG_WPS
92" wps_pin <uuid> <pin> [timeout] [addr] add WPS Enrollee PIN\n"
93" wps_check_pin <PIN> verify PIN checksum\n"
94" wps_pbc indicate button pushed to initiate PBC\n"
95#ifdef CONFIG_WPS_OOB
96" wps_oob <type> <path> <method> use WPS with out-of-band (UFD)\n"
97#endif /* CONFIG_WPS_OOB */
98" wps_ap_pin <cmd> [params..] enable/disable AP PIN\n"
99" wps_config <SSID> <auth> <encr> <key> configure AP\n"
100#endif /* CONFIG_WPS */
101" get_config show current configuration\n"
102" help show this usage help\n"
103" interface [ifname] show interfaces/select interface\n"
104" level <debug level> change debug level\n"
105" license show full hostapd_cli license\n"
106" quit exit hostapd_cli\n";
107
108static struct wpa_ctrl *ctrl_conn;
109static int hostapd_cli_quit = 0;
110static int hostapd_cli_attached = 0;
111static const char *ctrl_iface_dir = "/var/run/hostapd";
112static char *ctrl_ifname = NULL;
113static const char *pid_file = NULL;
114static const char *action_file = NULL;
115static int ping_interval = 5;
116
117
118static void usage(void)
119{
120 fprintf(stderr, "%s\n", hostapd_cli_version);
121 fprintf(stderr,
122 "\n"
123 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
124 "[-a<path>] \\\n"
125 " [-G<ping interval>] [command..]\n"
126 "\n"
127 "Options:\n"
128 " -h help (show this usage text)\n"
129 " -v shown version information\n"
130 " -p<path> path to find control sockets (default: "
131 "/var/run/hostapd)\n"
132 " -a<file> run in daemon mode executing the action file "
133 "based on events\n"
134 " from hostapd\n"
135 " -B run a daemon in the background\n"
136 " -i<ifname> Interface to listen on (default: first "
137 "interface found in the\n"
138 " socket path)\n\n"
139 "%s",
140 commands_help);
141}
142
143
144static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
145{
146 char *cfile;
147 int flen;
148
149 if (ifname == NULL)
150 return NULL;
151
152 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
153 cfile = malloc(flen);
154 if (cfile == NULL)
155 return NULL;
156 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
157
158 ctrl_conn = wpa_ctrl_open(cfile);
159 free(cfile);
160 return ctrl_conn;
161}
162
163
164static void hostapd_cli_close_connection(void)
165{
166 if (ctrl_conn == NULL)
167 return;
168
169 if (hostapd_cli_attached) {
170 wpa_ctrl_detach(ctrl_conn);
171 hostapd_cli_attached = 0;
172 }
173 wpa_ctrl_close(ctrl_conn);
174 ctrl_conn = NULL;
175}
176
177
178static void hostapd_cli_msg_cb(char *msg, size_t len)
179{
180 printf("%s\n", msg);
181}
182
183
184static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
185{
186 char buf[4096];
187 size_t len;
188 int ret;
189
190 if (ctrl_conn == NULL) {
191 printf("Not connected to hostapd - command dropped.\n");
192 return -1;
193 }
194 len = sizeof(buf) - 1;
195 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
196 hostapd_cli_msg_cb);
197 if (ret == -2) {
198 printf("'%s' command timed out.\n", cmd);
199 return -2;
200 } else if (ret < 0) {
201 printf("'%s' command failed.\n", cmd);
202 return -1;
203 }
204 if (print) {
205 buf[len] = '\0';
206 printf("%s", buf);
207 }
208 return 0;
209}
210
211
212static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
213{
214 return _wpa_ctrl_command(ctrl, cmd, 1);
215}
216
217
218static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
219{
220 return wpa_ctrl_command(ctrl, "PING");
221}
222
223
224static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
225{
226 return wpa_ctrl_command(ctrl, "RELOG");
227}
228
229
230static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
231{
232 return wpa_ctrl_command(ctrl, "MIB");
233}
234
235
236static int hostapd_cli_exec(const char *program, const char *arg1,
237 const char *arg2)
238{
239 char *cmd;
240 size_t len;
241 int res;
242 int ret = 0;
243
244 len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
245 cmd = os_malloc(len);
246 if (cmd == NULL)
247 return -1;
248 res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
249 if (res < 0 || (size_t) res >= len) {
250 os_free(cmd);
251 return -1;
252 }
253 cmd[len - 1] = '\0';
254#ifndef _WIN32_WCE
255 if (system(cmd) < 0)
256 ret = -1;
257#endif /* _WIN32_WCE */
258 os_free(cmd);
259
260 return ret;
261}
262
263
264static void hostapd_cli_action_process(char *msg, size_t len)
265{
266 const char *pos;
267
268 pos = msg;
269 if (*pos == '<') {
270 pos = os_strchr(pos, '>');
271 if (pos)
272 pos++;
273 else
274 pos = msg;
275 }
276
277 hostapd_cli_exec(action_file, ctrl_ifname, pos);
278}
279
280
281static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
282{
283 char buf[64];
284 if (argc != 1) {
285 printf("Invalid 'sta' command - exactly one argument, STA "
286 "address, is required.\n");
287 return -1;
288 }
289 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
290 return wpa_ctrl_command(ctrl, buf);
291}
292
293
294static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
295 char *argv[])
296{
297 char buf[64];
298 if (argc != 1) {
299 printf("Invalid 'new_sta' command - exactly one argument, STA "
300 "address, is required.\n");
301 return -1;
302 }
303 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
304 return wpa_ctrl_command(ctrl, buf);
305}
306
307
308static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
309 char *argv[])
310{
311 char buf[64];
312 if (argc < 1) {
313 printf("Invalid 'deauthenticate' command - exactly one "
314 "argument, STA address, is required.\n");
315 return -1;
316 }
317 if (argc > 1)
318 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
319 argv[0], argv[1]);
320 else
321 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
322 return wpa_ctrl_command(ctrl, buf);
323}
324
325
326static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
327 char *argv[])
328{
329 char buf[64];
330 if (argc < 1) {
331 printf("Invalid 'disassociate' command - exactly one "
332 "argument, STA address, is required.\n");
333 return -1;
334 }
335 if (argc > 1)
336 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
337 argv[0], argv[1]);
338 else
339 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
340 return wpa_ctrl_command(ctrl, buf);
341}
342
343
344#ifdef CONFIG_IEEE80211W
345static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
346 char *argv[])
347{
348 char buf[64];
349 if (argc != 1) {
350 printf("Invalid 'sa_query' command - exactly one argument, "
351 "STA address, is required.\n");
352 return -1;
353 }
354 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
355 return wpa_ctrl_command(ctrl, buf);
356}
357#endif /* CONFIG_IEEE80211W */
358
359
360#ifdef CONFIG_WPS
361static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
362 char *argv[])
363{
364 char buf[256];
365 if (argc < 2) {
366 printf("Invalid 'wps_pin' command - at least two arguments, "
367 "UUID and PIN, are required.\n");
368 return -1;
369 }
370 if (argc > 3)
371 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
372 argv[0], argv[1], argv[2], argv[3]);
373 else if (argc > 2)
374 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
375 argv[0], argv[1], argv[2]);
376 else
377 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
378 return wpa_ctrl_command(ctrl, buf);
379}
380
381
382static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
383 char *argv[])
384{
385 char cmd[256];
386 int res;
387
388 if (argc != 1 && argc != 2) {
389 printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
390 "- PIN to be verified\n");
391 return -1;
392 }
393
394 if (argc == 2)
395 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
396 argv[0], argv[1]);
397 else
398 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
399 argv[0]);
400 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
401 printf("Too long WPS_CHECK_PIN command.\n");
402 return -1;
403 }
404 return wpa_ctrl_command(ctrl, cmd);
405}
406
407
408static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
409 char *argv[])
410{
411 return wpa_ctrl_command(ctrl, "WPS_PBC");
412}
413
414
415#ifdef CONFIG_WPS_OOB
416static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
417 char *argv[])
418{
419 char cmd[256];
420 int res;
421
422 if (argc != 3 && argc != 4) {
423 printf("Invalid WPS_OOB command: need three or four "
424 "arguments:\n"
425 "- DEV_TYPE: use 'ufd' or 'nfc'\n"
426 "- PATH: path of OOB device like '/mnt'\n"
427 "- METHOD: OOB method 'pin-e' or 'pin-r', "
428 "'cred'\n"
429 "- DEV_NAME: (only for NFC) device name like "
430 "'pn531'\n");
431 return -1;
432 }
433
434 if (argc == 3)
435 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
436 argv[0], argv[1], argv[2]);
437 else
438 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
439 argv[0], argv[1], argv[2], argv[3]);
440 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
441 printf("Too long WPS_OOB command.\n");
442 return -1;
443 }
444 return wpa_ctrl_command(ctrl, cmd);
445}
446#endif /* CONFIG_WPS_OOB */
447
448
449static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
450 char *argv[])
451{
452 char buf[64];
453 if (argc < 1) {
454 printf("Invalid 'wps_ap_pin' command - at least one argument "
455 "is required.\n");
456 return -1;
457 }
458 if (argc > 2)
459 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
460 argv[0], argv[1], argv[2]);
461 else if (argc > 1)
462 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
463 argv[0], argv[1]);
464 else
465 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
466 return wpa_ctrl_command(ctrl, buf);
467}
468
469
470static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
471 char *argv[])
472{
473 char buf[256];
474 char ssid_hex[2 * 32 + 1];
475 char key_hex[2 * 64 + 1];
476 int i;
477
478 if (argc < 1) {
479 printf("Invalid 'wps_config' command - at least two arguments "
480 "are required.\n");
481 return -1;
482 }
483
484 ssid_hex[0] = '\0';
485 for (i = 0; i < 32; i++) {
486 if (argv[0][i] == '\0')
487 break;
488 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
489 }
490
491 key_hex[0] = '\0';
492 if (argc > 3) {
493 for (i = 0; i < 64; i++) {
494 if (argv[3][i] == '\0')
495 break;
496 os_snprintf(&key_hex[i * 2], 3, "%02x",
497 argv[3][i]);
498 }
499 }
500
501 if (argc > 3)
502 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
503 ssid_hex, argv[1], argv[2], key_hex);
504 else if (argc > 2)
505 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
506 ssid_hex, argv[1], argv[2]);
507 else
508 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
509 ssid_hex, argv[1]);
510 return wpa_ctrl_command(ctrl, buf);
511}
512#endif /* CONFIG_WPS */
513
514
515static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
516 char *argv[])
517{
518 return wpa_ctrl_command(ctrl, "GET_CONFIG");
519}
520
521
522static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
523 char *addr, size_t addr_len)
524{
525 char buf[4096], *pos;
526 size_t len;
527 int ret;
528
529 if (ctrl_conn == NULL) {
530 printf("Not connected to hostapd - command dropped.\n");
531 return -1;
532 }
533 len = sizeof(buf) - 1;
534 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
535 hostapd_cli_msg_cb);
536 if (ret == -2) {
537 printf("'%s' command timed out.\n", cmd);
538 return -2;
539 } else if (ret < 0) {
540 printf("'%s' command failed.\n", cmd);
541 return -1;
542 }
543
544 buf[len] = '\0';
545 if (memcmp(buf, "FAIL", 4) == 0)
546 return -1;
547 printf("%s", buf);
548
549 pos = buf;
550 while (*pos != '\0' && *pos != '\n')
551 pos++;
552 *pos = '\0';
553 os_strlcpy(addr, buf, addr_len);
554 return 0;
555}
556
557
558static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
559 char *argv[])
560{
561 char addr[32], cmd[64];
562
563 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
564 return 0;
565 do {
566 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
567 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
568
569 return -1;
570}
571
572
573static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
574{
575 printf("%s", commands_help);
576 return 0;
577}
578
579
580static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
581 char *argv[])
582{
583 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
584 return 0;
585}
586
587
588static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
589{
590 hostapd_cli_quit = 1;
591 return 0;
592}
593
594
595static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
596{
597 char cmd[256];
598 if (argc != 1) {
599 printf("Invalid LEVEL command: needs one argument (debug "
600 "level)\n");
601 return 0;
602 }
603 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
604 return wpa_ctrl_command(ctrl, cmd);
605}
606
607
608static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
609{
610 struct dirent *dent;
611 DIR *dir;
612
613 dir = opendir(ctrl_iface_dir);
614 if (dir == NULL) {
615 printf("Control interface directory '%s' could not be "
616 "openned.\n", ctrl_iface_dir);
617 return;
618 }
619
620 printf("Available interfaces:\n");
621 while ((dent = readdir(dir))) {
622 if (strcmp(dent->d_name, ".") == 0 ||
623 strcmp(dent->d_name, "..") == 0)
624 continue;
625 printf("%s\n", dent->d_name);
626 }
627 closedir(dir);
628}
629
630
631static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
632 char *argv[])
633{
634 if (argc < 1) {
635 hostapd_cli_list_interfaces(ctrl);
636 return 0;
637 }
638
639 hostapd_cli_close_connection();
640 free(ctrl_ifname);
641 ctrl_ifname = strdup(argv[0]);
642
643 if (hostapd_cli_open_connection(ctrl_ifname)) {
644 printf("Connected to interface '%s.\n", ctrl_ifname);
645 if (wpa_ctrl_attach(ctrl_conn) == 0) {
646 hostapd_cli_attached = 1;
647 } else {
648 printf("Warning: Failed to attach to "
649 "hostapd.\n");
650 }
651 } else {
652 printf("Could not connect to interface '%s' - re-trying\n",
653 ctrl_ifname);
654 }
655 return 0;
656}
657
658
659static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
660{
661 char cmd[256];
662 int res;
663
664 if (argc != 2) {
665 printf("Invalid SET command: needs two arguments (variable "
666 "name and value)\n");
667 return -1;
668 }
669
670 res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
671 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
672 printf("Too long SET command.\n");
673 return -1;
674 }
675 return wpa_ctrl_command(ctrl, cmd);
676}
677
678
679static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
680{
681 char cmd[256];
682 int res;
683
684 if (argc != 1) {
685 printf("Invalid GET command: needs one argument (variable "
686 "name)\n");
687 return -1;
688 }
689
690 res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
691 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
692 printf("Too long GET command.\n");
693 return -1;
694 }
695 return wpa_ctrl_command(ctrl, cmd);
696}
697
698
699struct hostapd_cli_cmd {
700 const char *cmd;
701 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
702};
703
704static struct hostapd_cli_cmd hostapd_cli_commands[] = {
705 { "ping", hostapd_cli_cmd_ping },
706 { "mib", hostapd_cli_cmd_mib },
707 { "relog", hostapd_cli_cmd_relog },
708 { "sta", hostapd_cli_cmd_sta },
709 { "all_sta", hostapd_cli_cmd_all_sta },
710 { "new_sta", hostapd_cli_cmd_new_sta },
711 { "deauthenticate", hostapd_cli_cmd_deauthenticate },
712 { "disassociate", hostapd_cli_cmd_disassociate },
713#ifdef CONFIG_IEEE80211W
714 { "sa_query", hostapd_cli_cmd_sa_query },
715#endif /* CONFIG_IEEE80211W */
716#ifdef CONFIG_WPS
717 { "wps_pin", hostapd_cli_cmd_wps_pin },
718 { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
719 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
720#ifdef CONFIG_WPS_OOB
721 { "wps_oob", hostapd_cli_cmd_wps_oob },
722#endif /* CONFIG_WPS_OOB */
723 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
724 { "wps_config", hostapd_cli_cmd_wps_config },
725#endif /* CONFIG_WPS */
726 { "get_config", hostapd_cli_cmd_get_config },
727 { "help", hostapd_cli_cmd_help },
728 { "interface", hostapd_cli_cmd_interface },
729 { "level", hostapd_cli_cmd_level },
730 { "license", hostapd_cli_cmd_license },
731 { "quit", hostapd_cli_cmd_quit },
732 { "set", hostapd_cli_cmd_set },
733 { "get", hostapd_cli_cmd_get },
734 { NULL, NULL }
735};
736
737
738static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
739{
740 struct hostapd_cli_cmd *cmd, *match = NULL;
741 int count;
742
743 count = 0;
744 cmd = hostapd_cli_commands;
745 while (cmd->cmd) {
746 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
747 match = cmd;
748 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
749 /* we have an exact match */
750 count = 1;
751 break;
752 }
753 count++;
754 }
755 cmd++;
756 }
757
758 if (count > 1) {
759 printf("Ambiguous command '%s'; possible commands:", argv[0]);
760 cmd = hostapd_cli_commands;
761 while (cmd->cmd) {
762 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
763 0) {
764 printf(" %s", cmd->cmd);
765 }
766 cmd++;
767 }
768 printf("\n");
769 } else if (count == 0) {
770 printf("Unknown command '%s'\n", argv[0]);
771 } else {
772 match->handler(ctrl, argc - 1, &argv[1]);
773 }
774}
775
776
777static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
778 int action_monitor)
779{
780 int first = 1;
781 if (ctrl_conn == NULL)
782 return;
783 while (wpa_ctrl_pending(ctrl)) {
784 char buf[256];
785 size_t len = sizeof(buf) - 1;
786 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
787 buf[len] = '\0';
788 if (action_monitor)
789 hostapd_cli_action_process(buf, len);
790 else {
791 if (in_read && first)
792 printf("\n");
793 first = 0;
794 printf("%s\n", buf);
795 }
796 } else {
797 printf("Could not read pending message.\n");
798 break;
799 }
800 }
801}
802
803
804static void hostapd_cli_interactive(void)
805{
806 const int max_args = 10;
807 char cmd[256], *res, *argv[max_args], *pos;
808 int argc;
809
810 printf("\nInteractive mode\n\n");
811
812 do {
813 hostapd_cli_recv_pending(ctrl_conn, 0, 0);
814 printf("> ");
815 alarm(ping_interval);
816 res = fgets(cmd, sizeof(cmd), stdin);
817 alarm(0);
818 if (res == NULL)
819 break;
820 pos = cmd;
821 while (*pos != '\0') {
822 if (*pos == '\n') {
823 *pos = '\0';
824 break;
825 }
826 pos++;
827 }
828 argc = 0;
829 pos = cmd;
830 for (;;) {
831 while (*pos == ' ')
832 pos++;
833 if (*pos == '\0')
834 break;
835 argv[argc] = pos;
836 argc++;
837 if (argc == max_args)
838 break;
839 while (*pos != '\0' && *pos != ' ')
840 pos++;
841 if (*pos == ' ')
842 *pos++ = '\0';
843 }
844 if (argc)
845 wpa_request(ctrl_conn, argc, argv);
846 } while (!hostapd_cli_quit);
847}
848
849
850static void hostapd_cli_cleanup(void)
851{
852 hostapd_cli_close_connection();
853 if (pid_file)
854 os_daemonize_terminate(pid_file);
855
856 os_program_deinit();
857}
858
859
860static void hostapd_cli_terminate(int sig)
861{
862 hostapd_cli_cleanup();
863 exit(0);
864}
865
866
867static void hostapd_cli_alarm(int sig)
868{
869 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
870 printf("Connection to hostapd lost - trying to reconnect\n");
871 hostapd_cli_close_connection();
872 }
873 if (!ctrl_conn) {
874 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
875 if (ctrl_conn) {
876 printf("Connection to hostapd re-established\n");
877 if (wpa_ctrl_attach(ctrl_conn) == 0) {
878 hostapd_cli_attached = 1;
879 } else {
880 printf("Warning: Failed to attach to "
881 "hostapd.\n");
882 }
883 }
884 }
885 if (ctrl_conn)
886 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
887 alarm(ping_interval);
888}
889
890
891static void hostapd_cli_action(struct wpa_ctrl *ctrl)
892{
893 fd_set rfds;
894 int fd, res;
895 struct timeval tv;
896 char buf[256];
897 size_t len;
898
899 fd = wpa_ctrl_get_fd(ctrl);
900
901 while (!hostapd_cli_quit) {
902 FD_ZERO(&rfds);
903 FD_SET(fd, &rfds);
904 tv.tv_sec = ping_interval;
905 tv.tv_usec = 0;
906 res = select(fd + 1, &rfds, NULL, NULL, &tv);
907 if (res < 0 && errno != EINTR) {
908 perror("select");
909 break;
910 }
911
912 if (FD_ISSET(fd, &rfds))
913 hostapd_cli_recv_pending(ctrl, 0, 1);
914 else {
915 len = sizeof(buf) - 1;
916 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
917 hostapd_cli_action_process) < 0 ||
918 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
919 printf("hostapd did not reply to PING "
920 "command - exiting\n");
921 break;
922 }
923 }
924 }
925}
926
927
928int main(int argc, char *argv[])
929{
930 int interactive;
931 int warning_displayed = 0;
932 int c;
933 int daemonize = 0;
934
935 if (os_program_init())
936 return -1;
937
938 for (;;) {
939 c = getopt(argc, argv, "a:BhG:i:p:v");
940 if (c < 0)
941 break;
942 switch (c) {
943 case 'a':
944 action_file = optarg;
945 break;
946 case 'B':
947 daemonize = 1;
948 break;
949 case 'G':
950 ping_interval = atoi(optarg);
951 break;
952 case 'h':
953 usage();
954 return 0;
955 case 'v':
956 printf("%s\n", hostapd_cli_version);
957 return 0;
958 case 'i':
959 os_free(ctrl_ifname);
960 ctrl_ifname = os_strdup(optarg);
961 break;
962 case 'p':
963 ctrl_iface_dir = optarg;
964 break;
965 default:
966 usage();
967 return -1;
968 }
969 }
970
971 interactive = (argc == optind) && (action_file == NULL);
972
973 if (interactive) {
974 printf("%s\n\n%s\n\n", hostapd_cli_version,
975 hostapd_cli_license);
976 }
977
978 for (;;) {
979 if (ctrl_ifname == NULL) {
980 struct dirent *dent;
981 DIR *dir = opendir(ctrl_iface_dir);
982 if (dir) {
983 while ((dent = readdir(dir))) {
984 if (os_strcmp(dent->d_name, ".") == 0
985 ||
986 os_strcmp(dent->d_name, "..") == 0)
987 continue;
988 printf("Selected interface '%s'\n",
989 dent->d_name);
990 ctrl_ifname = os_strdup(dent->d_name);
991 break;
992 }
993 closedir(dir);
994 }
995 }
996 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
997 if (ctrl_conn) {
998 if (warning_displayed)
999 printf("Connection established.\n");
1000 break;
1001 }
1002
1003 if (!interactive) {
1004 perror("Failed to connect to hostapd - "
1005 "wpa_ctrl_open");
1006 return -1;
1007 }
1008
1009 if (!warning_displayed) {
1010 printf("Could not connect to hostapd - re-trying\n");
1011 warning_displayed = 1;
1012 }
1013 os_sleep(1, 0);
1014 continue;
1015 }
1016
1017 signal(SIGINT, hostapd_cli_terminate);
1018 signal(SIGTERM, hostapd_cli_terminate);
1019 signal(SIGALRM, hostapd_cli_alarm);
1020
1021 if (interactive || action_file) {
1022 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1023 hostapd_cli_attached = 1;
1024 } else {
1025 printf("Warning: Failed to attach to hostapd.\n");
1026 if (action_file)
1027 return -1;
1028 }
1029 }
1030
1031 if (daemonize && os_daemonize(pid_file))
1032 return -1;
1033
1034 if (interactive)
1035 hostapd_cli_interactive();
1036 else if (action_file)
1037 hostapd_cli_action(ctrl_conn);
1038 else
1039 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1040
1041 os_free(ctrl_ifname);
1042 hostapd_cli_cleanup();
1043 return 0;
1044}