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