Add test commands for sending deauth/disassoc without dropping state
[mech_eap.git] / hostapd / hostapd_cli.c
1 /*
2  * hostapd - command line interface for hostapd daemon
3  * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include "includes.h"
16 #include <dirent.h>
17
18 #include "common/wpa_ctrl.h"
19 #include "common.h"
20 #include "common/version.h"
21
22
23 static const char *hostapd_cli_version =
24 "hostapd_cli v" VERSION_STR "\n"
25 "Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi> and contributors";
26
27
28 static const char *hostapd_cli_license =
29 "This program is free software. You can distribute it and/or modify it\n"
30 "under the terms of the GNU General Public License version 2.\n"
31 "\n"
32 "Alternatively, this software may be distributed under the terms of the\n"
33 "BSD license. See README and COPYING for more details.\n";
34
35 static const char *hostapd_cli_full_license =
36 "This program is free software; you can redistribute it and/or modify\n"
37 "it under the terms of the GNU General Public License version 2 as\n"
38 "published by the Free Software Foundation.\n"
39 "\n"
40 "This program is distributed in the hope that it will be useful,\n"
41 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
42 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
43 "GNU General Public License for more details.\n"
44 "\n"
45 "You should have received a copy of the GNU General Public License\n"
46 "along with this program; if not, write to the Free Software\n"
47 "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n"
48 "\n"
49 "Alternatively, this software may be distributed under the terms of the\n"
50 "BSD license.\n"
51 "\n"
52 "Redistribution and use in source and binary forms, with or without\n"
53 "modification, are permitted provided that the following conditions are\n"
54 "met:\n"
55 "\n"
56 "1. Redistributions of source code must retain the above copyright\n"
57 "   notice, this list of conditions and the following disclaimer.\n"
58 "\n"
59 "2. Redistributions in binary form must reproduce the above copyright\n"
60 "   notice, this list of conditions and the following disclaimer in the\n"
61 "   documentation and/or other materials provided with the distribution.\n"
62 "\n"
63 "3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
64 "   names of its contributors may be used to endorse or promote products\n"
65 "   derived from this software without specific prior written permission.\n"
66 "\n"
67 "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
68 "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
69 "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
70 "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
71 "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
72 "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
73 "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
74 "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
75 "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
76 "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
77 "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
78 "\n";
79
80 static const char *commands_help =
81 "Commands:\n"
82 "   mib                  get MIB variables (dot1x, dot11, radius)\n"
83 "   sta <addr>           get MIB variables for one station\n"
84 "   all_sta              get MIB variables for all stations\n"
85 "   new_sta <addr>       add a new station\n"
86 #ifdef CONFIG_IEEE80211W
87 "   sa_query <addr>      send SA Query to a station\n"
88 #endif /* CONFIG_IEEE80211W */
89 #ifdef CONFIG_WPS
90 "   wps_pin <uuid> <pin> [timeout]  add WPS Enrollee PIN (Device Password)\n"
91 "   wps_pbc              indicate button pushed to initiate PBC\n"
92 #ifdef CONFIG_WPS_OOB
93 "   wps_oob <type> <path> <method>  use WPS with out-of-band (UFD)\n"
94 #endif /* CONFIG_WPS_OOB */
95 #endif /* CONFIG_WPS */
96 "   help                 show this usage help\n"
97 "   interface [ifname]   show interfaces/select interface\n"
98 "   level <debug level>  change debug level\n"
99 "   license              show full hostapd_cli license\n"
100 "   quit                 exit hostapd_cli\n";
101
102 static struct wpa_ctrl *ctrl_conn;
103 static int hostapd_cli_quit = 0;
104 static int hostapd_cli_attached = 0;
105 static const char *ctrl_iface_dir = "/var/run/hostapd";
106 static char *ctrl_ifname = NULL;
107 static int ping_interval = 5;
108
109
110 static void usage(void)
111 {
112         fprintf(stderr, "%s\n", hostapd_cli_version);
113         fprintf(stderr, 
114                 "\n"    
115                 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hv] "
116                 "[-G<ping interval>] \\\n"
117                 "        [command..]\n"
118                 "\n"
119                 "Options:\n"
120                 "   -h           help (show this usage text)\n"
121                 "   -v           shown version information\n"
122                 "   -p<path>     path to find control sockets (default: "
123                 "/var/run/hostapd)\n"
124                 "   -i<ifname>   Interface to listen on (default: first "
125                 "interface found in the\n"
126                 "                socket path)\n\n"
127                 "%s",
128                 commands_help);
129 }
130
131
132 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
133 {
134         char *cfile;
135         int flen;
136
137         if (ifname == NULL)
138                 return NULL;
139
140         flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
141         cfile = malloc(flen);
142         if (cfile == NULL)
143                 return NULL;
144         snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
145
146         ctrl_conn = wpa_ctrl_open(cfile);
147         free(cfile);
148         return ctrl_conn;
149 }
150
151
152 static void hostapd_cli_close_connection(void)
153 {
154         if (ctrl_conn == NULL)
155                 return;
156
157         if (hostapd_cli_attached) {
158                 wpa_ctrl_detach(ctrl_conn);
159                 hostapd_cli_attached = 0;
160         }
161         wpa_ctrl_close(ctrl_conn);
162         ctrl_conn = NULL;
163 }
164
165
166 static void hostapd_cli_msg_cb(char *msg, size_t len)
167 {
168         printf("%s\n", msg);
169 }
170
171
172 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
173 {
174         char buf[4096];
175         size_t len;
176         int ret;
177
178         if (ctrl_conn == NULL) {
179                 printf("Not connected to hostapd - command dropped.\n");
180                 return -1;
181         }
182         len = sizeof(buf) - 1;
183         ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
184                                hostapd_cli_msg_cb);
185         if (ret == -2) {
186                 printf("'%s' command timed out.\n", cmd);
187                 return -2;
188         } else if (ret < 0) {
189                 printf("'%s' command failed.\n", cmd);
190                 return -1;
191         }
192         if (print) {
193                 buf[len] = '\0';
194                 printf("%s", buf);
195         }
196         return 0;
197 }
198
199
200 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
201 {
202         return _wpa_ctrl_command(ctrl, cmd, 1);
203 }
204
205
206 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
207 {
208         return wpa_ctrl_command(ctrl, "PING");
209 }
210
211
212 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
213 {
214         return wpa_ctrl_command(ctrl, "MIB");
215 }
216
217
218 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
219 {
220         char buf[64];
221         if (argc != 1) {
222                 printf("Invalid 'sta' command - exactly one argument, STA "
223                        "address, is required.\n");
224                 return -1;
225         }
226         snprintf(buf, sizeof(buf), "STA %s", argv[0]);
227         return wpa_ctrl_command(ctrl, buf);
228 }
229
230
231 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
232                                    char *argv[])
233 {
234         char buf[64];
235         if (argc != 1) {
236                 printf("Invalid 'new_sta' command - exactly one argument, STA "
237                        "address, is required.\n");
238                 return -1;
239         }
240         snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
241         return wpa_ctrl_command(ctrl, buf);
242 }
243
244
245 static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
246                                           char *argv[])
247 {
248         char buf[64];
249         if (argc < 1) {
250                 printf("Invalid 'deauthenticate' command - exactly one "
251                        "argument, STA address, is required.\n");
252                 return -1;
253         }
254         if (argc > 1)
255                 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
256                             argv[0], argv[1]);
257         else
258                 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
259         return wpa_ctrl_command(ctrl, buf);
260 }
261
262
263 static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
264                                         char *argv[])
265 {
266         char buf[64];
267         if (argc < 1) {
268                 printf("Invalid 'disassociate' command - exactly one "
269                        "argument, STA address, is required.\n");
270                 return -1;
271         }
272         if (argc > 1)
273                 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
274                             argv[0], argv[1]);
275         else
276                 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
277         return wpa_ctrl_command(ctrl, buf);
278 }
279
280
281 #ifdef CONFIG_IEEE80211W
282 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
283                                     char *argv[])
284 {
285         char buf[64];
286         if (argc != 1) {
287                 printf("Invalid 'sa_query' command - exactly one argument, "
288                        "STA address, is required.\n");
289                 return -1;
290         }
291         snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
292         return wpa_ctrl_command(ctrl, buf);
293 }
294 #endif /* CONFIG_IEEE80211W */
295
296
297 #ifdef CONFIG_WPS
298 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
299                                    char *argv[])
300 {
301         char buf[64];
302         if (argc < 2) {
303                 printf("Invalid 'wps_pin' command - at least two arguments, "
304                        "UUID and PIN, are required.\n");
305                 return -1;
306         }
307         if (argc > 2)
308                 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
309                          argv[0], argv[1], argv[2]);
310         else
311                 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
312         return wpa_ctrl_command(ctrl, buf);
313 }
314
315
316 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
317                                    char *argv[])
318 {
319         return wpa_ctrl_command(ctrl, "WPS_PBC");
320 }
321
322
323 #ifdef CONFIG_WPS_OOB
324 static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
325                                    char *argv[])
326 {
327         char cmd[256];
328         int res;
329
330         if (argc != 3 && argc != 4) {
331                 printf("Invalid WPS_OOB command: need three or four "
332                        "arguments:\n"
333                        "- DEV_TYPE: use 'ufd' or 'nfc'\n"
334                        "- PATH: path of OOB device like '/mnt'\n"
335                        "- METHOD: OOB method 'pin-e' or 'pin-r', "
336                        "'cred'\n"
337                        "- DEV_NAME: (only for NFC) device name like "
338                        "'pn531'\n");
339                 return -1;
340         }
341
342         if (argc == 3)
343                 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
344                                   argv[0], argv[1], argv[2]);
345         else
346                 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
347                                   argv[0], argv[1], argv[2], argv[3]);
348         if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
349                 printf("Too long WPS_OOB command.\n");
350                 return -1;
351         }
352         return wpa_ctrl_command(ctrl, cmd);
353 }
354 #endif /* CONFIG_WPS_OOB */
355 #endif /* CONFIG_WPS */
356
357
358 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
359                                 char *addr, size_t addr_len)
360 {
361         char buf[4096], *pos;
362         size_t len;
363         int ret;
364
365         if (ctrl_conn == NULL) {
366                 printf("Not connected to hostapd - command dropped.\n");
367                 return -1;
368         }
369         len = sizeof(buf) - 1;
370         ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
371                                hostapd_cli_msg_cb);
372         if (ret == -2) {
373                 printf("'%s' command timed out.\n", cmd);
374                 return -2;
375         } else if (ret < 0) {
376                 printf("'%s' command failed.\n", cmd);
377                 return -1;
378         }
379
380         buf[len] = '\0';
381         if (memcmp(buf, "FAIL", 4) == 0)
382                 return -1;
383         printf("%s", buf);
384
385         pos = buf;
386         while (*pos != '\0' && *pos != '\n')
387                 pos++;
388         *pos = '\0';
389         os_strlcpy(addr, buf, addr_len);
390         return 0;
391 }
392
393
394 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
395                                    char *argv[])
396 {
397         char addr[32], cmd[64];
398
399         if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
400                 return 0;
401         do {
402                 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
403         } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
404
405         return -1;
406 }
407
408
409 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
410 {
411         printf("%s", commands_help);
412         return 0;
413 }
414
415
416 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
417                                    char *argv[])
418 {
419         printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
420         return 0;
421 }
422
423
424 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
425 {
426         hostapd_cli_quit = 1;
427         return 0;
428 }
429
430
431 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
432 {
433         char cmd[256];
434         if (argc != 1) {
435                 printf("Invalid LEVEL command: needs one argument (debug "
436                        "level)\n");
437                 return 0;
438         }
439         snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
440         return wpa_ctrl_command(ctrl, cmd);
441 }
442
443
444 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
445 {
446         struct dirent *dent;
447         DIR *dir;
448
449         dir = opendir(ctrl_iface_dir);
450         if (dir == NULL) {
451                 printf("Control interface directory '%s' could not be "
452                        "openned.\n", ctrl_iface_dir);
453                 return;
454         }
455
456         printf("Available interfaces:\n");
457         while ((dent = readdir(dir))) {
458                 if (strcmp(dent->d_name, ".") == 0 ||
459                     strcmp(dent->d_name, "..") == 0)
460                         continue;
461                 printf("%s\n", dent->d_name);
462         }
463         closedir(dir);
464 }
465
466
467 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
468                                      char *argv[])
469 {
470         if (argc < 1) {
471                 hostapd_cli_list_interfaces(ctrl);
472                 return 0;
473         }
474
475         hostapd_cli_close_connection();
476         free(ctrl_ifname);
477         ctrl_ifname = strdup(argv[0]);
478
479         if (hostapd_cli_open_connection(ctrl_ifname)) {
480                 printf("Connected to interface '%s.\n", ctrl_ifname);
481                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
482                         hostapd_cli_attached = 1;
483                 } else {
484                         printf("Warning: Failed to attach to "
485                                "hostapd.\n");
486                 }
487         } else {
488                 printf("Could not connect to interface '%s' - re-trying\n",
489                         ctrl_ifname);
490         }
491         return 0;
492 }
493
494
495 struct hostapd_cli_cmd {
496         const char *cmd;
497         int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
498 };
499
500 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
501         { "ping", hostapd_cli_cmd_ping },
502         { "mib", hostapd_cli_cmd_mib },
503         { "sta", hostapd_cli_cmd_sta },
504         { "all_sta", hostapd_cli_cmd_all_sta },
505         { "new_sta", hostapd_cli_cmd_new_sta },
506         { "deauthenticate", hostapd_cli_cmd_deauthenticate },
507         { "disassociate", hostapd_cli_cmd_disassociate },
508 #ifdef CONFIG_IEEE80211W
509         { "sa_query", hostapd_cli_cmd_sa_query },
510 #endif /* CONFIG_IEEE80211W */
511 #ifdef CONFIG_WPS
512         { "wps_pin", hostapd_cli_cmd_wps_pin },
513         { "wps_pbc", hostapd_cli_cmd_wps_pbc },
514 #ifdef CONFIG_WPS_OOB
515         { "wps_oob", hostapd_cli_cmd_wps_oob },
516 #endif /* CONFIG_WPS_OOB */
517 #endif /* CONFIG_WPS */
518         { "help", hostapd_cli_cmd_help },
519         { "interface", hostapd_cli_cmd_interface },
520         { "level", hostapd_cli_cmd_level },
521         { "license", hostapd_cli_cmd_license },
522         { "quit", hostapd_cli_cmd_quit },
523         { NULL, NULL }
524 };
525
526
527 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
528 {
529         struct hostapd_cli_cmd *cmd, *match = NULL;
530         int count;
531
532         count = 0;
533         cmd = hostapd_cli_commands;
534         while (cmd->cmd) {
535                 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
536                         match = cmd;
537                         count++;
538                 }
539                 cmd++;
540         }
541
542         if (count > 1) {
543                 printf("Ambiguous command '%s'; possible commands:", argv[0]);
544                 cmd = hostapd_cli_commands;
545                 while (cmd->cmd) {
546                         if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
547                             0) {
548                                 printf(" %s", cmd->cmd);
549                         }
550                         cmd++;
551                 }
552                 printf("\n");
553         } else if (count == 0) {
554                 printf("Unknown command '%s'\n", argv[0]);
555         } else {
556                 match->handler(ctrl, argc - 1, &argv[1]);
557         }
558 }
559
560
561 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read)
562 {
563         int first = 1;
564         if (ctrl_conn == NULL)
565                 return;
566         while (wpa_ctrl_pending(ctrl)) {
567                 char buf[256];
568                 size_t len = sizeof(buf) - 1;
569                 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
570                         buf[len] = '\0';
571                         if (in_read && first)
572                                 printf("\n");
573                         first = 0;
574                         printf("%s\n", buf);
575                 } else {
576                         printf("Could not read pending message.\n");
577                         break;
578                 }
579         }
580 }
581
582
583 static void hostapd_cli_interactive(void)
584 {
585         const int max_args = 10;
586         char cmd[256], *res, *argv[max_args], *pos;
587         int argc;
588
589         printf("\nInteractive mode\n\n");
590
591         do {
592                 hostapd_cli_recv_pending(ctrl_conn, 0);
593                 printf("> ");
594                 alarm(ping_interval);
595                 res = fgets(cmd, sizeof(cmd), stdin);
596                 alarm(0);
597                 if (res == NULL)
598                         break;
599                 pos = cmd;
600                 while (*pos != '\0') {
601                         if (*pos == '\n') {
602                                 *pos = '\0';
603                                 break;
604                         }
605                         pos++;
606                 }
607                 argc = 0;
608                 pos = cmd;
609                 for (;;) {
610                         while (*pos == ' ')
611                                 pos++;
612                         if (*pos == '\0')
613                                 break;
614                         argv[argc] = pos;
615                         argc++;
616                         if (argc == max_args)
617                                 break;
618                         while (*pos != '\0' && *pos != ' ')
619                                 pos++;
620                         if (*pos == ' ')
621                                 *pos++ = '\0';
622                 }
623                 if (argc)
624                         wpa_request(ctrl_conn, argc, argv);
625         } while (!hostapd_cli_quit);
626 }
627
628
629 static void hostapd_cli_terminate(int sig)
630 {
631         hostapd_cli_close_connection();
632         exit(0);
633 }
634
635
636 static void hostapd_cli_alarm(int sig)
637 {
638         if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
639                 printf("Connection to hostapd lost - trying to reconnect\n");
640                 hostapd_cli_close_connection();
641         }
642         if (!ctrl_conn) {
643                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
644                 if (ctrl_conn) {
645                         printf("Connection to hostapd re-established\n");
646                         if (wpa_ctrl_attach(ctrl_conn) == 0) {
647                                 hostapd_cli_attached = 1;
648                         } else {
649                                 printf("Warning: Failed to attach to "
650                                        "hostapd.\n");
651                         }
652                 }
653         }
654         if (ctrl_conn)
655                 hostapd_cli_recv_pending(ctrl_conn, 1);
656         alarm(ping_interval);
657 }
658
659
660 int main(int argc, char *argv[])
661 {
662         int interactive;
663         int warning_displayed = 0;
664         int c;
665
666         if (os_program_init())
667                 return -1;
668
669         for (;;) {
670                 c = getopt(argc, argv, "hG:i:p:v");
671                 if (c < 0)
672                         break;
673                 switch (c) {
674                 case 'G':
675                         ping_interval = atoi(optarg);
676                         break;
677                 case 'h':
678                         usage();
679                         return 0;
680                 case 'v':
681                         printf("%s\n", hostapd_cli_version);
682                         return 0;
683                 case 'i':
684                         free(ctrl_ifname);
685                         ctrl_ifname = strdup(optarg);
686                         break;
687                 case 'p':
688                         ctrl_iface_dir = optarg;
689                         break;
690                 default:
691                         usage();
692                         return -1;
693                 }
694         }
695
696         interactive = argc == optind;
697
698         if (interactive) {
699                 printf("%s\n\n%s\n\n", hostapd_cli_version,
700                        hostapd_cli_license);
701         }
702
703         for (;;) {
704                 if (ctrl_ifname == NULL) {
705                         struct dirent *dent;
706                         DIR *dir = opendir(ctrl_iface_dir);
707                         if (dir) {
708                                 while ((dent = readdir(dir))) {
709                                         if (strcmp(dent->d_name, ".") == 0 ||
710                                             strcmp(dent->d_name, "..") == 0)
711                                                 continue;
712                                         printf("Selected interface '%s'\n",
713                                                dent->d_name);
714                                         ctrl_ifname = strdup(dent->d_name);
715                                         break;
716                                 }
717                                 closedir(dir);
718                         }
719                 }
720                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
721                 if (ctrl_conn) {
722                         if (warning_displayed)
723                                 printf("Connection established.\n");
724                         break;
725                 }
726
727                 if (!interactive) {
728                         perror("Failed to connect to hostapd - "
729                                "wpa_ctrl_open");
730                         return -1;
731                 }
732
733                 if (!warning_displayed) {
734                         printf("Could not connect to hostapd - re-trying\n");
735                         warning_displayed = 1;
736                 }
737                 sleep(1);
738                 continue;
739         }
740
741         signal(SIGINT, hostapd_cli_terminate);
742         signal(SIGTERM, hostapd_cli_terminate);
743         signal(SIGALRM, hostapd_cli_alarm);
744
745         if (interactive) {
746                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
747                         hostapd_cli_attached = 1;
748                 } else {
749                         printf("Warning: Failed to attach to hostapd.\n");
750                 }
751                 hostapd_cli_interactive();
752         } else
753                 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
754
755         free(ctrl_ifname);
756         hostapd_cli_close_connection();
757         os_program_deinit();
758         return 0;
759 }