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