nl80211: Stop driver init sooner if the interface does not exist
[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 "   deauthenticate <addr>  deauthenticate a station\n"
87 "   disassociate <addr>  disassociate a station\n"
88 #ifdef CONFIG_IEEE80211W
89 "   sa_query <addr>      send SA Query to a station\n"
90 #endif /* CONFIG_IEEE80211W */
91 #ifdef CONFIG_WPS
92 "   wps_pin <uuid> <pin> [timeout] [addr]  add WPS Enrollee PIN\n"
93 "   wps_check_pin <PIN>  verify PIN checksum\n"
94 "   wps_pbc              indicate button pushed to initiate PBC\n"
95 #ifdef CONFIG_WPS_OOB
96 "   wps_oob <type> <path> <method>  use WPS with out-of-band (UFD)\n"
97 #endif /* CONFIG_WPS_OOB */
98 "   wps_ap_pin <cmd> [params..]  enable/disable AP PIN\n"
99 "   wps_config <SSID> <auth> <encr> <key>  configure AP\n"
100 #endif /* CONFIG_WPS */
101 "   get_config           show current configuration\n"
102 "   help                 show this usage help\n"
103 "   interface [ifname]   show interfaces/select interface\n"
104 "   level <debug level>  change debug level\n"
105 "   license              show full hostapd_cli license\n"
106 "   quit                 exit hostapd_cli\n";
107
108 static struct wpa_ctrl *ctrl_conn;
109 static int hostapd_cli_quit = 0;
110 static int hostapd_cli_attached = 0;
111 static const char *ctrl_iface_dir = "/var/run/hostapd";
112 static char *ctrl_ifname = NULL;
113 static const char *pid_file = NULL;
114 static const char *action_file = NULL;
115 static int ping_interval = 5;
116
117
118 static void usage(void)
119 {
120         fprintf(stderr, "%s\n", hostapd_cli_version);
121         fprintf(stderr,
122                 "\n"
123                 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
124                 "[-a<path>] \\\n"
125                 "                   [-G<ping interval>] [command..]\n"
126                 "\n"
127                 "Options:\n"
128                 "   -h           help (show this usage text)\n"
129                 "   -v           shown version information\n"
130                 "   -p<path>     path to find control sockets (default: "
131                 "/var/run/hostapd)\n"
132                 "   -a<file>     run in daemon mode executing the action file "
133                 "based on events\n"
134                 "                from hostapd\n"
135                 "   -B           run a daemon in the background\n"
136                 "   -i<ifname>   Interface to listen on (default: first "
137                 "interface found in the\n"
138                 "                socket path)\n\n"
139                 "%s",
140                 commands_help);
141 }
142
143
144 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
145 {
146         char *cfile;
147         int flen;
148
149         if (ifname == NULL)
150                 return NULL;
151
152         flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
153         cfile = malloc(flen);
154         if (cfile == NULL)
155                 return NULL;
156         snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
157
158         ctrl_conn = wpa_ctrl_open(cfile);
159         free(cfile);
160         return ctrl_conn;
161 }
162
163
164 static void hostapd_cli_close_connection(void)
165 {
166         if (ctrl_conn == NULL)
167                 return;
168
169         if (hostapd_cli_attached) {
170                 wpa_ctrl_detach(ctrl_conn);
171                 hostapd_cli_attached = 0;
172         }
173         wpa_ctrl_close(ctrl_conn);
174         ctrl_conn = NULL;
175 }
176
177
178 static void hostapd_cli_msg_cb(char *msg, size_t len)
179 {
180         printf("%s\n", msg);
181 }
182
183
184 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
185 {
186         char buf[4096];
187         size_t len;
188         int ret;
189
190         if (ctrl_conn == NULL) {
191                 printf("Not connected to hostapd - command dropped.\n");
192                 return -1;
193         }
194         len = sizeof(buf) - 1;
195         ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
196                                hostapd_cli_msg_cb);
197         if (ret == -2) {
198                 printf("'%s' command timed out.\n", cmd);
199                 return -2;
200         } else if (ret < 0) {
201                 printf("'%s' command failed.\n", cmd);
202                 return -1;
203         }
204         if (print) {
205                 buf[len] = '\0';
206                 printf("%s", buf);
207         }
208         return 0;
209 }
210
211
212 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
213 {
214         return _wpa_ctrl_command(ctrl, cmd, 1);
215 }
216
217
218 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
219 {
220         return wpa_ctrl_command(ctrl, "PING");
221 }
222
223
224 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
225 {
226         return wpa_ctrl_command(ctrl, "MIB");
227 }
228
229
230 static int hostapd_cli_exec(const char *program, const char *arg1,
231                             const char *arg2)
232 {
233         char *cmd;
234         size_t len;
235         int res;
236         int ret = 0;
237
238         len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
239         cmd = os_malloc(len);
240         if (cmd == NULL)
241                 return -1;
242         res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
243         if (res < 0 || (size_t) res >= len) {
244                 os_free(cmd);
245                 return -1;
246         }
247         cmd[len - 1] = '\0';
248 #ifndef _WIN32_WCE
249         if (system(cmd) < 0)
250                 ret = -1;
251 #endif /* _WIN32_WCE */
252         os_free(cmd);
253
254         return ret;
255 }
256
257
258 static void hostapd_cli_action_process(char *msg, size_t len)
259 {
260         const char *pos;
261
262         pos = msg;
263         if (*pos == '<') {
264                 pos = os_strchr(pos, '>');
265                 if (pos)
266                         pos++;
267                 else
268                         pos = msg;
269         }
270
271         hostapd_cli_exec(action_file, ctrl_ifname, pos);
272 }
273
274
275 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
276 {
277         char buf[64];
278         if (argc != 1) {
279                 printf("Invalid 'sta' command - exactly one argument, STA "
280                        "address, is required.\n");
281                 return -1;
282         }
283         snprintf(buf, sizeof(buf), "STA %s", argv[0]);
284         return wpa_ctrl_command(ctrl, buf);
285 }
286
287
288 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
289                                    char *argv[])
290 {
291         char buf[64];
292         if (argc != 1) {
293                 printf("Invalid 'new_sta' command - exactly one argument, STA "
294                        "address, is required.\n");
295                 return -1;
296         }
297         snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
298         return wpa_ctrl_command(ctrl, buf);
299 }
300
301
302 static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
303                                           char *argv[])
304 {
305         char buf[64];
306         if (argc < 1) {
307                 printf("Invalid 'deauthenticate' command - exactly one "
308                        "argument, STA address, is required.\n");
309                 return -1;
310         }
311         if (argc > 1)
312                 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
313                             argv[0], argv[1]);
314         else
315                 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
316         return wpa_ctrl_command(ctrl, buf);
317 }
318
319
320 static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
321                                         char *argv[])
322 {
323         char buf[64];
324         if (argc < 1) {
325                 printf("Invalid 'disassociate' command - exactly one "
326                        "argument, STA address, is required.\n");
327                 return -1;
328         }
329         if (argc > 1)
330                 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
331                             argv[0], argv[1]);
332         else
333                 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
334         return wpa_ctrl_command(ctrl, buf);
335 }
336
337
338 #ifdef CONFIG_IEEE80211W
339 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
340                                     char *argv[])
341 {
342         char buf[64];
343         if (argc != 1) {
344                 printf("Invalid 'sa_query' command - exactly one argument, "
345                        "STA address, is required.\n");
346                 return -1;
347         }
348         snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
349         return wpa_ctrl_command(ctrl, buf);
350 }
351 #endif /* CONFIG_IEEE80211W */
352
353
354 #ifdef CONFIG_WPS
355 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
356                                    char *argv[])
357 {
358         char buf[256];
359         if (argc < 2) {
360                 printf("Invalid 'wps_pin' command - at least two arguments, "
361                        "UUID and PIN, are required.\n");
362                 return -1;
363         }
364         if (argc > 3)
365                 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
366                          argv[0], argv[1], argv[2], argv[3]);
367         else if (argc > 2)
368                 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
369                          argv[0], argv[1], argv[2]);
370         else
371                 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
372         return wpa_ctrl_command(ctrl, buf);
373 }
374
375
376 static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
377                                          char *argv[])
378 {
379         char cmd[256];
380         int res;
381
382         if (argc != 1 && argc != 2) {
383                 printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
384                        "- PIN to be verified\n");
385                 return -1;
386         }
387
388         if (argc == 2)
389                 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
390                                   argv[0], argv[1]);
391         else
392                 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
393                                   argv[0]);
394         if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
395                 printf("Too long WPS_CHECK_PIN command.\n");
396                 return -1;
397         }
398         return wpa_ctrl_command(ctrl, cmd);
399 }
400
401
402 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
403                                    char *argv[])
404 {
405         return wpa_ctrl_command(ctrl, "WPS_PBC");
406 }
407
408
409 #ifdef CONFIG_WPS_OOB
410 static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
411                                    char *argv[])
412 {
413         char cmd[256];
414         int res;
415
416         if (argc != 3 && argc != 4) {
417                 printf("Invalid WPS_OOB command: need three or four "
418                        "arguments:\n"
419                        "- DEV_TYPE: use 'ufd' or 'nfc'\n"
420                        "- PATH: path of OOB device like '/mnt'\n"
421                        "- METHOD: OOB method 'pin-e' or 'pin-r', "
422                        "'cred'\n"
423                        "- DEV_NAME: (only for NFC) device name like "
424                        "'pn531'\n");
425                 return -1;
426         }
427
428         if (argc == 3)
429                 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
430                                   argv[0], argv[1], argv[2]);
431         else
432                 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
433                                   argv[0], argv[1], argv[2], argv[3]);
434         if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
435                 printf("Too long WPS_OOB command.\n");
436                 return -1;
437         }
438         return wpa_ctrl_command(ctrl, cmd);
439 }
440 #endif /* CONFIG_WPS_OOB */
441
442
443 static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
444                                       char *argv[])
445 {
446         char buf[64];
447         if (argc < 1) {
448                 printf("Invalid 'wps_ap_pin' command - at least one argument "
449                        "is required.\n");
450                 return -1;
451         }
452         if (argc > 2)
453                 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
454                          argv[0], argv[1], argv[2]);
455         else if (argc > 1)
456                 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
457                          argv[0], argv[1]);
458         else
459                 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
460         return wpa_ctrl_command(ctrl, buf);
461 }
462
463
464 static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
465                                       char *argv[])
466 {
467         char buf[256];
468         char ssid_hex[2 * 32 + 1];
469         char key_hex[2 * 64 + 1];
470         int i;
471
472         if (argc < 1) {
473                 printf("Invalid 'wps_config' command - at least two arguments "
474                        "are required.\n");
475                 return -1;
476         }
477
478         ssid_hex[0] = '\0';
479         for (i = 0; i < 32; i++) {
480                 if (argv[0][i] == '\0')
481                         break;
482                 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
483         }
484
485         key_hex[0] = '\0';
486         if (argc > 3) {
487                 for (i = 0; i < 64; i++) {
488                         if (argv[3][i] == '\0')
489                                 break;
490                         os_snprintf(&key_hex[i * 2], 3, "%02x",
491                                     argv[3][i]);
492                 }
493         }
494
495         if (argc > 3)
496                 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
497                          ssid_hex, argv[1], argv[2], key_hex);
498         else if (argc > 2)
499                 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
500                          ssid_hex, argv[1], argv[2]);
501         else
502                 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
503                          ssid_hex, argv[1]);
504         return wpa_ctrl_command(ctrl, buf);
505 }
506 #endif /* CONFIG_WPS */
507
508
509 static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
510                                       char *argv[])
511 {
512         return wpa_ctrl_command(ctrl, "GET_CONFIG");
513 }
514
515
516 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
517                                 char *addr, size_t addr_len)
518 {
519         char buf[4096], *pos;
520         size_t len;
521         int ret;
522
523         if (ctrl_conn == NULL) {
524                 printf("Not connected to hostapd - command dropped.\n");
525                 return -1;
526         }
527         len = sizeof(buf) - 1;
528         ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
529                                hostapd_cli_msg_cb);
530         if (ret == -2) {
531                 printf("'%s' command timed out.\n", cmd);
532                 return -2;
533         } else if (ret < 0) {
534                 printf("'%s' command failed.\n", cmd);
535                 return -1;
536         }
537
538         buf[len] = '\0';
539         if (memcmp(buf, "FAIL", 4) == 0)
540                 return -1;
541         printf("%s", buf);
542
543         pos = buf;
544         while (*pos != '\0' && *pos != '\n')
545                 pos++;
546         *pos = '\0';
547         os_strlcpy(addr, buf, addr_len);
548         return 0;
549 }
550
551
552 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
553                                    char *argv[])
554 {
555         char addr[32], cmd[64];
556
557         if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
558                 return 0;
559         do {
560                 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
561         } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
562
563         return -1;
564 }
565
566
567 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
568 {
569         printf("%s", commands_help);
570         return 0;
571 }
572
573
574 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
575                                    char *argv[])
576 {
577         printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
578         return 0;
579 }
580
581
582 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
583 {
584         hostapd_cli_quit = 1;
585         return 0;
586 }
587
588
589 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
590 {
591         char cmd[256];
592         if (argc != 1) {
593                 printf("Invalid LEVEL command: needs one argument (debug "
594                        "level)\n");
595                 return 0;
596         }
597         snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
598         return wpa_ctrl_command(ctrl, cmd);
599 }
600
601
602 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
603 {
604         struct dirent *dent;
605         DIR *dir;
606
607         dir = opendir(ctrl_iface_dir);
608         if (dir == NULL) {
609                 printf("Control interface directory '%s' could not be "
610                        "openned.\n", ctrl_iface_dir);
611                 return;
612         }
613
614         printf("Available interfaces:\n");
615         while ((dent = readdir(dir))) {
616                 if (strcmp(dent->d_name, ".") == 0 ||
617                     strcmp(dent->d_name, "..") == 0)
618                         continue;
619                 printf("%s\n", dent->d_name);
620         }
621         closedir(dir);
622 }
623
624
625 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
626                                      char *argv[])
627 {
628         if (argc < 1) {
629                 hostapd_cli_list_interfaces(ctrl);
630                 return 0;
631         }
632
633         hostapd_cli_close_connection();
634         free(ctrl_ifname);
635         ctrl_ifname = strdup(argv[0]);
636
637         if (hostapd_cli_open_connection(ctrl_ifname)) {
638                 printf("Connected to interface '%s.\n", ctrl_ifname);
639                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
640                         hostapd_cli_attached = 1;
641                 } else {
642                         printf("Warning: Failed to attach to "
643                                "hostapd.\n");
644                 }
645         } else {
646                 printf("Could not connect to interface '%s' - re-trying\n",
647                         ctrl_ifname);
648         }
649         return 0;
650 }
651
652
653 static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
654 {
655         char cmd[256];
656         int res;
657
658         if (argc != 2) {
659                 printf("Invalid SET command: needs two arguments (variable "
660                        "name and value)\n");
661                 return -1;
662         }
663
664         res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
665         if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
666                 printf("Too long SET command.\n");
667                 return -1;
668         }
669         return wpa_ctrl_command(ctrl, cmd);
670 }
671
672
673 static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
674 {
675         char cmd[256];
676         int res;
677
678         if (argc != 1) {
679                 printf("Invalid GET command: needs one argument (variable "
680                        "name)\n");
681                 return -1;
682         }
683
684         res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
685         if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
686                 printf("Too long GET command.\n");
687                 return -1;
688         }
689         return wpa_ctrl_command(ctrl, cmd);
690 }
691
692
693 struct hostapd_cli_cmd {
694         const char *cmd;
695         int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
696 };
697
698 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
699         { "ping", hostapd_cli_cmd_ping },
700         { "mib", hostapd_cli_cmd_mib },
701         { "sta", hostapd_cli_cmd_sta },
702         { "all_sta", hostapd_cli_cmd_all_sta },
703         { "new_sta", hostapd_cli_cmd_new_sta },
704         { "deauthenticate", hostapd_cli_cmd_deauthenticate },
705         { "disassociate", hostapd_cli_cmd_disassociate },
706 #ifdef CONFIG_IEEE80211W
707         { "sa_query", hostapd_cli_cmd_sa_query },
708 #endif /* CONFIG_IEEE80211W */
709 #ifdef CONFIG_WPS
710         { "wps_pin", hostapd_cli_cmd_wps_pin },
711         { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
712         { "wps_pbc", hostapd_cli_cmd_wps_pbc },
713 #ifdef CONFIG_WPS_OOB
714         { "wps_oob", hostapd_cli_cmd_wps_oob },
715 #endif /* CONFIG_WPS_OOB */
716         { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
717         { "wps_config", hostapd_cli_cmd_wps_config },
718 #endif /* CONFIG_WPS */
719         { "get_config", hostapd_cli_cmd_get_config },
720         { "help", hostapd_cli_cmd_help },
721         { "interface", hostapd_cli_cmd_interface },
722         { "level", hostapd_cli_cmd_level },
723         { "license", hostapd_cli_cmd_license },
724         { "quit", hostapd_cli_cmd_quit },
725         { "set", hostapd_cli_cmd_set },
726         { "get", hostapd_cli_cmd_get },
727         { NULL, NULL }
728 };
729
730
731 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
732 {
733         struct hostapd_cli_cmd *cmd, *match = NULL;
734         int count;
735
736         count = 0;
737         cmd = hostapd_cli_commands;
738         while (cmd->cmd) {
739                 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
740                         match = cmd;
741                         if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
742                                 /* we have an exact match */
743                                 count = 1;
744                                 break;
745                         }
746                         count++;
747                 }
748                 cmd++;
749         }
750
751         if (count > 1) {
752                 printf("Ambiguous command '%s'; possible commands:", argv[0]);
753                 cmd = hostapd_cli_commands;
754                 while (cmd->cmd) {
755                         if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
756                             0) {
757                                 printf(" %s", cmd->cmd);
758                         }
759                         cmd++;
760                 }
761                 printf("\n");
762         } else if (count == 0) {
763                 printf("Unknown command '%s'\n", argv[0]);
764         } else {
765                 match->handler(ctrl, argc - 1, &argv[1]);
766         }
767 }
768
769
770 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
771                                      int action_monitor)
772 {
773         int first = 1;
774         if (ctrl_conn == NULL)
775                 return;
776         while (wpa_ctrl_pending(ctrl)) {
777                 char buf[256];
778                 size_t len = sizeof(buf) - 1;
779                 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
780                         buf[len] = '\0';
781                         if (action_monitor)
782                                 hostapd_cli_action_process(buf, len);
783                         else {
784                                 if (in_read && first)
785                                         printf("\n");
786                                 first = 0;
787                                 printf("%s\n", buf);
788                         }
789                 } else {
790                         printf("Could not read pending message.\n");
791                         break;
792                 }
793         }
794 }
795
796
797 static void hostapd_cli_interactive(void)
798 {
799         const int max_args = 10;
800         char cmd[256], *res, *argv[max_args], *pos;
801         int argc;
802
803         printf("\nInteractive mode\n\n");
804
805         do {
806                 hostapd_cli_recv_pending(ctrl_conn, 0, 0);
807                 printf("> ");
808                 alarm(ping_interval);
809                 res = fgets(cmd, sizeof(cmd), stdin);
810                 alarm(0);
811                 if (res == NULL)
812                         break;
813                 pos = cmd;
814                 while (*pos != '\0') {
815                         if (*pos == '\n') {
816                                 *pos = '\0';
817                                 break;
818                         }
819                         pos++;
820                 }
821                 argc = 0;
822                 pos = cmd;
823                 for (;;) {
824                         while (*pos == ' ')
825                                 pos++;
826                         if (*pos == '\0')
827                                 break;
828                         argv[argc] = pos;
829                         argc++;
830                         if (argc == max_args)
831                                 break;
832                         while (*pos != '\0' && *pos != ' ')
833                                 pos++;
834                         if (*pos == ' ')
835                                 *pos++ = '\0';
836                 }
837                 if (argc)
838                         wpa_request(ctrl_conn, argc, argv);
839         } while (!hostapd_cli_quit);
840 }
841
842
843 static void hostapd_cli_cleanup(void)
844 {
845         hostapd_cli_close_connection();
846         if (pid_file)
847                 os_daemonize_terminate(pid_file);
848
849         os_program_deinit();
850 }
851
852
853 static void hostapd_cli_terminate(int sig)
854 {
855         hostapd_cli_cleanup();
856         exit(0);
857 }
858
859
860 static void hostapd_cli_alarm(int sig)
861 {
862         if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
863                 printf("Connection to hostapd lost - trying to reconnect\n");
864                 hostapd_cli_close_connection();
865         }
866         if (!ctrl_conn) {
867                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
868                 if (ctrl_conn) {
869                         printf("Connection to hostapd re-established\n");
870                         if (wpa_ctrl_attach(ctrl_conn) == 0) {
871                                 hostapd_cli_attached = 1;
872                         } else {
873                                 printf("Warning: Failed to attach to "
874                                        "hostapd.\n");
875                         }
876                 }
877         }
878         if (ctrl_conn)
879                 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
880         alarm(ping_interval);
881 }
882
883
884 static void hostapd_cli_action(struct wpa_ctrl *ctrl)
885 {
886         fd_set rfds;
887         int fd, res;
888         struct timeval tv;
889         char buf[256];
890         size_t len;
891
892         fd = wpa_ctrl_get_fd(ctrl);
893
894         while (!hostapd_cli_quit) {
895                 FD_ZERO(&rfds);
896                 FD_SET(fd, &rfds);
897                 tv.tv_sec = ping_interval;
898                 tv.tv_usec = 0;
899                 res = select(fd + 1, &rfds, NULL, NULL, &tv);
900                 if (res < 0 && errno != EINTR) {
901                         perror("select");
902                         break;
903                 }
904
905                 if (FD_ISSET(fd, &rfds))
906                         hostapd_cli_recv_pending(ctrl, 0, 1);
907                 else {
908                         len = sizeof(buf) - 1;
909                         if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
910                                              hostapd_cli_action_process) < 0 ||
911                             len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
912                                 printf("hostapd did not reply to PING "
913                                        "command - exiting\n");
914                                 break;
915                         }
916                 }
917         }
918 }
919
920
921 int main(int argc, char *argv[])
922 {
923         int interactive;
924         int warning_displayed = 0;
925         int c;
926         int daemonize = 0;
927
928         if (os_program_init())
929                 return -1;
930
931         for (;;) {
932                 c = getopt(argc, argv, "a:BhG:i:p:v");
933                 if (c < 0)
934                         break;
935                 switch (c) {
936                 case 'a':
937                         action_file = optarg;
938                         break;
939                 case 'B':
940                         daemonize = 1;
941                         break;
942                 case 'G':
943                         ping_interval = atoi(optarg);
944                         break;
945                 case 'h':
946                         usage();
947                         return 0;
948                 case 'v':
949                         printf("%s\n", hostapd_cli_version);
950                         return 0;
951                 case 'i':
952                         os_free(ctrl_ifname);
953                         ctrl_ifname = os_strdup(optarg);
954                         break;
955                 case 'p':
956                         ctrl_iface_dir = optarg;
957                         break;
958                 default:
959                         usage();
960                         return -1;
961                 }
962         }
963
964         interactive = (argc == optind) && (action_file == NULL);
965
966         if (interactive) {
967                 printf("%s\n\n%s\n\n", hostapd_cli_version,
968                        hostapd_cli_license);
969         }
970
971         for (;;) {
972                 if (ctrl_ifname == NULL) {
973                         struct dirent *dent;
974                         DIR *dir = opendir(ctrl_iface_dir);
975                         if (dir) {
976                                 while ((dent = readdir(dir))) {
977                                         if (os_strcmp(dent->d_name, ".") == 0
978                                             ||
979                                             os_strcmp(dent->d_name, "..") == 0)
980                                                 continue;
981                                         printf("Selected interface '%s'\n",
982                                                dent->d_name);
983                                         ctrl_ifname = os_strdup(dent->d_name);
984                                         break;
985                                 }
986                                 closedir(dir);
987                         }
988                 }
989                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
990                 if (ctrl_conn) {
991                         if (warning_displayed)
992                                 printf("Connection established.\n");
993                         break;
994                 }
995
996                 if (!interactive) {
997                         perror("Failed to connect to hostapd - "
998                                "wpa_ctrl_open");
999                         return -1;
1000                 }
1001
1002                 if (!warning_displayed) {
1003                         printf("Could not connect to hostapd - re-trying\n");
1004                         warning_displayed = 1;
1005                 }
1006                 os_sleep(1, 0);
1007                 continue;
1008         }
1009
1010         signal(SIGINT, hostapd_cli_terminate);
1011         signal(SIGTERM, hostapd_cli_terminate);
1012         signal(SIGALRM, hostapd_cli_alarm);
1013
1014         if (interactive || action_file) {
1015                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1016                         hostapd_cli_attached = 1;
1017                 } else {
1018                         printf("Warning: Failed to attach to hostapd.\n");
1019                         if (action_file)
1020                                 return -1;
1021                 }
1022         }
1023
1024         if (daemonize && os_daemonize(pid_file))
1025                 return -1;
1026
1027         if (interactive)
1028                 hostapd_cli_interactive();
1029         else if (action_file)
1030                 hostapd_cli_action(ctrl_conn);
1031         else
1032                 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1033
1034         os_free(ctrl_ifname);
1035         hostapd_cli_cleanup();
1036         return 0;
1037 }