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