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