hostapd: Add wps_config ctrl_interface command for configuring AP
[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 struct hostapd_cli_cmd {
674         const char *cmd;
675         int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
676 };
677
678 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
679         { "ping", hostapd_cli_cmd_ping },
680         { "mib", hostapd_cli_cmd_mib },
681         { "sta", hostapd_cli_cmd_sta },
682         { "all_sta", hostapd_cli_cmd_all_sta },
683         { "new_sta", hostapd_cli_cmd_new_sta },
684         { "deauthenticate", hostapd_cli_cmd_deauthenticate },
685         { "disassociate", hostapd_cli_cmd_disassociate },
686 #ifdef CONFIG_IEEE80211W
687         { "sa_query", hostapd_cli_cmd_sa_query },
688 #endif /* CONFIG_IEEE80211W */
689 #ifdef CONFIG_WPS
690         { "wps_pin", hostapd_cli_cmd_wps_pin },
691         { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
692         { "wps_pbc", hostapd_cli_cmd_wps_pbc },
693 #ifdef CONFIG_WPS_OOB
694         { "wps_oob", hostapd_cli_cmd_wps_oob },
695 #endif /* CONFIG_WPS_OOB */
696         { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
697         { "wps_config", hostapd_cli_cmd_wps_config },
698 #endif /* CONFIG_WPS */
699         { "get_config", hostapd_cli_cmd_get_config },
700         { "help", hostapd_cli_cmd_help },
701         { "interface", hostapd_cli_cmd_interface },
702         { "level", hostapd_cli_cmd_level },
703         { "license", hostapd_cli_cmd_license },
704         { "quit", hostapd_cli_cmd_quit },
705         { "set", hostapd_cli_cmd_set },
706         { NULL, NULL }
707 };
708
709
710 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
711 {
712         struct hostapd_cli_cmd *cmd, *match = NULL;
713         int count;
714
715         count = 0;
716         cmd = hostapd_cli_commands;
717         while (cmd->cmd) {
718                 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
719                         match = cmd;
720                         count++;
721                 }
722                 cmd++;
723         }
724
725         if (count > 1) {
726                 printf("Ambiguous command '%s'; possible commands:", argv[0]);
727                 cmd = hostapd_cli_commands;
728                 while (cmd->cmd) {
729                         if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
730                             0) {
731                                 printf(" %s", cmd->cmd);
732                         }
733                         cmd++;
734                 }
735                 printf("\n");
736         } else if (count == 0) {
737                 printf("Unknown command '%s'\n", argv[0]);
738         } else {
739                 match->handler(ctrl, argc - 1, &argv[1]);
740         }
741 }
742
743
744 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
745                                      int action_monitor)
746 {
747         int first = 1;
748         if (ctrl_conn == NULL)
749                 return;
750         while (wpa_ctrl_pending(ctrl)) {
751                 char buf[256];
752                 size_t len = sizeof(buf) - 1;
753                 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
754                         buf[len] = '\0';
755                         if (action_monitor)
756                                 hostapd_cli_action_process(buf, len);
757                         else {
758                                 if (in_read && first)
759                                         printf("\n");
760                                 first = 0;
761                                 printf("%s\n", buf);
762                         }
763                 } else {
764                         printf("Could not read pending message.\n");
765                         break;
766                 }
767         }
768 }
769
770
771 static void hostapd_cli_interactive(void)
772 {
773         const int max_args = 10;
774         char cmd[256], *res, *argv[max_args], *pos;
775         int argc;
776
777         printf("\nInteractive mode\n\n");
778
779         do {
780                 hostapd_cli_recv_pending(ctrl_conn, 0, 0);
781                 printf("> ");
782                 alarm(ping_interval);
783                 res = fgets(cmd, sizeof(cmd), stdin);
784                 alarm(0);
785                 if (res == NULL)
786                         break;
787                 pos = cmd;
788                 while (*pos != '\0') {
789                         if (*pos == '\n') {
790                                 *pos = '\0';
791                                 break;
792                         }
793                         pos++;
794                 }
795                 argc = 0;
796                 pos = cmd;
797                 for (;;) {
798                         while (*pos == ' ')
799                                 pos++;
800                         if (*pos == '\0')
801                                 break;
802                         argv[argc] = pos;
803                         argc++;
804                         if (argc == max_args)
805                                 break;
806                         while (*pos != '\0' && *pos != ' ')
807                                 pos++;
808                         if (*pos == ' ')
809                                 *pos++ = '\0';
810                 }
811                 if (argc)
812                         wpa_request(ctrl_conn, argc, argv);
813         } while (!hostapd_cli_quit);
814 }
815
816
817 static void hostapd_cli_cleanup(void)
818 {
819         hostapd_cli_close_connection();
820         if (pid_file)
821                 os_daemonize_terminate(pid_file);
822
823         os_program_deinit();
824 }
825
826
827 static void hostapd_cli_terminate(int sig)
828 {
829         hostapd_cli_cleanup();
830         exit(0);
831 }
832
833
834 static void hostapd_cli_alarm(int sig)
835 {
836         if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
837                 printf("Connection to hostapd lost - trying to reconnect\n");
838                 hostapd_cli_close_connection();
839         }
840         if (!ctrl_conn) {
841                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
842                 if (ctrl_conn) {
843                         printf("Connection to hostapd re-established\n");
844                         if (wpa_ctrl_attach(ctrl_conn) == 0) {
845                                 hostapd_cli_attached = 1;
846                         } else {
847                                 printf("Warning: Failed to attach to "
848                                        "hostapd.\n");
849                         }
850                 }
851         }
852         if (ctrl_conn)
853                 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
854         alarm(ping_interval);
855 }
856
857
858 static void hostapd_cli_action(struct wpa_ctrl *ctrl)
859 {
860         fd_set rfds;
861         int fd, res;
862         struct timeval tv;
863         char buf[256];
864         size_t len;
865
866         fd = wpa_ctrl_get_fd(ctrl);
867
868         while (!hostapd_cli_quit) {
869                 FD_ZERO(&rfds);
870                 FD_SET(fd, &rfds);
871                 tv.tv_sec = ping_interval;
872                 tv.tv_usec = 0;
873                 res = select(fd + 1, &rfds, NULL, NULL, &tv);
874                 if (res < 0 && errno != EINTR) {
875                         perror("select");
876                         break;
877                 }
878
879                 if (FD_ISSET(fd, &rfds))
880                         hostapd_cli_recv_pending(ctrl, 0, 1);
881                 else {
882                         len = sizeof(buf) - 1;
883                         if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
884                                              hostapd_cli_action_process) < 0 ||
885                             len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
886                                 printf("hostapd did not reply to PING "
887                                        "command - exiting\n");
888                                 break;
889                         }
890                 }
891         }
892 }
893
894
895 int main(int argc, char *argv[])
896 {
897         int interactive;
898         int warning_displayed = 0;
899         int c;
900         int daemonize = 0;
901
902         if (os_program_init())
903                 return -1;
904
905         for (;;) {
906                 c = getopt(argc, argv, "a:BhG:i:p:v");
907                 if (c < 0)
908                         break;
909                 switch (c) {
910                 case 'a':
911                         action_file = optarg;
912                         break;
913                 case 'B':
914                         daemonize = 1;
915                         break;
916                 case 'G':
917                         ping_interval = atoi(optarg);
918                         break;
919                 case 'h':
920                         usage();
921                         return 0;
922                 case 'v':
923                         printf("%s\n", hostapd_cli_version);
924                         return 0;
925                 case 'i':
926                         os_free(ctrl_ifname);
927                         ctrl_ifname = os_strdup(optarg);
928                         break;
929                 case 'p':
930                         ctrl_iface_dir = optarg;
931                         break;
932                 default:
933                         usage();
934                         return -1;
935                 }
936         }
937
938         interactive = (argc == optind) && (action_file == NULL);
939
940         if (interactive) {
941                 printf("%s\n\n%s\n\n", hostapd_cli_version,
942                        hostapd_cli_license);
943         }
944
945         for (;;) {
946                 if (ctrl_ifname == NULL) {
947                         struct dirent *dent;
948                         DIR *dir = opendir(ctrl_iface_dir);
949                         if (dir) {
950                                 while ((dent = readdir(dir))) {
951                                         if (os_strcmp(dent->d_name, ".") == 0
952                                             ||
953                                             os_strcmp(dent->d_name, "..") == 0)
954                                                 continue;
955                                         printf("Selected interface '%s'\n",
956                                                dent->d_name);
957                                         ctrl_ifname = os_strdup(dent->d_name);
958                                         break;
959                                 }
960                                 closedir(dir);
961                         }
962                 }
963                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
964                 if (ctrl_conn) {
965                         if (warning_displayed)
966                                 printf("Connection established.\n");
967                         break;
968                 }
969
970                 if (!interactive) {
971                         perror("Failed to connect to hostapd - "
972                                "wpa_ctrl_open");
973                         return -1;
974                 }
975
976                 if (!warning_displayed) {
977                         printf("Could not connect to hostapd - re-trying\n");
978                         warning_displayed = 1;
979                 }
980                 os_sleep(1, 0);
981                 continue;
982         }
983
984         signal(SIGINT, hostapd_cli_terminate);
985         signal(SIGTERM, hostapd_cli_terminate);
986         signal(SIGALRM, hostapd_cli_alarm);
987
988         if (interactive || action_file) {
989                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
990                         hostapd_cli_attached = 1;
991                 } else {
992                         printf("Warning: Failed to attach to hostapd.\n");
993                         if (action_file)
994                                 return -1;
995                 }
996         }
997
998         if (daemonize && os_daemonize(pid_file))
999                 return -1;
1000
1001         if (interactive)
1002                 hostapd_cli_interactive();
1003         else if (action_file)
1004                 hostapd_cli_action(ctrl_conn);
1005         else
1006                 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1007
1008         os_free(ctrl_ifname);
1009         hostapd_cli_cleanup();
1010         return 0;
1011 }