Merge wpa_supplicant and hostapd driver wrapper implementations
[wpasupplicant] / hostapd / hostapd_cli.c
1 /*
2  * hostapd - command line interface for hostapd daemon
3  * Copyright (c) 2004-2009, 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 "wpa_ctrl.h"
19 #include "common.h"
20 #include "version.h"
21
22
23 static const char *hostapd_cli_version =
24 "hostapd_cli v" VERSION_STR "\n"
25 "Copyright (c) 2004-2009, 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> 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 #ifdef CONFIG_IEEE80211W
246 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
247                                     char *argv[])
248 {
249         char buf[64];
250         if (argc != 1) {
251                 printf("Invalid 'sa_query' command - exactly one argument, "
252                        "STA address, is required.\n");
253                 return -1;
254         }
255         snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
256         return wpa_ctrl_command(ctrl, buf);
257 }
258 #endif /* CONFIG_IEEE80211W */
259
260
261 #ifdef CONFIG_WPS
262 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
263                                    char *argv[])
264 {
265         char buf[64];
266         if (argc != 2) {
267                 printf("Invalid 'wps_pin' command - exactly two arguments, "
268                        "UUID and PIN, are required.\n");
269                 return -1;
270         }
271         snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
272         return wpa_ctrl_command(ctrl, buf);
273 }
274
275
276 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
277                                    char *argv[])
278 {
279         return wpa_ctrl_command(ctrl, "WPS_PBC");
280 }
281
282
283 #ifdef CONFIG_WPS_OOB
284 static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
285                                    char *argv[])
286 {
287         char cmd[256];
288         int res;
289
290         if (argc != 3 && argc != 4) {
291                 printf("Invalid WPS_OOB command: need three or four "
292                        "arguments:\n"
293                        "- DEV_TYPE: use 'ufd' or 'nfc'\n"
294                        "- PATH: path of OOB device like '/mnt'\n"
295                        "- METHOD: OOB method 'pin-e' or 'pin-r', "
296                        "'cred'\n"
297                        "- DEV_NAME: (only for NFC) device name like "
298                        "'pn531'\n");
299                 return -1;
300         }
301
302         if (argc == 3)
303                 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
304                                   argv[0], argv[1], argv[2]);
305         else
306                 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
307                                   argv[0], argv[1], argv[2], argv[3]);
308         if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
309                 printf("Too long WPS_OOB command.\n");
310                 return -1;
311         }
312         return wpa_ctrl_command(ctrl, cmd);
313 }
314 #endif /* CONFIG_WPS_OOB */
315 #endif /* CONFIG_WPS */
316
317
318 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
319                                 char *addr, size_t addr_len)
320 {
321         char buf[4096], *pos;
322         size_t len;
323         int ret;
324
325         if (ctrl_conn == NULL) {
326                 printf("Not connected to hostapd - command dropped.\n");
327                 return -1;
328         }
329         len = sizeof(buf) - 1;
330         ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
331                                hostapd_cli_msg_cb);
332         if (ret == -2) {
333                 printf("'%s' command timed out.\n", cmd);
334                 return -2;
335         } else if (ret < 0) {
336                 printf("'%s' command failed.\n", cmd);
337                 return -1;
338         }
339
340         buf[len] = '\0';
341         if (memcmp(buf, "FAIL", 4) == 0)
342                 return -1;
343         printf("%s", buf);
344
345         pos = buf;
346         while (*pos != '\0' && *pos != '\n')
347                 pos++;
348         *pos = '\0';
349         os_strlcpy(addr, buf, addr_len);
350         return 0;
351 }
352
353
354 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
355                                    char *argv[])
356 {
357         char addr[32], cmd[64];
358
359         if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
360                 return 0;
361         do {
362                 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
363         } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
364
365         return -1;
366 }
367
368
369 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
370 {
371         printf("%s", commands_help);
372         return 0;
373 }
374
375
376 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
377                                    char *argv[])
378 {
379         printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
380         return 0;
381 }
382
383
384 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
385 {
386         hostapd_cli_quit = 1;
387         return 0;
388 }
389
390
391 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
392 {
393         char cmd[256];
394         if (argc != 1) {
395                 printf("Invalid LEVEL command: needs one argument (debug "
396                        "level)\n");
397                 return 0;
398         }
399         snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
400         return wpa_ctrl_command(ctrl, cmd);
401 }
402
403
404 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
405 {
406         struct dirent *dent;
407         DIR *dir;
408
409         dir = opendir(ctrl_iface_dir);
410         if (dir == NULL) {
411                 printf("Control interface directory '%s' could not be "
412                        "openned.\n", ctrl_iface_dir);
413                 return;
414         }
415
416         printf("Available interfaces:\n");
417         while ((dent = readdir(dir))) {
418                 if (strcmp(dent->d_name, ".") == 0 ||
419                     strcmp(dent->d_name, "..") == 0)
420                         continue;
421                 printf("%s\n", dent->d_name);
422         }
423         closedir(dir);
424 }
425
426
427 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
428                                      char *argv[])
429 {
430         if (argc < 1) {
431                 hostapd_cli_list_interfaces(ctrl);
432                 return 0;
433         }
434
435         hostapd_cli_close_connection();
436         free(ctrl_ifname);
437         ctrl_ifname = strdup(argv[0]);
438
439         if (hostapd_cli_open_connection(ctrl_ifname)) {
440                 printf("Connected to interface '%s.\n", ctrl_ifname);
441                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
442                         hostapd_cli_attached = 1;
443                 } else {
444                         printf("Warning: Failed to attach to "
445                                "hostapd.\n");
446                 }
447         } else {
448                 printf("Could not connect to interface '%s' - re-trying\n",
449                         ctrl_ifname);
450         }
451         return 0;
452 }
453
454
455 struct hostapd_cli_cmd {
456         const char *cmd;
457         int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
458 };
459
460 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
461         { "ping", hostapd_cli_cmd_ping },
462         { "mib", hostapd_cli_cmd_mib },
463         { "sta", hostapd_cli_cmd_sta },
464         { "all_sta", hostapd_cli_cmd_all_sta },
465         { "new_sta", hostapd_cli_cmd_new_sta },
466 #ifdef CONFIG_IEEE80211W
467         { "sa_query", hostapd_cli_cmd_sa_query },
468 #endif /* CONFIG_IEEE80211W */
469 #ifdef CONFIG_WPS
470         { "wps_pin", hostapd_cli_cmd_wps_pin },
471         { "wps_pbc", hostapd_cli_cmd_wps_pbc },
472 #ifdef CONFIG_WPS_OOB
473         { "wps_oob", hostapd_cli_cmd_wps_oob },
474 #endif /* CONFIG_WPS_OOB */
475 #endif /* CONFIG_WPS */
476         { "help", hostapd_cli_cmd_help },
477         { "interface", hostapd_cli_cmd_interface },
478         { "level", hostapd_cli_cmd_level },
479         { "license", hostapd_cli_cmd_license },
480         { "quit", hostapd_cli_cmd_quit },
481         { NULL, NULL }
482 };
483
484
485 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
486 {
487         struct hostapd_cli_cmd *cmd, *match = NULL;
488         int count;
489
490         count = 0;
491         cmd = hostapd_cli_commands;
492         while (cmd->cmd) {
493                 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
494                         match = cmd;
495                         count++;
496                 }
497                 cmd++;
498         }
499
500         if (count > 1) {
501                 printf("Ambiguous command '%s'; possible commands:", argv[0]);
502                 cmd = hostapd_cli_commands;
503                 while (cmd->cmd) {
504                         if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
505                             0) {
506                                 printf(" %s", cmd->cmd);
507                         }
508                         cmd++;
509                 }
510                 printf("\n");
511         } else if (count == 0) {
512                 printf("Unknown command '%s'\n", argv[0]);
513         } else {
514                 match->handler(ctrl, argc - 1, &argv[1]);
515         }
516 }
517
518
519 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read)
520 {
521         int first = 1;
522         if (ctrl_conn == NULL)
523                 return;
524         while (wpa_ctrl_pending(ctrl)) {
525                 char buf[256];
526                 size_t len = sizeof(buf) - 1;
527                 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
528                         buf[len] = '\0';
529                         if (in_read && first)
530                                 printf("\n");
531                         first = 0;
532                         printf("%s\n", buf);
533                 } else {
534                         printf("Could not read pending message.\n");
535                         break;
536                 }
537         }
538 }
539
540
541 static void hostapd_cli_interactive(void)
542 {
543         const int max_args = 10;
544         char cmd[256], *res, *argv[max_args], *pos;
545         int argc;
546
547         printf("\nInteractive mode\n\n");
548
549         do {
550                 hostapd_cli_recv_pending(ctrl_conn, 0);
551                 printf("> ");
552                 alarm(ping_interval);
553                 res = fgets(cmd, sizeof(cmd), stdin);
554                 alarm(0);
555                 if (res == NULL)
556                         break;
557                 pos = cmd;
558                 while (*pos != '\0') {
559                         if (*pos == '\n') {
560                                 *pos = '\0';
561                                 break;
562                         }
563                         pos++;
564                 }
565                 argc = 0;
566                 pos = cmd;
567                 for (;;) {
568                         while (*pos == ' ')
569                                 pos++;
570                         if (*pos == '\0')
571                                 break;
572                         argv[argc] = pos;
573                         argc++;
574                         if (argc == max_args)
575                                 break;
576                         while (*pos != '\0' && *pos != ' ')
577                                 pos++;
578                         if (*pos == ' ')
579                                 *pos++ = '\0';
580                 }
581                 if (argc)
582                         wpa_request(ctrl_conn, argc, argv);
583         } while (!hostapd_cli_quit);
584 }
585
586
587 static void hostapd_cli_terminate(int sig)
588 {
589         hostapd_cli_close_connection();
590         exit(0);
591 }
592
593
594 static void hostapd_cli_alarm(int sig)
595 {
596         if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
597                 printf("Connection to hostapd lost - trying to reconnect\n");
598                 hostapd_cli_close_connection();
599         }
600         if (!ctrl_conn) {
601                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
602                 if (ctrl_conn) {
603                         printf("Connection to hostapd re-established\n");
604                         if (wpa_ctrl_attach(ctrl_conn) == 0) {
605                                 hostapd_cli_attached = 1;
606                         } else {
607                                 printf("Warning: Failed to attach to "
608                                        "hostapd.\n");
609                         }
610                 }
611         }
612         if (ctrl_conn)
613                 hostapd_cli_recv_pending(ctrl_conn, 1);
614         alarm(ping_interval);
615 }
616
617
618 int main(int argc, char *argv[])
619 {
620         int interactive;
621         int warning_displayed = 0;
622         int c;
623
624         for (;;) {
625                 c = getopt(argc, argv, "hG:i:p:v");
626                 if (c < 0)
627                         break;
628                 switch (c) {
629                 case 'G':
630                         ping_interval = atoi(optarg);
631                         break;
632                 case 'h':
633                         usage();
634                         return 0;
635                 case 'v':
636                         printf("%s\n", hostapd_cli_version);
637                         return 0;
638                 case 'i':
639                         free(ctrl_ifname);
640                         ctrl_ifname = strdup(optarg);
641                         break;
642                 case 'p':
643                         ctrl_iface_dir = optarg;
644                         break;
645                 default:
646                         usage();
647                         return -1;
648                 }
649         }
650
651         interactive = argc == optind;
652
653         if (interactive) {
654                 printf("%s\n\n%s\n\n", hostapd_cli_version,
655                        hostapd_cli_license);
656         }
657
658         for (;;) {
659                 if (ctrl_ifname == NULL) {
660                         struct dirent *dent;
661                         DIR *dir = opendir(ctrl_iface_dir);
662                         if (dir) {
663                                 while ((dent = readdir(dir))) {
664                                         if (strcmp(dent->d_name, ".") == 0 ||
665                                             strcmp(dent->d_name, "..") == 0)
666                                                 continue;
667                                         printf("Selected interface '%s'\n",
668                                                dent->d_name);
669                                         ctrl_ifname = strdup(dent->d_name);
670                                         break;
671                                 }
672                                 closedir(dir);
673                         }
674                 }
675                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
676                 if (ctrl_conn) {
677                         if (warning_displayed)
678                                 printf("Connection established.\n");
679                         break;
680                 }
681
682                 if (!interactive) {
683                         perror("Failed to connect to hostapd - "
684                                "wpa_ctrl_open");
685                         return -1;
686                 }
687
688                 if (!warning_displayed) {
689                         printf("Could not connect to hostapd - re-trying\n");
690                         warning_displayed = 1;
691                 }
692                 sleep(1);
693                 continue;
694         }
695
696         signal(SIGINT, hostapd_cli_terminate);
697         signal(SIGTERM, hostapd_cli_terminate);
698         signal(SIGALRM, hostapd_cli_alarm);
699
700         if (interactive) {
701                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
702                         hostapd_cli_attached = 1;
703                 } else {
704                         printf("Warning: Failed to attach to hostapd.\n");
705                 }
706                 hostapd_cli_interactive();
707         } else
708                 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
709
710         free(ctrl_ifname);
711         hostapd_cli_close_connection();
712         return 0;
713 }