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