OSDN Git Service

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