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