hostapd: Add vendor command support
[mech_eap.git] / 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_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc,
747                                           char *argv[])
748 {
749         char buf[300];
750         int res;
751
752         if (argc < 2) {
753                 printf("Invalid 'hs20_wnm_notif' command - two arguments (STA "
754                        "addr and URL) are needed\n");
755                 return -1;
756         }
757
758         res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s",
759                           argv[0], argv[1]);
760         if (res < 0 || res >= (int) sizeof(buf))
761                 return -1;
762         return wpa_ctrl_command(ctrl, buf);
763 }
764
765
766 static int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc,
767                                            char *argv[])
768 {
769         char buf[300];
770         int res;
771
772         if (argc < 3) {
773                 printf("Invalid 'hs20_deauth_req' command - at least three arguments (STA addr, Code, Re-auth Delay) are needed\n");
774                 return -1;
775         }
776
777         if (argc > 3)
778                 res = os_snprintf(buf, sizeof(buf),
779                                   "HS20_DEAUTH_REQ %s %s %s %s",
780                                   argv[0], argv[1], argv[2], argv[3]);
781         else
782                 res = os_snprintf(buf, sizeof(buf),
783                                   "HS20_DEAUTH_REQ %s %s %s",
784                                   argv[0], argv[1], argv[2]);
785         if (res < 0 || res >= (int) sizeof(buf))
786                 return -1;
787         return wpa_ctrl_command(ctrl, buf);
788 }
789
790
791 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
792 {
793         hostapd_cli_quit = 1;
794         if (interactive)
795                 eloop_terminate();
796         return 0;
797 }
798
799
800 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
801 {
802         char cmd[256];
803         if (argc != 1) {
804                 printf("Invalid LEVEL command: needs one argument (debug "
805                        "level)\n");
806                 return 0;
807         }
808         snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
809         return wpa_ctrl_command(ctrl, cmd);
810 }
811
812
813 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
814 {
815         struct dirent *dent;
816         DIR *dir;
817
818         dir = opendir(ctrl_iface_dir);
819         if (dir == NULL) {
820                 printf("Control interface directory '%s' could not be "
821                        "openned.\n", ctrl_iface_dir);
822                 return;
823         }
824
825         printf("Available interfaces:\n");
826         while ((dent = readdir(dir))) {
827                 if (strcmp(dent->d_name, ".") == 0 ||
828                     strcmp(dent->d_name, "..") == 0)
829                         continue;
830                 printf("%s\n", dent->d_name);
831         }
832         closedir(dir);
833 }
834
835
836 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
837                                      char *argv[])
838 {
839         if (argc < 1) {
840                 hostapd_cli_list_interfaces(ctrl);
841                 return 0;
842         }
843
844         hostapd_cli_close_connection();
845         free(ctrl_ifname);
846         ctrl_ifname = strdup(argv[0]);
847
848         if (hostapd_cli_open_connection(ctrl_ifname)) {
849                 printf("Connected to interface '%s.\n", ctrl_ifname);
850                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
851                         hostapd_cli_attached = 1;
852                 } else {
853                         printf("Warning: Failed to attach to "
854                                "hostapd.\n");
855                 }
856         } else {
857                 printf("Could not connect to interface '%s' - re-trying\n",
858                         ctrl_ifname);
859         }
860         return 0;
861 }
862
863
864 static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
865 {
866         char cmd[256];
867         int res;
868
869         if (argc != 2) {
870                 printf("Invalid SET command: needs two arguments (variable "
871                        "name and value)\n");
872                 return -1;
873         }
874
875         res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
876         if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
877                 printf("Too long SET command.\n");
878                 return -1;
879         }
880         return wpa_ctrl_command(ctrl, cmd);
881 }
882
883
884 static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
885 {
886         char cmd[256];
887         int res;
888
889         if (argc != 1) {
890                 printf("Invalid GET command: needs one argument (variable "
891                        "name)\n");
892                 return -1;
893         }
894
895         res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
896         if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
897                 printf("Too long GET command.\n");
898                 return -1;
899         }
900         return wpa_ctrl_command(ctrl, cmd);
901 }
902
903
904 static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
905                                        int argc, char *argv[])
906 {
907         char cmd[256];
908         int res;
909         int i;
910         char *tmp;
911         int total;
912
913         if (argc < 2) {
914                 printf("Invalid chan_switch command: needs at least two "
915                        "arguments (count and freq)\n"
916                        "usage: <cs_count> <freq> [sec_channel_offset=] "
917                        "[center_freq1=] [center_freq2=] [bandwidth=] "
918                        "[blocktx] [ht|vht]\n");
919                 return -1;
920         }
921
922         res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
923                           argv[0], argv[1]);
924         if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
925                 printf("Too long CHAN_SWITCH command.\n");
926                 return -1;
927         }
928
929         total = res;
930         for (i = 2; i < argc; i++) {
931                 tmp = cmd + total;
932                 res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
933                 if (res < 0 || (size_t) res >= sizeof(cmd) - total - 1) {
934                         printf("Too long CHAN_SWITCH command.\n");
935                         return -1;
936                 }
937                 total += res;
938         }
939         return wpa_ctrl_command(ctrl, cmd);
940 }
941
942
943 static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
944 {
945         char cmd[256];
946         int res;
947
948         if (argc < 2 || argc > 3) {
949                 printf("Invalid vendor command\n"
950                        "usage: <vendor id> <command id> [<hex formatted command argument>]\n");
951                 return -1;
952         }
953
954         res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
955                           argc == 3 ? argv[2] : "");
956         if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
957                 printf("Too long VENDOR command.\n");
958                 return -1;
959         }
960         return wpa_ctrl_command(ctrl, cmd);
961 }
962
963
964 struct hostapd_cli_cmd {
965         const char *cmd;
966         int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
967 };
968
969 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
970         { "ping", hostapd_cli_cmd_ping },
971         { "mib", hostapd_cli_cmd_mib },
972         { "relog", hostapd_cli_cmd_relog },
973         { "status", hostapd_cli_cmd_status },
974         { "sta", hostapd_cli_cmd_sta },
975         { "all_sta", hostapd_cli_cmd_all_sta },
976         { "new_sta", hostapd_cli_cmd_new_sta },
977         { "deauthenticate", hostapd_cli_cmd_deauthenticate },
978         { "disassociate", hostapd_cli_cmd_disassociate },
979 #ifdef CONFIG_IEEE80211W
980         { "sa_query", hostapd_cli_cmd_sa_query },
981 #endif /* CONFIG_IEEE80211W */
982 #ifdef CONFIG_WPS
983         { "wps_pin", hostapd_cli_cmd_wps_pin },
984         { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
985         { "wps_pbc", hostapd_cli_cmd_wps_pbc },
986         { "wps_cancel", hostapd_cli_cmd_wps_cancel },
987 #ifdef CONFIG_WPS_NFC
988         { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
989         { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
990         { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
991         { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
992 #endif /* CONFIG_WPS_NFC */
993         { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
994         { "wps_config", hostapd_cli_cmd_wps_config },
995         { "wps_get_status", hostapd_cli_cmd_wps_get_status },
996 #endif /* CONFIG_WPS */
997         { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
998         { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
999         { "get_config", hostapd_cli_cmd_get_config },
1000         { "help", hostapd_cli_cmd_help },
1001         { "interface", hostapd_cli_cmd_interface },
1002         { "level", hostapd_cli_cmd_level },
1003         { "license", hostapd_cli_cmd_license },
1004         { "quit", hostapd_cli_cmd_quit },
1005         { "set", hostapd_cli_cmd_set },
1006         { "get", hostapd_cli_cmd_get },
1007         { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
1008         { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
1009         { "chan_switch", hostapd_cli_cmd_chan_switch },
1010         { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif },
1011         { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req },
1012         { "vendor", hostapd_cli_cmd_vendor },
1013         { NULL, NULL }
1014 };
1015
1016
1017 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
1018 {
1019         struct hostapd_cli_cmd *cmd, *match = NULL;
1020         int count;
1021
1022         count = 0;
1023         cmd = hostapd_cli_commands;
1024         while (cmd->cmd) {
1025                 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
1026                         match = cmd;
1027                         if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1028                                 /* we have an exact match */
1029                                 count = 1;
1030                                 break;
1031                         }
1032                         count++;
1033                 }
1034                 cmd++;
1035         }
1036
1037         if (count > 1) {
1038                 printf("Ambiguous command '%s'; possible commands:", argv[0]);
1039                 cmd = hostapd_cli_commands;
1040                 while (cmd->cmd) {
1041                         if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
1042                             0) {
1043                                 printf(" %s", cmd->cmd);
1044                         }
1045                         cmd++;
1046                 }
1047                 printf("\n");
1048         } else if (count == 0) {
1049                 printf("Unknown command '%s'\n", argv[0]);
1050         } else {
1051                 match->handler(ctrl, argc - 1, &argv[1]);
1052         }
1053 }
1054
1055
1056 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
1057                                      int action_monitor)
1058 {
1059         int first = 1;
1060         if (ctrl_conn == NULL)
1061                 return;
1062         while (wpa_ctrl_pending(ctrl)) {
1063                 char buf[256];
1064                 size_t len = sizeof(buf) - 1;
1065                 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
1066                         buf[len] = '\0';
1067                         if (action_monitor)
1068                                 hostapd_cli_action_process(buf, len);
1069                         else {
1070                                 if (in_read && first)
1071                                         printf("\n");
1072                                 first = 0;
1073                                 printf("%s\n", buf);
1074                         }
1075                 } else {
1076                         printf("Could not read pending message.\n");
1077                         break;
1078                 }
1079         }
1080 }
1081
1082
1083 #define max_args 10
1084
1085 static int tokenize_cmd(char *cmd, char *argv[])
1086 {
1087         char *pos;
1088         int argc = 0;
1089
1090         pos = cmd;
1091         for (;;) {
1092                 while (*pos == ' ')
1093                         pos++;
1094                 if (*pos == '\0')
1095                         break;
1096                 argv[argc] = pos;
1097                 argc++;
1098                 if (argc == max_args)
1099                         break;
1100                 if (*pos == '"') {
1101                         char *pos2 = os_strrchr(pos, '"');
1102                         if (pos2)
1103                                 pos = pos2 + 1;
1104                 }
1105                 while (*pos != '\0' && *pos != ' ')
1106                         pos++;
1107                 if (*pos == ' ')
1108                         *pos++ = '\0';
1109         }
1110
1111         return argc;
1112 }
1113
1114
1115 static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
1116 {
1117         if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
1118                 printf("Connection to hostapd lost - trying to reconnect\n");
1119                 hostapd_cli_close_connection();
1120         }
1121         if (!ctrl_conn) {
1122                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1123                 if (ctrl_conn) {
1124                         printf("Connection to hostapd re-established\n");
1125                         if (wpa_ctrl_attach(ctrl_conn) == 0) {
1126                                 hostapd_cli_attached = 1;
1127                         } else {
1128                                 printf("Warning: Failed to attach to "
1129                                        "hostapd.\n");
1130                         }
1131                 }
1132         }
1133         if (ctrl_conn)
1134                 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
1135         eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1136 }
1137
1138
1139 static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
1140 {
1141         eloop_terminate();
1142 }
1143
1144
1145 static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
1146 {
1147         char *argv[max_args];
1148         int argc;
1149         argc = tokenize_cmd(cmd, argv);
1150         if (argc)
1151                 wpa_request(ctrl_conn, argc, argv);
1152 }
1153
1154
1155 static void hostapd_cli_edit_eof_cb(void *ctx)
1156 {
1157         eloop_terminate();
1158 }
1159
1160
1161 static void hostapd_cli_interactive(void)
1162 {
1163         printf("\nInteractive mode\n\n");
1164
1165         eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
1166         edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
1167                   NULL, NULL, NULL, NULL);
1168         eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1169
1170         eloop_run();
1171
1172         edit_deinit(NULL, NULL);
1173         eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
1174 }
1175
1176
1177 static void hostapd_cli_cleanup(void)
1178 {
1179         hostapd_cli_close_connection();
1180         if (pid_file)
1181                 os_daemonize_terminate(pid_file);
1182
1183         os_program_deinit();
1184 }
1185
1186
1187 static void hostapd_cli_action(struct wpa_ctrl *ctrl)
1188 {
1189         fd_set rfds;
1190         int fd, res;
1191         struct timeval tv;
1192         char buf[256];
1193         size_t len;
1194
1195         fd = wpa_ctrl_get_fd(ctrl);
1196
1197         while (!hostapd_cli_quit) {
1198                 FD_ZERO(&rfds);
1199                 FD_SET(fd, &rfds);
1200                 tv.tv_sec = ping_interval;
1201                 tv.tv_usec = 0;
1202                 res = select(fd + 1, &rfds, NULL, NULL, &tv);
1203                 if (res < 0 && errno != EINTR) {
1204                         perror("select");
1205                         break;
1206                 }
1207
1208                 if (FD_ISSET(fd, &rfds))
1209                         hostapd_cli_recv_pending(ctrl, 0, 1);
1210                 else {
1211                         len = sizeof(buf) - 1;
1212                         if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1213                                              hostapd_cli_action_process) < 0 ||
1214                             len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
1215                                 printf("hostapd did not reply to PING "
1216                                        "command - exiting\n");
1217                                 break;
1218                         }
1219                 }
1220         }
1221 }
1222
1223
1224 int main(int argc, char *argv[])
1225 {
1226         int warning_displayed = 0;
1227         int c;
1228         int daemonize = 0;
1229
1230         if (os_program_init())
1231                 return -1;
1232
1233         for (;;) {
1234                 c = getopt(argc, argv, "a:BhG:i:p:v");
1235                 if (c < 0)
1236                         break;
1237                 switch (c) {
1238                 case 'a':
1239                         action_file = optarg;
1240                         break;
1241                 case 'B':
1242                         daemonize = 1;
1243                         break;
1244                 case 'G':
1245                         ping_interval = atoi(optarg);
1246                         break;
1247                 case 'h':
1248                         usage();
1249                         return 0;
1250                 case 'v':
1251                         printf("%s\n", hostapd_cli_version);
1252                         return 0;
1253                 case 'i':
1254                         os_free(ctrl_ifname);
1255                         ctrl_ifname = os_strdup(optarg);
1256                         break;
1257                 case 'p':
1258                         ctrl_iface_dir = optarg;
1259                         break;
1260                 default:
1261                         usage();
1262                         return -1;
1263                 }
1264         }
1265
1266         interactive = (argc == optind) && (action_file == NULL);
1267
1268         if (interactive) {
1269                 printf("%s\n\n%s\n\n", hostapd_cli_version,
1270                        hostapd_cli_license);
1271         }
1272
1273         if (eloop_init())
1274                 return -1;
1275
1276         for (;;) {
1277                 if (ctrl_ifname == NULL) {
1278                         struct dirent *dent;
1279                         DIR *dir = opendir(ctrl_iface_dir);
1280                         if (dir) {
1281                                 while ((dent = readdir(dir))) {
1282                                         if (os_strcmp(dent->d_name, ".") == 0
1283                                             ||
1284                                             os_strcmp(dent->d_name, "..") == 0)
1285                                                 continue;
1286                                         printf("Selected interface '%s'\n",
1287                                                dent->d_name);
1288                                         ctrl_ifname = os_strdup(dent->d_name);
1289                                         break;
1290                                 }
1291                                 closedir(dir);
1292                         }
1293                 }
1294                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1295                 if (ctrl_conn) {
1296                         if (warning_displayed)
1297                                 printf("Connection established.\n");
1298                         break;
1299                 }
1300
1301                 if (!interactive) {
1302                         perror("Failed to connect to hostapd - "
1303                                "wpa_ctrl_open");
1304                         return -1;
1305                 }
1306
1307                 if (!warning_displayed) {
1308                         printf("Could not connect to hostapd - re-trying\n");
1309                         warning_displayed = 1;
1310                 }
1311                 os_sleep(1, 0);
1312                 continue;
1313         }
1314
1315         if (interactive || action_file) {
1316                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1317                         hostapd_cli_attached = 1;
1318                 } else {
1319                         printf("Warning: Failed to attach to hostapd.\n");
1320                         if (action_file)
1321                                 return -1;
1322                 }
1323         }
1324
1325         if (daemonize && os_daemonize(pid_file))
1326                 return -1;
1327
1328         if (interactive)
1329                 hostapd_cli_interactive();
1330         else if (action_file)
1331                 hostapd_cli_action(ctrl_conn);
1332         else
1333                 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1334
1335         os_free(ctrl_ifname);
1336         eloop_destroy();
1337         hostapd_cli_cleanup();
1338         return 0;
1339 }