bsd: Fix compilation error for NetBSD
[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 static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
850                                        int argc, char *argv[])
851 {
852         char cmd[256];
853         int res;
854         int i;
855         char *tmp;
856         int total;
857
858         if (argc < 2) {
859                 printf("Invalid chan_switch command: needs at least two "
860                        "arguments (count and freq)\n"
861                        "usage: <cs_count> <freq> [sec_channel_offset=] "
862                        "[center_freq1=] [center_freq2=] [bandwidth=] "
863                        "[blocktx] [ht|vht]\n");
864                 return -1;
865         }
866
867         res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
868                           argv[0], argv[1]);
869         if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
870                 printf("Too long CHAN_SWITCH command.\n");
871                 return -1;
872         }
873
874         total = res;
875         for (i = 2; i < argc; i++) {
876                 tmp = cmd + total;
877                 res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
878                 if (res < 0 || (size_t) res >= sizeof(cmd) - total - 1) {
879                         printf("Too long CHAN_SWITCH command.\n");
880                         return -1;
881                 }
882                 total += res;
883         }
884         return wpa_ctrl_command(ctrl, cmd);
885 }
886
887
888 struct hostapd_cli_cmd {
889         const char *cmd;
890         int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
891 };
892
893 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
894         { "ping", hostapd_cli_cmd_ping },
895         { "mib", hostapd_cli_cmd_mib },
896         { "relog", hostapd_cli_cmd_relog },
897         { "status", hostapd_cli_cmd_status },
898         { "sta", hostapd_cli_cmd_sta },
899         { "all_sta", hostapd_cli_cmd_all_sta },
900         { "new_sta", hostapd_cli_cmd_new_sta },
901         { "deauthenticate", hostapd_cli_cmd_deauthenticate },
902         { "disassociate", hostapd_cli_cmd_disassociate },
903 #ifdef CONFIG_IEEE80211W
904         { "sa_query", hostapd_cli_cmd_sa_query },
905 #endif /* CONFIG_IEEE80211W */
906 #ifdef CONFIG_WPS
907         { "wps_pin", hostapd_cli_cmd_wps_pin },
908         { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
909         { "wps_pbc", hostapd_cli_cmd_wps_pbc },
910         { "wps_cancel", hostapd_cli_cmd_wps_cancel },
911 #ifdef CONFIG_WPS_NFC
912         { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
913         { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
914         { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
915         { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
916 #endif /* CONFIG_WPS_NFC */
917         { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
918         { "wps_config", hostapd_cli_cmd_wps_config },
919         { "wps_get_status", hostapd_cli_cmd_wps_get_status },
920 #endif /* CONFIG_WPS */
921         { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
922         { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
923         { "get_config", hostapd_cli_cmd_get_config },
924         { "help", hostapd_cli_cmd_help },
925         { "interface", hostapd_cli_cmd_interface },
926         { "level", hostapd_cli_cmd_level },
927         { "license", hostapd_cli_cmd_license },
928         { "quit", hostapd_cli_cmd_quit },
929         { "set", hostapd_cli_cmd_set },
930         { "get", hostapd_cli_cmd_get },
931         { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
932         { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
933         { "chan_switch", hostapd_cli_cmd_chan_switch },
934         { NULL, NULL }
935 };
936
937
938 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
939 {
940         struct hostapd_cli_cmd *cmd, *match = NULL;
941         int count;
942
943         count = 0;
944         cmd = hostapd_cli_commands;
945         while (cmd->cmd) {
946                 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
947                         match = cmd;
948                         if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
949                                 /* we have an exact match */
950                                 count = 1;
951                                 break;
952                         }
953                         count++;
954                 }
955                 cmd++;
956         }
957
958         if (count > 1) {
959                 printf("Ambiguous command '%s'; possible commands:", argv[0]);
960                 cmd = hostapd_cli_commands;
961                 while (cmd->cmd) {
962                         if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
963                             0) {
964                                 printf(" %s", cmd->cmd);
965                         }
966                         cmd++;
967                 }
968                 printf("\n");
969         } else if (count == 0) {
970                 printf("Unknown command '%s'\n", argv[0]);
971         } else {
972                 match->handler(ctrl, argc - 1, &argv[1]);
973         }
974 }
975
976
977 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
978                                      int action_monitor)
979 {
980         int first = 1;
981         if (ctrl_conn == NULL)
982                 return;
983         while (wpa_ctrl_pending(ctrl)) {
984                 char buf[256];
985                 size_t len = sizeof(buf) - 1;
986                 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
987                         buf[len] = '\0';
988                         if (action_monitor)
989                                 hostapd_cli_action_process(buf, len);
990                         else {
991                                 if (in_read && first)
992                                         printf("\n");
993                                 first = 0;
994                                 printf("%s\n", buf);
995                         }
996                 } else {
997                         printf("Could not read pending message.\n");
998                         break;
999                 }
1000         }
1001 }
1002
1003
1004 #define max_args 10
1005
1006 static int tokenize_cmd(char *cmd, char *argv[])
1007 {
1008         char *pos;
1009         int argc = 0;
1010
1011         pos = cmd;
1012         for (;;) {
1013                 while (*pos == ' ')
1014                         pos++;
1015                 if (*pos == '\0')
1016                         break;
1017                 argv[argc] = pos;
1018                 argc++;
1019                 if (argc == max_args)
1020                         break;
1021                 if (*pos == '"') {
1022                         char *pos2 = os_strrchr(pos, '"');
1023                         if (pos2)
1024                                 pos = pos2 + 1;
1025                 }
1026                 while (*pos != '\0' && *pos != ' ')
1027                         pos++;
1028                 if (*pos == ' ')
1029                         *pos++ = '\0';
1030         }
1031
1032         return argc;
1033 }
1034
1035
1036 static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
1037 {
1038         if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
1039                 printf("Connection to hostapd lost - trying to reconnect\n");
1040                 hostapd_cli_close_connection();
1041         }
1042         if (!ctrl_conn) {
1043                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1044                 if (ctrl_conn) {
1045                         printf("Connection to hostapd re-established\n");
1046                         if (wpa_ctrl_attach(ctrl_conn) == 0) {
1047                                 hostapd_cli_attached = 1;
1048                         } else {
1049                                 printf("Warning: Failed to attach to "
1050                                        "hostapd.\n");
1051                         }
1052                 }
1053         }
1054         if (ctrl_conn)
1055                 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
1056         eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1057 }
1058
1059
1060 static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
1061 {
1062         eloop_terminate();
1063 }
1064
1065
1066 static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
1067 {
1068         char *argv[max_args];
1069         int argc;
1070         argc = tokenize_cmd(cmd, argv);
1071         if (argc)
1072                 wpa_request(ctrl_conn, argc, argv);
1073 }
1074
1075
1076 static void hostapd_cli_edit_eof_cb(void *ctx)
1077 {
1078         eloop_terminate();
1079 }
1080
1081
1082 static void hostapd_cli_interactive(void)
1083 {
1084         printf("\nInteractive mode\n\n");
1085
1086         eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
1087         edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
1088                   NULL, NULL, NULL, NULL);
1089         eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1090
1091         eloop_run();
1092
1093         edit_deinit(NULL, NULL);
1094         eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
1095 }
1096
1097
1098 static void hostapd_cli_cleanup(void)
1099 {
1100         hostapd_cli_close_connection();
1101         if (pid_file)
1102                 os_daemonize_terminate(pid_file);
1103
1104         os_program_deinit();
1105 }
1106
1107
1108 static void hostapd_cli_action(struct wpa_ctrl *ctrl)
1109 {
1110         fd_set rfds;
1111         int fd, res;
1112         struct timeval tv;
1113         char buf[256];
1114         size_t len;
1115
1116         fd = wpa_ctrl_get_fd(ctrl);
1117
1118         while (!hostapd_cli_quit) {
1119                 FD_ZERO(&rfds);
1120                 FD_SET(fd, &rfds);
1121                 tv.tv_sec = ping_interval;
1122                 tv.tv_usec = 0;
1123                 res = select(fd + 1, &rfds, NULL, NULL, &tv);
1124                 if (res < 0 && errno != EINTR) {
1125                         perror("select");
1126                         break;
1127                 }
1128
1129                 if (FD_ISSET(fd, &rfds))
1130                         hostapd_cli_recv_pending(ctrl, 0, 1);
1131                 else {
1132                         len = sizeof(buf) - 1;
1133                         if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1134                                              hostapd_cli_action_process) < 0 ||
1135                             len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
1136                                 printf("hostapd did not reply to PING "
1137                                        "command - exiting\n");
1138                                 break;
1139                         }
1140                 }
1141         }
1142 }
1143
1144
1145 int main(int argc, char *argv[])
1146 {
1147         int warning_displayed = 0;
1148         int c;
1149         int daemonize = 0;
1150
1151         if (os_program_init())
1152                 return -1;
1153
1154         for (;;) {
1155                 c = getopt(argc, argv, "a:BhG:i:p:v");
1156                 if (c < 0)
1157                         break;
1158                 switch (c) {
1159                 case 'a':
1160                         action_file = optarg;
1161                         break;
1162                 case 'B':
1163                         daemonize = 1;
1164                         break;
1165                 case 'G':
1166                         ping_interval = atoi(optarg);
1167                         break;
1168                 case 'h':
1169                         usage();
1170                         return 0;
1171                 case 'v':
1172                         printf("%s\n", hostapd_cli_version);
1173                         return 0;
1174                 case 'i':
1175                         os_free(ctrl_ifname);
1176                         ctrl_ifname = os_strdup(optarg);
1177                         break;
1178                 case 'p':
1179                         ctrl_iface_dir = optarg;
1180                         break;
1181                 default:
1182                         usage();
1183                         return -1;
1184                 }
1185         }
1186
1187         interactive = (argc == optind) && (action_file == NULL);
1188
1189         if (interactive) {
1190                 printf("%s\n\n%s\n\n", hostapd_cli_version,
1191                        hostapd_cli_license);
1192         }
1193
1194         if (eloop_init())
1195                 return -1;
1196
1197         for (;;) {
1198                 if (ctrl_ifname == NULL) {
1199                         struct dirent *dent;
1200                         DIR *dir = opendir(ctrl_iface_dir);
1201                         if (dir) {
1202                                 while ((dent = readdir(dir))) {
1203                                         if (os_strcmp(dent->d_name, ".") == 0
1204                                             ||
1205                                             os_strcmp(dent->d_name, "..") == 0)
1206                                                 continue;
1207                                         printf("Selected interface '%s'\n",
1208                                                dent->d_name);
1209                                         ctrl_ifname = os_strdup(dent->d_name);
1210                                         break;
1211                                 }
1212                                 closedir(dir);
1213                         }
1214                 }
1215                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1216                 if (ctrl_conn) {
1217                         if (warning_displayed)
1218                                 printf("Connection established.\n");
1219                         break;
1220                 }
1221
1222                 if (!interactive) {
1223                         perror("Failed to connect to hostapd - "
1224                                "wpa_ctrl_open");
1225                         return -1;
1226                 }
1227
1228                 if (!warning_displayed) {
1229                         printf("Could not connect to hostapd - re-trying\n");
1230                         warning_displayed = 1;
1231                 }
1232                 os_sleep(1, 0);
1233                 continue;
1234         }
1235
1236         if (interactive || action_file) {
1237                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1238                         hostapd_cli_attached = 1;
1239                 } else {
1240                         printf("Warning: Failed to attach to hostapd.\n");
1241                         if (action_file)
1242                                 return -1;
1243                 }
1244         }
1245
1246         if (daemonize && os_daemonize(pid_file))
1247                 return -1;
1248
1249         if (interactive)
1250                 hostapd_cli_interactive();
1251         else if (action_file)
1252                 hostapd_cli_action(ctrl_conn);
1253         else
1254                 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1255
1256         os_free(ctrl_ifname);
1257         eloop_destroy();
1258         hostapd_cli_cleanup();
1259         return 0;
1260 }