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