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