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