]> git.ipfire.org Git - thirdparty/hostap.git/blob - hostapd/hostapd_cli.c
633c13d2769af87507b45c250d201825bc604774
[thirdparty/hostap.git] / hostapd / hostapd_cli.c
1 /*
2 * hostapd - command line interface for hostapd daemon
3 * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9 #include "includes.h"
10 #include <dirent.h>
11
12 #include "common/wpa_ctrl.h"
13 #include "utils/common.h"
14 #include "utils/eloop.h"
15 #include "utils/edit.h"
16 #include "common/version.h"
17
18
19 static const char *hostapd_cli_version =
20 "hostapd_cli v" VERSION_STR "\n"
21 "Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> and contributors";
22
23
24 static const char *hostapd_cli_license =
25 "This software may be distributed under the terms of the BSD license.\n"
26 "See README for more details.\n";
27
28 static const char *hostapd_cli_full_license =
29 "This software may be distributed under the terms of the BSD license.\n"
30 "\n"
31 "Redistribution and use in source and binary forms, with or without\n"
32 "modification, are permitted provided that the following conditions are\n"
33 "met:\n"
34 "\n"
35 "1. Redistributions of source code must retain the above copyright\n"
36 " notice, this list of conditions and the following disclaimer.\n"
37 "\n"
38 "2. Redistributions in binary form must reproduce the above copyright\n"
39 " notice, this list of conditions and the following disclaimer in the\n"
40 " documentation and/or other materials provided with the distribution.\n"
41 "\n"
42 "3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
43 " names of its contributors may be used to endorse or promote products\n"
44 " derived from this software without specific prior written permission.\n"
45 "\n"
46 "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
47 "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
48 "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
49 "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
50 "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
51 "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
52 "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
53 "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
54 "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
55 "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
56 "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
57 "\n";
58
59 static const char *commands_help =
60 "Commands:\n"
61 " mib get MIB variables (dot1x, dot11, radius)\n"
62 " sta <addr> get MIB variables for one station\n"
63 " all_sta get MIB variables for all stations\n"
64 " new_sta <addr> add a new station\n"
65 " deauthenticate <addr> deauthenticate a station\n"
66 " disassociate <addr> disassociate a station\n"
67 #ifdef CONFIG_IEEE80211W
68 " sa_query <addr> send SA Query to a station\n"
69 #endif /* CONFIG_IEEE80211W */
70 #ifdef CONFIG_WPS
71 " wps_pin <uuid> <pin> [timeout] [addr] add WPS Enrollee PIN\n"
72 " wps_check_pin <PIN> verify PIN checksum\n"
73 " wps_pbc indicate button pushed to initiate PBC\n"
74 " wps_cancel cancel the pending WPS operation\n"
75 #ifdef CONFIG_WPS_NFC
76 " wps_nfc_tag_read <hexdump> report read NFC tag with WPS data\n"
77 " wps_nfc_config_token <WPS/NDEF> build NFC configuration token\n"
78 " wps_nfc_token <WPS/NDEF/enable/disable> manager NFC password token\n"
79 #endif /* CONFIG_WPS_NFC */
80 " wps_ap_pin <cmd> [params..] enable/disable AP PIN\n"
81 " wps_config <SSID> <auth> <encr> <key> configure AP\n"
82 #endif /* CONFIG_WPS */
83 " get_config show current configuration\n"
84 " help show this usage help\n"
85 " interface [ifname] show interfaces/select interface\n"
86 " level <debug level> change debug level\n"
87 " license show full hostapd_cli license\n"
88 " quit exit hostapd_cli\n";
89
90 static struct wpa_ctrl *ctrl_conn;
91 static int hostapd_cli_quit = 0;
92 static int hostapd_cli_attached = 0;
93 static const char *ctrl_iface_dir = "/var/run/hostapd";
94 static char *ctrl_ifname = NULL;
95 static const char *pid_file = NULL;
96 static const char *action_file = NULL;
97 static int ping_interval = 5;
98 static int interactive = 0;
99
100
101 static void usage(void)
102 {
103 fprintf(stderr, "%s\n", hostapd_cli_version);
104 fprintf(stderr,
105 "\n"
106 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
107 "[-a<path>] \\\n"
108 " [-G<ping interval>] [command..]\n"
109 "\n"
110 "Options:\n"
111 " -h help (show this usage text)\n"
112 " -v shown version information\n"
113 " -p<path> path to find control sockets (default: "
114 "/var/run/hostapd)\n"
115 " -a<file> run in daemon mode executing the action file "
116 "based on events\n"
117 " from hostapd\n"
118 " -B run a daemon in the background\n"
119 " -i<ifname> Interface to listen on (default: first "
120 "interface found in the\n"
121 " socket path)\n\n"
122 "%s",
123 commands_help);
124 }
125
126
127 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
128 {
129 char *cfile;
130 int flen;
131
132 if (ifname == NULL)
133 return NULL;
134
135 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
136 cfile = malloc(flen);
137 if (cfile == NULL)
138 return NULL;
139 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
140
141 ctrl_conn = wpa_ctrl_open(cfile);
142 free(cfile);
143 return ctrl_conn;
144 }
145
146
147 static void hostapd_cli_close_connection(void)
148 {
149 if (ctrl_conn == NULL)
150 return;
151
152 if (hostapd_cli_attached) {
153 wpa_ctrl_detach(ctrl_conn);
154 hostapd_cli_attached = 0;
155 }
156 wpa_ctrl_close(ctrl_conn);
157 ctrl_conn = NULL;
158 }
159
160
161 static void hostapd_cli_msg_cb(char *msg, size_t len)
162 {
163 printf("%s\n", msg);
164 }
165
166
167 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
168 {
169 char buf[4096];
170 size_t len;
171 int ret;
172
173 if (ctrl_conn == NULL) {
174 printf("Not connected to hostapd - command dropped.\n");
175 return -1;
176 }
177 len = sizeof(buf) - 1;
178 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
179 hostapd_cli_msg_cb);
180 if (ret == -2) {
181 printf("'%s' command timed out.\n", cmd);
182 return -2;
183 } else if (ret < 0) {
184 printf("'%s' command failed.\n", cmd);
185 return -1;
186 }
187 if (print) {
188 buf[len] = '\0';
189 printf("%s", buf);
190 }
191 return 0;
192 }
193
194
195 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
196 {
197 return _wpa_ctrl_command(ctrl, cmd, 1);
198 }
199
200
201 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
202 {
203 return wpa_ctrl_command(ctrl, "PING");
204 }
205
206
207 static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
208 {
209 return wpa_ctrl_command(ctrl, "RELOG");
210 }
211
212
213 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
214 {
215 return wpa_ctrl_command(ctrl, "MIB");
216 }
217
218
219 static int hostapd_cli_exec(const char *program, const char *arg1,
220 const char *arg2)
221 {
222 char *cmd;
223 size_t len;
224 int res;
225 int ret = 0;
226
227 len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
228 cmd = os_malloc(len);
229 if (cmd == NULL)
230 return -1;
231 res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
232 if (res < 0 || (size_t) res >= len) {
233 os_free(cmd);
234 return -1;
235 }
236 cmd[len - 1] = '\0';
237 #ifndef _WIN32_WCE
238 if (system(cmd) < 0)
239 ret = -1;
240 #endif /* _WIN32_WCE */
241 os_free(cmd);
242
243 return ret;
244 }
245
246
247 static void hostapd_cli_action_process(char *msg, size_t len)
248 {
249 const char *pos;
250
251 pos = msg;
252 if (*pos == '<') {
253 pos = os_strchr(pos, '>');
254 if (pos)
255 pos++;
256 else
257 pos = msg;
258 }
259
260 hostapd_cli_exec(action_file, ctrl_ifname, pos);
261 }
262
263
264 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
265 {
266 char buf[64];
267 if (argc != 1) {
268 printf("Invalid 'sta' command - exactly one argument, STA "
269 "address, is required.\n");
270 return -1;
271 }
272 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
273 return wpa_ctrl_command(ctrl, buf);
274 }
275
276
277 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
278 char *argv[])
279 {
280 char buf[64];
281 if (argc != 1) {
282 printf("Invalid 'new_sta' command - exactly one argument, STA "
283 "address, is required.\n");
284 return -1;
285 }
286 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
287 return wpa_ctrl_command(ctrl, buf);
288 }
289
290
291 static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
292 char *argv[])
293 {
294 char buf[64];
295 if (argc < 1) {
296 printf("Invalid 'deauthenticate' command - exactly one "
297 "argument, STA address, is required.\n");
298 return -1;
299 }
300 if (argc > 1)
301 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
302 argv[0], argv[1]);
303 else
304 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
305 return wpa_ctrl_command(ctrl, buf);
306 }
307
308
309 static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
310 char *argv[])
311 {
312 char buf[64];
313 if (argc < 1) {
314 printf("Invalid 'disassociate' command - exactly one "
315 "argument, STA address, is required.\n");
316 return -1;
317 }
318 if (argc > 1)
319 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
320 argv[0], argv[1]);
321 else
322 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
323 return wpa_ctrl_command(ctrl, buf);
324 }
325
326
327 #ifdef CONFIG_IEEE80211W
328 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
329 char *argv[])
330 {
331 char buf[64];
332 if (argc != 1) {
333 printf("Invalid 'sa_query' command - exactly one argument, "
334 "STA address, is required.\n");
335 return -1;
336 }
337 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
338 return wpa_ctrl_command(ctrl, buf);
339 }
340 #endif /* CONFIG_IEEE80211W */
341
342
343 #ifdef CONFIG_WPS
344 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
345 char *argv[])
346 {
347 char buf[256];
348 if (argc < 2) {
349 printf("Invalid 'wps_pin' command - at least two arguments, "
350 "UUID and PIN, are required.\n");
351 return -1;
352 }
353 if (argc > 3)
354 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
355 argv[0], argv[1], argv[2], argv[3]);
356 else if (argc > 2)
357 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
358 argv[0], argv[1], argv[2]);
359 else
360 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
361 return wpa_ctrl_command(ctrl, buf);
362 }
363
364
365 static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
366 char *argv[])
367 {
368 char cmd[256];
369 int res;
370
371 if (argc != 1 && argc != 2) {
372 printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
373 "- PIN to be verified\n");
374 return -1;
375 }
376
377 if (argc == 2)
378 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
379 argv[0], argv[1]);
380 else
381 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
382 argv[0]);
383 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
384 printf("Too long WPS_CHECK_PIN command.\n");
385 return -1;
386 }
387 return wpa_ctrl_command(ctrl, cmd);
388 }
389
390
391 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
392 char *argv[])
393 {
394 return wpa_ctrl_command(ctrl, "WPS_PBC");
395 }
396
397
398 static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
399 char *argv[])
400 {
401 return wpa_ctrl_command(ctrl, "WPS_CANCEL");
402 }
403
404
405 #ifdef CONFIG_WPS_NFC
406 static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
407 char *argv[])
408 {
409 int ret;
410 char *buf;
411 size_t buflen;
412
413 if (argc != 1) {
414 printf("Invalid 'wps_nfc_tag_read' command - one argument "
415 "is required.\n");
416 return -1;
417 }
418
419 buflen = 18 + os_strlen(argv[0]);
420 buf = os_malloc(buflen);
421 if (buf == NULL)
422 return -1;
423 os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
424
425 ret = wpa_ctrl_command(ctrl, buf);
426 os_free(buf);
427
428 return ret;
429 }
430
431
432 static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
433 int argc, char *argv[])
434 {
435 char cmd[64];
436 int res;
437
438 if (argc != 1) {
439 printf("Invalid 'wps_nfc_config_token' command - one argument "
440 "is required.\n");
441 return -1;
442 }
443
444 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
445 argv[0]);
446 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
447 printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
448 return -1;
449 }
450 return wpa_ctrl_command(ctrl, cmd);
451 }
452
453
454 static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
455 int argc, char *argv[])
456 {
457 char cmd[64];
458 int res;
459
460 if (argc != 1) {
461 printf("Invalid 'wps_nfc_token' command - one argument is "
462 "required.\n");
463 return -1;
464 }
465
466 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
467 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
468 printf("Too long WPS_NFC_TOKEN command.\n");
469 return -1;
470 }
471 return wpa_ctrl_command(ctrl, cmd);
472 }
473 #endif /* CONFIG_WPS_NFC */
474
475
476 static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
477 char *argv[])
478 {
479 char buf[64];
480 if (argc < 1) {
481 printf("Invalid 'wps_ap_pin' command - at least one argument "
482 "is required.\n");
483 return -1;
484 }
485 if (argc > 2)
486 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
487 argv[0], argv[1], argv[2]);
488 else if (argc > 1)
489 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
490 argv[0], argv[1]);
491 else
492 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
493 return wpa_ctrl_command(ctrl, buf);
494 }
495
496
497 static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
498 char *argv[])
499 {
500 char buf[256];
501 char ssid_hex[2 * 32 + 1];
502 char key_hex[2 * 64 + 1];
503 int i;
504
505 if (argc < 1) {
506 printf("Invalid 'wps_config' command - at least two arguments "
507 "are required.\n");
508 return -1;
509 }
510
511 ssid_hex[0] = '\0';
512 for (i = 0; i < 32; i++) {
513 if (argv[0][i] == '\0')
514 break;
515 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
516 }
517
518 key_hex[0] = '\0';
519 if (argc > 3) {
520 for (i = 0; i < 64; i++) {
521 if (argv[3][i] == '\0')
522 break;
523 os_snprintf(&key_hex[i * 2], 3, "%02x",
524 argv[3][i]);
525 }
526 }
527
528 if (argc > 3)
529 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
530 ssid_hex, argv[1], argv[2], key_hex);
531 else if (argc > 2)
532 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
533 ssid_hex, argv[1], argv[2]);
534 else
535 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
536 ssid_hex, argv[1]);
537 return wpa_ctrl_command(ctrl, buf);
538 }
539 #endif /* CONFIG_WPS */
540
541
542 static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
543 char *argv[])
544 {
545 char buf[300];
546 int res;
547
548 if (argc < 2) {
549 printf("Invalid 'ess_disassoc' command - two arguments (STA "
550 "addr and URL) are needed\n");
551 return -1;
552 }
553
554 res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s",
555 argv[0], argv[1]);
556 if (res < 0 || res >= (int) sizeof(buf))
557 return -1;
558 return wpa_ctrl_command(ctrl, buf);
559 }
560
561
562 static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
563 char *argv[])
564 {
565 return wpa_ctrl_command(ctrl, "GET_CONFIG");
566 }
567
568
569 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
570 char *addr, size_t addr_len)
571 {
572 char buf[4096], *pos;
573 size_t len;
574 int ret;
575
576 if (ctrl_conn == NULL) {
577 printf("Not connected to hostapd - command dropped.\n");
578 return -1;
579 }
580 len = sizeof(buf) - 1;
581 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
582 hostapd_cli_msg_cb);
583 if (ret == -2) {
584 printf("'%s' command timed out.\n", cmd);
585 return -2;
586 } else if (ret < 0) {
587 printf("'%s' command failed.\n", cmd);
588 return -1;
589 }
590
591 buf[len] = '\0';
592 if (memcmp(buf, "FAIL", 4) == 0)
593 return -1;
594 printf("%s", buf);
595
596 pos = buf;
597 while (*pos != '\0' && *pos != '\n')
598 pos++;
599 *pos = '\0';
600 os_strlcpy(addr, buf, addr_len);
601 return 0;
602 }
603
604
605 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
606 char *argv[])
607 {
608 char addr[32], cmd[64];
609
610 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
611 return 0;
612 do {
613 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
614 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
615
616 return -1;
617 }
618
619
620 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
621 {
622 printf("%s", commands_help);
623 return 0;
624 }
625
626
627 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
628 char *argv[])
629 {
630 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
631 return 0;
632 }
633
634
635 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
636 {
637 hostapd_cli_quit = 1;
638 if (interactive)
639 eloop_terminate();
640 return 0;
641 }
642
643
644 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
645 {
646 char cmd[256];
647 if (argc != 1) {
648 printf("Invalid LEVEL command: needs one argument (debug "
649 "level)\n");
650 return 0;
651 }
652 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
653 return wpa_ctrl_command(ctrl, cmd);
654 }
655
656
657 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
658 {
659 struct dirent *dent;
660 DIR *dir;
661
662 dir = opendir(ctrl_iface_dir);
663 if (dir == NULL) {
664 printf("Control interface directory '%s' could not be "
665 "openned.\n", ctrl_iface_dir);
666 return;
667 }
668
669 printf("Available interfaces:\n");
670 while ((dent = readdir(dir))) {
671 if (strcmp(dent->d_name, ".") == 0 ||
672 strcmp(dent->d_name, "..") == 0)
673 continue;
674 printf("%s\n", dent->d_name);
675 }
676 closedir(dir);
677 }
678
679
680 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
681 char *argv[])
682 {
683 if (argc < 1) {
684 hostapd_cli_list_interfaces(ctrl);
685 return 0;
686 }
687
688 hostapd_cli_close_connection();
689 free(ctrl_ifname);
690 ctrl_ifname = strdup(argv[0]);
691
692 if (hostapd_cli_open_connection(ctrl_ifname)) {
693 printf("Connected to interface '%s.\n", ctrl_ifname);
694 if (wpa_ctrl_attach(ctrl_conn) == 0) {
695 hostapd_cli_attached = 1;
696 } else {
697 printf("Warning: Failed to attach to "
698 "hostapd.\n");
699 }
700 } else {
701 printf("Could not connect to interface '%s' - re-trying\n",
702 ctrl_ifname);
703 }
704 return 0;
705 }
706
707
708 static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
709 {
710 char cmd[256];
711 int res;
712
713 if (argc != 2) {
714 printf("Invalid SET command: needs two arguments (variable "
715 "name and value)\n");
716 return -1;
717 }
718
719 res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
720 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
721 printf("Too long SET command.\n");
722 return -1;
723 }
724 return wpa_ctrl_command(ctrl, cmd);
725 }
726
727
728 static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
729 {
730 char cmd[256];
731 int res;
732
733 if (argc != 1) {
734 printf("Invalid GET command: needs one argument (variable "
735 "name)\n");
736 return -1;
737 }
738
739 res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
740 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
741 printf("Too long GET command.\n");
742 return -1;
743 }
744 return wpa_ctrl_command(ctrl, cmd);
745 }
746
747
748 struct hostapd_cli_cmd {
749 const char *cmd;
750 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
751 };
752
753 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
754 { "ping", hostapd_cli_cmd_ping },
755 { "mib", hostapd_cli_cmd_mib },
756 { "relog", hostapd_cli_cmd_relog },
757 { "sta", hostapd_cli_cmd_sta },
758 { "all_sta", hostapd_cli_cmd_all_sta },
759 { "new_sta", hostapd_cli_cmd_new_sta },
760 { "deauthenticate", hostapd_cli_cmd_deauthenticate },
761 { "disassociate", hostapd_cli_cmd_disassociate },
762 #ifdef CONFIG_IEEE80211W
763 { "sa_query", hostapd_cli_cmd_sa_query },
764 #endif /* CONFIG_IEEE80211W */
765 #ifdef CONFIG_WPS
766 { "wps_pin", hostapd_cli_cmd_wps_pin },
767 { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
768 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
769 { "wps_cancel", hostapd_cli_cmd_wps_cancel },
770 #ifdef CONFIG_WPS_NFC
771 { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
772 { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
773 { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
774 #endif /* CONFIG_WPS_NFC */
775 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
776 { "wps_config", hostapd_cli_cmd_wps_config },
777 #endif /* CONFIG_WPS */
778 { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
779 { "get_config", hostapd_cli_cmd_get_config },
780 { "help", hostapd_cli_cmd_help },
781 { "interface", hostapd_cli_cmd_interface },
782 { "level", hostapd_cli_cmd_level },
783 { "license", hostapd_cli_cmd_license },
784 { "quit", hostapd_cli_cmd_quit },
785 { "set", hostapd_cli_cmd_set },
786 { "get", hostapd_cli_cmd_get },
787 { NULL, NULL }
788 };
789
790
791 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
792 {
793 struct hostapd_cli_cmd *cmd, *match = NULL;
794 int count;
795
796 count = 0;
797 cmd = hostapd_cli_commands;
798 while (cmd->cmd) {
799 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
800 match = cmd;
801 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
802 /* we have an exact match */
803 count = 1;
804 break;
805 }
806 count++;
807 }
808 cmd++;
809 }
810
811 if (count > 1) {
812 printf("Ambiguous command '%s'; possible commands:", argv[0]);
813 cmd = hostapd_cli_commands;
814 while (cmd->cmd) {
815 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
816 0) {
817 printf(" %s", cmd->cmd);
818 }
819 cmd++;
820 }
821 printf("\n");
822 } else if (count == 0) {
823 printf("Unknown command '%s'\n", argv[0]);
824 } else {
825 match->handler(ctrl, argc - 1, &argv[1]);
826 }
827 }
828
829
830 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
831 int action_monitor)
832 {
833 int first = 1;
834 if (ctrl_conn == NULL)
835 return;
836 while (wpa_ctrl_pending(ctrl)) {
837 char buf[256];
838 size_t len = sizeof(buf) - 1;
839 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
840 buf[len] = '\0';
841 if (action_monitor)
842 hostapd_cli_action_process(buf, len);
843 else {
844 if (in_read && first)
845 printf("\n");
846 first = 0;
847 printf("%s\n", buf);
848 }
849 } else {
850 printf("Could not read pending message.\n");
851 break;
852 }
853 }
854 }
855
856
857 #define max_args 10
858
859 static int tokenize_cmd(char *cmd, char *argv[])
860 {
861 char *pos;
862 int argc = 0;
863
864 pos = cmd;
865 for (;;) {
866 while (*pos == ' ')
867 pos++;
868 if (*pos == '\0')
869 break;
870 argv[argc] = pos;
871 argc++;
872 if (argc == max_args)
873 break;
874 if (*pos == '"') {
875 char *pos2 = os_strrchr(pos, '"');
876 if (pos2)
877 pos = pos2 + 1;
878 }
879 while (*pos != '\0' && *pos != ' ')
880 pos++;
881 if (*pos == ' ')
882 *pos++ = '\0';
883 }
884
885 return argc;
886 }
887
888
889 static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
890 {
891 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
892 printf("Connection to hostapd lost - trying to reconnect\n");
893 hostapd_cli_close_connection();
894 }
895 if (!ctrl_conn) {
896 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
897 if (ctrl_conn) {
898 printf("Connection to hostapd re-established\n");
899 if (wpa_ctrl_attach(ctrl_conn) == 0) {
900 hostapd_cli_attached = 1;
901 } else {
902 printf("Warning: Failed to attach to "
903 "hostapd.\n");
904 }
905 }
906 }
907 if (ctrl_conn)
908 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
909 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
910 }
911
912
913 static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
914 {
915 eloop_terminate();
916 }
917
918
919 static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
920 {
921 char *argv[max_args];
922 int argc;
923 argc = tokenize_cmd(cmd, argv);
924 if (argc)
925 wpa_request(ctrl_conn, argc, argv);
926 }
927
928
929 static void hostapd_cli_edit_eof_cb(void *ctx)
930 {
931 eloop_terminate();
932 }
933
934
935 static void hostapd_cli_interactive(void)
936 {
937 printf("\nInteractive mode\n\n");
938
939 eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
940 edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
941 NULL, NULL, NULL, NULL);
942 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
943
944 eloop_run();
945
946 edit_deinit(NULL, NULL);
947 eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
948 }
949
950
951 static void hostapd_cli_cleanup(void)
952 {
953 hostapd_cli_close_connection();
954 if (pid_file)
955 os_daemonize_terminate(pid_file);
956
957 os_program_deinit();
958 }
959
960
961 static void hostapd_cli_action(struct wpa_ctrl *ctrl)
962 {
963 fd_set rfds;
964 int fd, res;
965 struct timeval tv;
966 char buf[256];
967 size_t len;
968
969 fd = wpa_ctrl_get_fd(ctrl);
970
971 while (!hostapd_cli_quit) {
972 FD_ZERO(&rfds);
973 FD_SET(fd, &rfds);
974 tv.tv_sec = ping_interval;
975 tv.tv_usec = 0;
976 res = select(fd + 1, &rfds, NULL, NULL, &tv);
977 if (res < 0 && errno != EINTR) {
978 perror("select");
979 break;
980 }
981
982 if (FD_ISSET(fd, &rfds))
983 hostapd_cli_recv_pending(ctrl, 0, 1);
984 else {
985 len = sizeof(buf) - 1;
986 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
987 hostapd_cli_action_process) < 0 ||
988 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
989 printf("hostapd did not reply to PING "
990 "command - exiting\n");
991 break;
992 }
993 }
994 }
995 }
996
997
998 int main(int argc, char *argv[])
999 {
1000 int warning_displayed = 0;
1001 int c;
1002 int daemonize = 0;
1003
1004 if (os_program_init())
1005 return -1;
1006
1007 for (;;) {
1008 c = getopt(argc, argv, "a:BhG:i:p:v");
1009 if (c < 0)
1010 break;
1011 switch (c) {
1012 case 'a':
1013 action_file = optarg;
1014 break;
1015 case 'B':
1016 daemonize = 1;
1017 break;
1018 case 'G':
1019 ping_interval = atoi(optarg);
1020 break;
1021 case 'h':
1022 usage();
1023 return 0;
1024 case 'v':
1025 printf("%s\n", hostapd_cli_version);
1026 return 0;
1027 case 'i':
1028 os_free(ctrl_ifname);
1029 ctrl_ifname = os_strdup(optarg);
1030 break;
1031 case 'p':
1032 ctrl_iface_dir = optarg;
1033 break;
1034 default:
1035 usage();
1036 return -1;
1037 }
1038 }
1039
1040 interactive = (argc == optind) && (action_file == NULL);
1041
1042 if (interactive) {
1043 printf("%s\n\n%s\n\n", hostapd_cli_version,
1044 hostapd_cli_license);
1045 }
1046
1047 if (eloop_init())
1048 return -1;
1049
1050 for (;;) {
1051 if (ctrl_ifname == NULL) {
1052 struct dirent *dent;
1053 DIR *dir = opendir(ctrl_iface_dir);
1054 if (dir) {
1055 while ((dent = readdir(dir))) {
1056 if (os_strcmp(dent->d_name, ".") == 0
1057 ||
1058 os_strcmp(dent->d_name, "..") == 0)
1059 continue;
1060 printf("Selected interface '%s'\n",
1061 dent->d_name);
1062 ctrl_ifname = os_strdup(dent->d_name);
1063 break;
1064 }
1065 closedir(dir);
1066 }
1067 }
1068 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1069 if (ctrl_conn) {
1070 if (warning_displayed)
1071 printf("Connection established.\n");
1072 break;
1073 }
1074
1075 if (!interactive) {
1076 perror("Failed to connect to hostapd - "
1077 "wpa_ctrl_open");
1078 return -1;
1079 }
1080
1081 if (!warning_displayed) {
1082 printf("Could not connect to hostapd - re-trying\n");
1083 warning_displayed = 1;
1084 }
1085 os_sleep(1, 0);
1086 continue;
1087 }
1088
1089 if (interactive || action_file) {
1090 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1091 hostapd_cli_attached = 1;
1092 } else {
1093 printf("Warning: Failed to attach to hostapd.\n");
1094 if (action_file)
1095 return -1;
1096 }
1097 }
1098
1099 if (daemonize && os_daemonize(pid_file))
1100 return -1;
1101
1102 if (interactive)
1103 hostapd_cli_interactive();
1104 else if (action_file)
1105 hostapd_cli_action(ctrl_conn);
1106 else
1107 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1108
1109 os_free(ctrl_ifname);
1110 eloop_destroy();
1111 hostapd_cli_cleanup();
1112 return 0;
1113 }