Add wps_cancel for hostapd_cli
[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 static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
396                                       char *argv[])
397 {
398         return wpa_ctrl_command(ctrl, "WPS_CANCEL");
399 }
400
401
402 #ifdef CONFIG_WPS_OOB
403 static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
404                                    char *argv[])
405 {
406         char cmd[256];
407         int res;
408
409         if (argc != 3 && argc != 4) {
410                 printf("Invalid WPS_OOB command: need three or four "
411                        "arguments:\n"
412                        "- DEV_TYPE: use 'ufd' or 'nfc'\n"
413                        "- PATH: path of OOB device like '/mnt'\n"
414                        "- METHOD: OOB method 'pin-e' or 'pin-r', "
415                        "'cred'\n"
416                        "- DEV_NAME: (only for NFC) device name like "
417                        "'pn531'\n");
418                 return -1;
419         }
420
421         if (argc == 3)
422                 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
423                                   argv[0], argv[1], argv[2]);
424         else
425                 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
426                                   argv[0], argv[1], argv[2], argv[3]);
427         if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
428                 printf("Too long WPS_OOB command.\n");
429                 return -1;
430         }
431         return wpa_ctrl_command(ctrl, cmd);
432 }
433 #endif /* CONFIG_WPS_OOB */
434
435
436 static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
437                                       char *argv[])
438 {
439         char buf[64];
440         if (argc < 1) {
441                 printf("Invalid 'wps_ap_pin' command - at least one argument "
442                        "is required.\n");
443                 return -1;
444         }
445         if (argc > 2)
446                 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
447                          argv[0], argv[1], argv[2]);
448         else if (argc > 1)
449                 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
450                          argv[0], argv[1]);
451         else
452                 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
453         return wpa_ctrl_command(ctrl, buf);
454 }
455
456
457 static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
458                                       char *argv[])
459 {
460         char buf[256];
461         char ssid_hex[2 * 32 + 1];
462         char key_hex[2 * 64 + 1];
463         int i;
464
465         if (argc < 1) {
466                 printf("Invalid 'wps_config' command - at least two arguments "
467                        "are required.\n");
468                 return -1;
469         }
470
471         ssid_hex[0] = '\0';
472         for (i = 0; i < 32; i++) {
473                 if (argv[0][i] == '\0')
474                         break;
475                 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
476         }
477
478         key_hex[0] = '\0';
479         if (argc > 3) {
480                 for (i = 0; i < 64; i++) {
481                         if (argv[3][i] == '\0')
482                                 break;
483                         os_snprintf(&key_hex[i * 2], 3, "%02x",
484                                     argv[3][i]);
485                 }
486         }
487
488         if (argc > 3)
489                 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
490                          ssid_hex, argv[1], argv[2], key_hex);
491         else if (argc > 2)
492                 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
493                          ssid_hex, argv[1], argv[2]);
494         else
495                 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
496                          ssid_hex, argv[1]);
497         return wpa_ctrl_command(ctrl, buf);
498 }
499 #endif /* CONFIG_WPS */
500
501
502 static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
503                                         char *argv[])
504 {
505         char buf[300];
506         int res;
507
508         if (argc < 2) {
509                 printf("Invalid 'ess_disassoc' command - two arguments (STA "
510                        "addr and URL) are needed\n");
511                 return -1;
512         }
513
514         res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s",
515                           argv[0], argv[1]);
516         if (res < 0 || res >= (int) sizeof(buf))
517                 return -1;
518         return wpa_ctrl_command(ctrl, buf);
519 }
520
521
522 static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
523                                       char *argv[])
524 {
525         return wpa_ctrl_command(ctrl, "GET_CONFIG");
526 }
527
528
529 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
530                                 char *addr, size_t addr_len)
531 {
532         char buf[4096], *pos;
533         size_t len;
534         int ret;
535
536         if (ctrl_conn == NULL) {
537                 printf("Not connected to hostapd - command dropped.\n");
538                 return -1;
539         }
540         len = sizeof(buf) - 1;
541         ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
542                                hostapd_cli_msg_cb);
543         if (ret == -2) {
544                 printf("'%s' command timed out.\n", cmd);
545                 return -2;
546         } else if (ret < 0) {
547                 printf("'%s' command failed.\n", cmd);
548                 return -1;
549         }
550
551         buf[len] = '\0';
552         if (memcmp(buf, "FAIL", 4) == 0)
553                 return -1;
554         printf("%s", buf);
555
556         pos = buf;
557         while (*pos != '\0' && *pos != '\n')
558                 pos++;
559         *pos = '\0';
560         os_strlcpy(addr, buf, addr_len);
561         return 0;
562 }
563
564
565 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
566                                    char *argv[])
567 {
568         char addr[32], cmd[64];
569
570         if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
571                 return 0;
572         do {
573                 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
574         } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
575
576         return -1;
577 }
578
579
580 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
581 {
582         printf("%s", commands_help);
583         return 0;
584 }
585
586
587 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
588                                    char *argv[])
589 {
590         printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
591         return 0;
592 }
593
594
595 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
596 {
597         hostapd_cli_quit = 1;
598         if (interactive)
599                 eloop_terminate();
600         return 0;
601 }
602
603
604 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
605 {
606         char cmd[256];
607         if (argc != 1) {
608                 printf("Invalid LEVEL command: needs one argument (debug "
609                        "level)\n");
610                 return 0;
611         }
612         snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
613         return wpa_ctrl_command(ctrl, cmd);
614 }
615
616
617 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
618 {
619         struct dirent *dent;
620         DIR *dir;
621
622         dir = opendir(ctrl_iface_dir);
623         if (dir == NULL) {
624                 printf("Control interface directory '%s' could not be "
625                        "openned.\n", ctrl_iface_dir);
626                 return;
627         }
628
629         printf("Available interfaces:\n");
630         while ((dent = readdir(dir))) {
631                 if (strcmp(dent->d_name, ".") == 0 ||
632                     strcmp(dent->d_name, "..") == 0)
633                         continue;
634                 printf("%s\n", dent->d_name);
635         }
636         closedir(dir);
637 }
638
639
640 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
641                                      char *argv[])
642 {
643         if (argc < 1) {
644                 hostapd_cli_list_interfaces(ctrl);
645                 return 0;
646         }
647
648         hostapd_cli_close_connection();
649         free(ctrl_ifname);
650         ctrl_ifname = strdup(argv[0]);
651
652         if (hostapd_cli_open_connection(ctrl_ifname)) {
653                 printf("Connected to interface '%s.\n", ctrl_ifname);
654                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
655                         hostapd_cli_attached = 1;
656                 } else {
657                         printf("Warning: Failed to attach to "
658                                "hostapd.\n");
659                 }
660         } else {
661                 printf("Could not connect to interface '%s' - re-trying\n",
662                         ctrl_ifname);
663         }
664         return 0;
665 }
666
667
668 static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
669 {
670         char cmd[256];
671         int res;
672
673         if (argc != 2) {
674                 printf("Invalid SET command: needs two arguments (variable "
675                        "name and value)\n");
676                 return -1;
677         }
678
679         res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
680         if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
681                 printf("Too long SET command.\n");
682                 return -1;
683         }
684         return wpa_ctrl_command(ctrl, cmd);
685 }
686
687
688 static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
689 {
690         char cmd[256];
691         int res;
692
693         if (argc != 1) {
694                 printf("Invalid GET command: needs one argument (variable "
695                        "name)\n");
696                 return -1;
697         }
698
699         res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
700         if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
701                 printf("Too long GET command.\n");
702                 return -1;
703         }
704         return wpa_ctrl_command(ctrl, cmd);
705 }
706
707
708 struct hostapd_cli_cmd {
709         const char *cmd;
710         int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
711 };
712
713 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
714         { "ping", hostapd_cli_cmd_ping },
715         { "mib", hostapd_cli_cmd_mib },
716         { "relog", hostapd_cli_cmd_relog },
717         { "sta", hostapd_cli_cmd_sta },
718         { "all_sta", hostapd_cli_cmd_all_sta },
719         { "new_sta", hostapd_cli_cmd_new_sta },
720         { "deauthenticate", hostapd_cli_cmd_deauthenticate },
721         { "disassociate", hostapd_cli_cmd_disassociate },
722 #ifdef CONFIG_IEEE80211W
723         { "sa_query", hostapd_cli_cmd_sa_query },
724 #endif /* CONFIG_IEEE80211W */
725 #ifdef CONFIG_WPS
726         { "wps_pin", hostapd_cli_cmd_wps_pin },
727         { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
728         { "wps_pbc", hostapd_cli_cmd_wps_pbc },
729         { "wps_cancel", hostapd_cli_cmd_wps_cancel },
730 #ifdef CONFIG_WPS_OOB
731         { "wps_oob", hostapd_cli_cmd_wps_oob },
732 #endif /* CONFIG_WPS_OOB */
733         { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
734         { "wps_config", hostapd_cli_cmd_wps_config },
735 #endif /* CONFIG_WPS */
736         { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
737         { "get_config", hostapd_cli_cmd_get_config },
738         { "help", hostapd_cli_cmd_help },
739         { "interface", hostapd_cli_cmd_interface },
740         { "level", hostapd_cli_cmd_level },
741         { "license", hostapd_cli_cmd_license },
742         { "quit", hostapd_cli_cmd_quit },
743         { "set", hostapd_cli_cmd_set },
744         { "get", hostapd_cli_cmd_get },
745         { NULL, NULL }
746 };
747
748
749 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
750 {
751         struct hostapd_cli_cmd *cmd, *match = NULL;
752         int count;
753
754         count = 0;
755         cmd = hostapd_cli_commands;
756         while (cmd->cmd) {
757                 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
758                         match = cmd;
759                         if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
760                                 /* we have an exact match */
761                                 count = 1;
762                                 break;
763                         }
764                         count++;
765                 }
766                 cmd++;
767         }
768
769         if (count > 1) {
770                 printf("Ambiguous command '%s'; possible commands:", argv[0]);
771                 cmd = hostapd_cli_commands;
772                 while (cmd->cmd) {
773                         if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
774                             0) {
775                                 printf(" %s", cmd->cmd);
776                         }
777                         cmd++;
778                 }
779                 printf("\n");
780         } else if (count == 0) {
781                 printf("Unknown command '%s'\n", argv[0]);
782         } else {
783                 match->handler(ctrl, argc - 1, &argv[1]);
784         }
785 }
786
787
788 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
789                                      int action_monitor)
790 {
791         int first = 1;
792         if (ctrl_conn == NULL)
793                 return;
794         while (wpa_ctrl_pending(ctrl)) {
795                 char buf[256];
796                 size_t len = sizeof(buf) - 1;
797                 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
798                         buf[len] = '\0';
799                         if (action_monitor)
800                                 hostapd_cli_action_process(buf, len);
801                         else {
802                                 if (in_read && first)
803                                         printf("\n");
804                                 first = 0;
805                                 printf("%s\n", buf);
806                         }
807                 } else {
808                         printf("Could not read pending message.\n");
809                         break;
810                 }
811         }
812 }
813
814
815 #define max_args 10
816
817 static int tokenize_cmd(char *cmd, char *argv[])
818 {
819         char *pos;
820         int argc = 0;
821
822         pos = cmd;
823         for (;;) {
824                 while (*pos == ' ')
825                         pos++;
826                 if (*pos == '\0')
827                         break;
828                 argv[argc] = pos;
829                 argc++;
830                 if (argc == max_args)
831                         break;
832                 if (*pos == '"') {
833                         char *pos2 = os_strrchr(pos, '"');
834                         if (pos2)
835                                 pos = pos2 + 1;
836                 }
837                 while (*pos != '\0' && *pos != ' ')
838                         pos++;
839                 if (*pos == ' ')
840                         *pos++ = '\0';
841         }
842
843         return argc;
844 }
845
846
847 static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
848 {
849         if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
850                 printf("Connection to hostapd lost - trying to reconnect\n");
851                 hostapd_cli_close_connection();
852         }
853         if (!ctrl_conn) {
854                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
855                 if (ctrl_conn) {
856                         printf("Connection to hostapd re-established\n");
857                         if (wpa_ctrl_attach(ctrl_conn) == 0) {
858                                 hostapd_cli_attached = 1;
859                         } else {
860                                 printf("Warning: Failed to attach to "
861                                        "hostapd.\n");
862                         }
863                 }
864         }
865         if (ctrl_conn)
866                 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
867         eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
868 }
869
870
871 static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
872 {
873         eloop_terminate();
874 }
875
876
877 static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
878 {
879         char *argv[max_args];
880         int argc;
881         argc = tokenize_cmd(cmd, argv);
882         if (argc)
883                 wpa_request(ctrl_conn, argc, argv);
884 }
885
886
887 static void hostapd_cli_edit_eof_cb(void *ctx)
888 {
889         eloop_terminate();
890 }
891
892
893 static void hostapd_cli_interactive(void)
894 {
895         printf("\nInteractive mode\n\n");
896
897         eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
898         edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
899                   NULL, NULL, NULL);
900         eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
901
902         eloop_run();
903
904         edit_deinit(NULL, NULL);
905         eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
906 }
907
908
909 static void hostapd_cli_cleanup(void)
910 {
911         hostapd_cli_close_connection();
912         if (pid_file)
913                 os_daemonize_terminate(pid_file);
914
915         os_program_deinit();
916 }
917
918
919 static void hostapd_cli_action(struct wpa_ctrl *ctrl)
920 {
921         fd_set rfds;
922         int fd, res;
923         struct timeval tv;
924         char buf[256];
925         size_t len;
926
927         fd = wpa_ctrl_get_fd(ctrl);
928
929         while (!hostapd_cli_quit) {
930                 FD_ZERO(&rfds);
931                 FD_SET(fd, &rfds);
932                 tv.tv_sec = ping_interval;
933                 tv.tv_usec = 0;
934                 res = select(fd + 1, &rfds, NULL, NULL, &tv);
935                 if (res < 0 && errno != EINTR) {
936                         perror("select");
937                         break;
938                 }
939
940                 if (FD_ISSET(fd, &rfds))
941                         hostapd_cli_recv_pending(ctrl, 0, 1);
942                 else {
943                         len = sizeof(buf) - 1;
944                         if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
945                                              hostapd_cli_action_process) < 0 ||
946                             len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
947                                 printf("hostapd did not reply to PING "
948                                        "command - exiting\n");
949                                 break;
950                         }
951                 }
952         }
953 }
954
955
956 int main(int argc, char *argv[])
957 {
958         int warning_displayed = 0;
959         int c;
960         int daemonize = 0;
961
962         if (os_program_init())
963                 return -1;
964
965         for (;;) {
966                 c = getopt(argc, argv, "a:BhG:i:p:v");
967                 if (c < 0)
968                         break;
969                 switch (c) {
970                 case 'a':
971                         action_file = optarg;
972                         break;
973                 case 'B':
974                         daemonize = 1;
975                         break;
976                 case 'G':
977                         ping_interval = atoi(optarg);
978                         break;
979                 case 'h':
980                         usage();
981                         return 0;
982                 case 'v':
983                         printf("%s\n", hostapd_cli_version);
984                         return 0;
985                 case 'i':
986                         os_free(ctrl_ifname);
987                         ctrl_ifname = os_strdup(optarg);
988                         break;
989                 case 'p':
990                         ctrl_iface_dir = optarg;
991                         break;
992                 default:
993                         usage();
994                         return -1;
995                 }
996         }
997
998         interactive = (argc == optind) && (action_file == NULL);
999
1000         if (interactive) {
1001                 printf("%s\n\n%s\n\n", hostapd_cli_version,
1002                        hostapd_cli_license);
1003         }
1004
1005         if (eloop_init())
1006                 return -1;
1007
1008         for (;;) {
1009                 if (ctrl_ifname == NULL) {
1010                         struct dirent *dent;
1011                         DIR *dir = opendir(ctrl_iface_dir);
1012                         if (dir) {
1013                                 while ((dent = readdir(dir))) {
1014                                         if (os_strcmp(dent->d_name, ".") == 0
1015                                             ||
1016                                             os_strcmp(dent->d_name, "..") == 0)
1017                                                 continue;
1018                                         printf("Selected interface '%s'\n",
1019                                                dent->d_name);
1020                                         ctrl_ifname = os_strdup(dent->d_name);
1021                                         break;
1022                                 }
1023                                 closedir(dir);
1024                         }
1025                 }
1026                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1027                 if (ctrl_conn) {
1028                         if (warning_displayed)
1029                                 printf("Connection established.\n");
1030                         break;
1031                 }
1032
1033                 if (!interactive) {
1034                         perror("Failed to connect to hostapd - "
1035                                "wpa_ctrl_open");
1036                         return -1;
1037                 }
1038
1039                 if (!warning_displayed) {
1040                         printf("Could not connect to hostapd - re-trying\n");
1041                         warning_displayed = 1;
1042                 }
1043                 os_sleep(1, 0);
1044                 continue;
1045         }
1046
1047         if (interactive || action_file) {
1048                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1049                         hostapd_cli_attached = 1;
1050                 } else {
1051                         printf("Warning: Failed to attach to hostapd.\n");
1052                         if (action_file)
1053                                 return -1;
1054                 }
1055         }
1056
1057         if (daemonize && os_daemonize(pid_file))
1058                 return -1;
1059
1060         if (interactive)
1061                 hostapd_cli_interactive();
1062         else if (action_file)
1063                 hostapd_cli_action(ctrl_conn);
1064         else
1065                 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1066
1067         os_free(ctrl_ifname);
1068         eloop_destroy();
1069         hostapd_cli_cleanup();
1070         return 0;
1071 }