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