udp: Merge udp_send and udp_output
[dragonfly.git] / contrib / hostapd / hostapd / hostapd_cli.c
1 /*
2  * hostapd - command line interface for hostapd daemon
3  * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include "includes.h"
16 #include <dirent.h>
17
18 #include "wpa_ctrl.h"
19 #include "common.h"
20 #include "version.h"
21
22
23 static const char *hostapd_cli_version =
24 "hostapd_cli v" VERSION_STR "\n"
25 "Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> and contributors";
26
27
28 static const char *hostapd_cli_license =
29 "This program is free software. You can distribute it and/or modify it\n"
30 "under the terms of the GNU General Public License version 2.\n"
31 "\n"
32 "Alternatively, this software may be distributed under the terms of the\n"
33 "BSD license. See README and COPYING for more details.\n";
34
35 static const char *hostapd_cli_full_license =
36 "This program is free software; you can redistribute it and/or modify\n"
37 "it under the terms of the GNU General Public License version 2 as\n"
38 "published by the Free Software Foundation.\n"
39 "\n"
40 "This program is distributed in the hope that it will be useful,\n"
41 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
42 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
43 "GNU General Public License for more details.\n"
44 "\n"
45 "You should have received a copy of the GNU General Public License\n"
46 "along with this program; if not, write to the Free Software\n"
47 "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n"
48 "\n"
49 "Alternatively, this software may be distributed under the terms of the\n"
50 "BSD license.\n"
51 "\n"
52 "Redistribution and use in source and binary forms, with or without\n"
53 "modification, are permitted provided that the following conditions are\n"
54 "met:\n"
55 "\n"
56 "1. Redistributions of source code must retain the above copyright\n"
57 "   notice, this list of conditions and the following disclaimer.\n"
58 "\n"
59 "2. Redistributions in binary form must reproduce the above copyright\n"
60 "   notice, this list of conditions and the following disclaimer in the\n"
61 "   documentation and/or other materials provided with the distribution.\n"
62 "\n"
63 "3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
64 "   names of its contributors may be used to endorse or promote products\n"
65 "   derived from this software without specific prior written permission.\n"
66 "\n"
67 "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
68 "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
69 "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
70 "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
71 "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
72 "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
73 "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
74 "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
75 "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
76 "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
77 "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
78 "\n";
79
80 static const char *commands_help =
81 "Commands:\n"
82 "   mib                  get MIB variables (dot1x, dot11, radius)\n"
83 "   sta <addr>           get MIB variables for one station\n"
84 "   all_sta              get MIB variables for all stations\n"
85 "   new_sta <addr>       add a new station\n"
86 #ifdef CONFIG_IEEE80211W
87 "   sa_query <addr>      send SA Query to a station\n"
88 #endif /* CONFIG_IEEE80211W */
89 #ifdef CONFIG_WPS
90 "   wps_pin <uuid> <pin> [timeout]  add WPS Enrollee PIN (Device Password)\n"
91 "   wps_pbc              indicate button pushed to initiate PBC\n"
92 #endif /* CONFIG_WPS */
93 "   help                 show this usage help\n"
94 "   interface [ifname]   show interfaces/select interface\n"
95 "   level <debug level>  change debug level\n"
96 "   license              show full hostapd_cli license\n"
97 "   quit                 exit hostapd_cli\n";
98
99 static struct wpa_ctrl *ctrl_conn;
100 static int hostapd_cli_quit = 0;
101 static int hostapd_cli_attached = 0;
102 static const char *ctrl_iface_dir = "/var/run/hostapd";
103 static char *ctrl_ifname = NULL;
104 static int ping_interval = 5;
105
106
107 static void usage(void)
108 {
109         fprintf(stderr, "%s\n", hostapd_cli_version);
110         fprintf(stderr, 
111                 "\n"    
112                 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hv] "
113                 "[-G<ping interval>] \\\n"
114                 "        [command..]\n"
115                 "\n"
116                 "Options:\n"
117                 "   -h           help (show this usage text)\n"
118                 "   -v           shown version information\n"
119                 "   -p<path>     path to find control sockets (default: "
120                 "/var/run/hostapd)\n"
121                 "   -i<ifname>   Interface to listen on (default: first "
122                 "interface found in the\n"
123                 "                socket path)\n\n"
124                 "%s",
125                 commands_help);
126 }
127
128
129 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
130 {
131         char *cfile;
132         int flen;
133
134         if (ifname == NULL)
135                 return NULL;
136
137         flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
138         cfile = malloc(flen);
139         if (cfile == NULL)
140                 return NULL;
141         snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
142
143         ctrl_conn = wpa_ctrl_open(cfile);
144         free(cfile);
145         return ctrl_conn;
146 }
147
148
149 static void hostapd_cli_close_connection(void)
150 {
151         if (ctrl_conn == NULL)
152                 return;
153
154         if (hostapd_cli_attached) {
155                 wpa_ctrl_detach(ctrl_conn);
156                 hostapd_cli_attached = 0;
157         }
158         wpa_ctrl_close(ctrl_conn);
159         ctrl_conn = NULL;
160 }
161
162
163 static void hostapd_cli_msg_cb(char *msg, size_t len)
164 {
165         printf("%s\n", msg);
166 }
167
168
169 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
170 {
171         char buf[4096];
172         size_t len;
173         int ret;
174
175         if (ctrl_conn == NULL) {
176                 printf("Not connected to hostapd - command dropped.\n");
177                 return -1;
178         }
179         len = sizeof(buf) - 1;
180         ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
181                                hostapd_cli_msg_cb);
182         if (ret == -2) {
183                 printf("'%s' command timed out.\n", cmd);
184                 return -2;
185         } else if (ret < 0) {
186                 printf("'%s' command failed.\n", cmd);
187                 return -1;
188         }
189         if (print) {
190                 buf[len] = '\0';
191                 printf("%s", buf);
192         }
193         return 0;
194 }
195
196
197 static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
198 {
199         return _wpa_ctrl_command(ctrl, cmd, 1);
200 }
201
202
203 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
204 {
205         return wpa_ctrl_command(ctrl, "PING");
206 }
207
208
209 static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
210 {
211         return wpa_ctrl_command(ctrl, "MIB");
212 }
213
214
215 static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
216 {
217         char buf[64];
218         if (argc != 1) {
219                 printf("Invalid 'sta' command - exactly one argument, STA "
220                        "address, is required.\n");
221                 return -1;
222         }
223         snprintf(buf, sizeof(buf), "STA %s", argv[0]);
224         return wpa_ctrl_command(ctrl, buf);
225 }
226
227
228 static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
229                                    char *argv[])
230 {
231         char buf[64];
232         if (argc != 1) {
233                 printf("Invalid 'new_sta' command - exactly one argument, STA "
234                        "address, is required.\n");
235                 return -1;
236         }
237         snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
238         return wpa_ctrl_command(ctrl, buf);
239 }
240
241
242 #ifdef CONFIG_IEEE80211W
243 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
244                                     char *argv[])
245 {
246         char buf[64];
247         if (argc != 1) {
248                 printf("Invalid 'sa_query' command - exactly one argument, "
249                        "STA address, is required.\n");
250                 return -1;
251         }
252         snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
253         return wpa_ctrl_command(ctrl, buf);
254 }
255 #endif /* CONFIG_IEEE80211W */
256
257
258 #ifdef CONFIG_WPS
259 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
260                                    char *argv[])
261 {
262         char buf[64];
263         if (argc < 2) {
264                 printf("Invalid 'wps_pin' command - at least two arguments, "
265                        "UUID and PIN, are required.\n");
266                 return -1;
267         }
268         if (argc > 2)
269                 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
270                          argv[0], argv[1], argv[2]);
271         else
272                 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
273         return wpa_ctrl_command(ctrl, buf);
274 }
275
276
277 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
278                                    char *argv[])
279 {
280         return wpa_ctrl_command(ctrl, "WPS_PBC");
281 }
282 #endif /* CONFIG_WPS */
283
284
285 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
286                                 char *addr, size_t addr_len)
287 {
288         char buf[4096], *pos;
289         size_t len;
290         int ret;
291
292         if (ctrl_conn == NULL) {
293                 printf("Not connected to hostapd - command dropped.\n");
294                 return -1;
295         }
296         len = sizeof(buf) - 1;
297         ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
298                                hostapd_cli_msg_cb);
299         if (ret == -2) {
300                 printf("'%s' command timed out.\n", cmd);
301                 return -2;
302         } else if (ret < 0) {
303                 printf("'%s' command failed.\n", cmd);
304                 return -1;
305         }
306
307         buf[len] = '\0';
308         if (memcmp(buf, "FAIL", 4) == 0)
309                 return -1;
310         printf("%s", buf);
311
312         pos = buf;
313         while (*pos != '\0' && *pos != '\n')
314                 pos++;
315         *pos = '\0';
316         os_strlcpy(addr, buf, addr_len);
317         return 0;
318 }
319
320
321 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
322                                    char *argv[])
323 {
324         char addr[32], cmd[64];
325
326         if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
327                 return 0;
328         do {
329                 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
330         } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
331
332         return -1;
333 }
334
335
336 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
337 {
338         printf("%s", commands_help);
339         return 0;
340 }
341
342
343 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
344                                    char *argv[])
345 {
346         printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
347         return 0;
348 }
349
350
351 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
352 {
353         hostapd_cli_quit = 1;
354         return 0;
355 }
356
357
358 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
359 {
360         char cmd[256];
361         if (argc != 1) {
362                 printf("Invalid LEVEL command: needs one argument (debug "
363                        "level)\n");
364                 return 0;
365         }
366         snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
367         return wpa_ctrl_command(ctrl, cmd);
368 }
369
370
371 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
372 {
373         struct dirent *dent;
374         DIR *dir;
375
376         dir = opendir(ctrl_iface_dir);
377         if (dir == NULL) {
378                 printf("Control interface directory '%s' could not be "
379                        "openned.\n", ctrl_iface_dir);
380                 return;
381         }
382
383         printf("Available interfaces:\n");
384         while ((dent = readdir(dir))) {
385                 if (strcmp(dent->d_name, ".") == 0 ||
386                     strcmp(dent->d_name, "..") == 0)
387                         continue;
388                 printf("%s\n", dent->d_name);
389         }
390         closedir(dir);
391 }
392
393
394 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
395                                      char *argv[])
396 {
397         if (argc < 1) {
398                 hostapd_cli_list_interfaces(ctrl);
399                 return 0;
400         }
401
402         hostapd_cli_close_connection();
403         free(ctrl_ifname);
404         ctrl_ifname = strdup(argv[0]);
405
406         if (hostapd_cli_open_connection(ctrl_ifname)) {
407                 printf("Connected to interface '%s.\n", ctrl_ifname);
408                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
409                         hostapd_cli_attached = 1;
410                 } else {
411                         printf("Warning: Failed to attach to "
412                                "hostapd.\n");
413                 }
414         } else {
415                 printf("Could not connect to interface '%s' - re-trying\n",
416                         ctrl_ifname);
417         }
418         return 0;
419 }
420
421
422 struct hostapd_cli_cmd {
423         const char *cmd;
424         int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
425 };
426
427 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
428         { "ping", hostapd_cli_cmd_ping },
429         { "mib", hostapd_cli_cmd_mib },
430         { "sta", hostapd_cli_cmd_sta },
431         { "all_sta", hostapd_cli_cmd_all_sta },
432         { "new_sta", hostapd_cli_cmd_new_sta },
433 #ifdef CONFIG_IEEE80211W
434         { "sa_query", hostapd_cli_cmd_sa_query },
435 #endif /* CONFIG_IEEE80211W */
436 #ifdef CONFIG_WPS
437         { "wps_pin", hostapd_cli_cmd_wps_pin },
438         { "wps_pbc", hostapd_cli_cmd_wps_pbc },
439 #endif /* CONFIG_WPS */
440         { "help", hostapd_cli_cmd_help },
441         { "interface", hostapd_cli_cmd_interface },
442         { "level", hostapd_cli_cmd_level },
443         { "license", hostapd_cli_cmd_license },
444         { "quit", hostapd_cli_cmd_quit },
445         { NULL, NULL }
446 };
447
448
449 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
450 {
451         struct hostapd_cli_cmd *cmd, *match = NULL;
452         int count;
453
454         count = 0;
455         cmd = hostapd_cli_commands;
456         while (cmd->cmd) {
457                 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
458                         match = cmd;
459                         count++;
460                 }
461                 cmd++;
462         }
463
464         if (count > 1) {
465                 printf("Ambiguous command '%s'; possible commands:", argv[0]);
466                 cmd = hostapd_cli_commands;
467                 while (cmd->cmd) {
468                         if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
469                             0) {
470                                 printf(" %s", cmd->cmd);
471                         }
472                         cmd++;
473                 }
474                 printf("\n");
475         } else if (count == 0) {
476                 printf("Unknown command '%s'\n", argv[0]);
477         } else {
478                 match->handler(ctrl, argc - 1, &argv[1]);
479         }
480 }
481
482
483 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read)
484 {
485         int first = 1;
486         if (ctrl_conn == NULL)
487                 return;
488         while (wpa_ctrl_pending(ctrl)) {
489                 char buf[256];
490                 size_t len = sizeof(buf) - 1;
491                 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
492                         buf[len] = '\0';
493                         if (in_read && first)
494                                 printf("\n");
495                         first = 0;
496                         printf("%s\n", buf);
497                 } else {
498                         printf("Could not read pending message.\n");
499                         break;
500                 }
501         }
502 }
503
504
505 static void hostapd_cli_interactive(void)
506 {
507         const int max_args = 10;
508         char cmd[256], *res, *argv[max_args], *pos;
509         int argc;
510
511         printf("\nInteractive mode\n\n");
512
513         do {
514                 hostapd_cli_recv_pending(ctrl_conn, 0);
515                 printf("> ");
516                 alarm(ping_interval);
517                 res = fgets(cmd, sizeof(cmd), stdin);
518                 alarm(0);
519                 if (res == NULL)
520                         break;
521                 pos = cmd;
522                 while (*pos != '\0') {
523                         if (*pos == '\n') {
524                                 *pos = '\0';
525                                 break;
526                         }
527                         pos++;
528                 }
529                 argc = 0;
530                 pos = cmd;
531                 for (;;) {
532                         while (*pos == ' ')
533                                 pos++;
534                         if (*pos == '\0')
535                                 break;
536                         argv[argc] = pos;
537                         argc++;
538                         if (argc == max_args)
539                                 break;
540                         while (*pos != '\0' && *pos != ' ')
541                                 pos++;
542                         if (*pos == ' ')
543                                 *pos++ = '\0';
544                 }
545                 if (argc)
546                         wpa_request(ctrl_conn, argc, argv);
547         } while (!hostapd_cli_quit);
548 }
549
550
551 static void hostapd_cli_terminate(int sig)
552 {
553         hostapd_cli_close_connection();
554         exit(0);
555 }
556
557
558 static void hostapd_cli_alarm(int sig)
559 {
560         if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
561                 printf("Connection to hostapd lost - trying to reconnect\n");
562                 hostapd_cli_close_connection();
563         }
564         if (!ctrl_conn) {
565                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
566                 if (ctrl_conn) {
567                         printf("Connection to hostapd re-established\n");
568                         if (wpa_ctrl_attach(ctrl_conn) == 0) {
569                                 hostapd_cli_attached = 1;
570                         } else {
571                                 printf("Warning: Failed to attach to "
572                                        "hostapd.\n");
573                         }
574                 }
575         }
576         if (ctrl_conn)
577                 hostapd_cli_recv_pending(ctrl_conn, 1);
578         alarm(ping_interval);
579 }
580
581
582 int main(int argc, char *argv[])
583 {
584         int interactive;
585         int warning_displayed = 0;
586         int c;
587
588         for (;;) {
589                 c = getopt(argc, argv, "hG:i:p:v");
590                 if (c < 0)
591                         break;
592                 switch (c) {
593                 case 'G':
594                         ping_interval = atoi(optarg);
595                         break;
596                 case 'h':
597                         usage();
598                         return 0;
599                 case 'v':
600                         printf("%s\n", hostapd_cli_version);
601                         return 0;
602                 case 'i':
603                         free(ctrl_ifname);
604                         ctrl_ifname = strdup(optarg);
605                         break;
606                 case 'p':
607                         ctrl_iface_dir = optarg;
608                         break;
609                 default:
610                         usage();
611                         return -1;
612                 }
613         }
614
615         interactive = argc == optind;
616
617         if (interactive) {
618                 printf("%s\n\n%s\n\n", hostapd_cli_version,
619                        hostapd_cli_license);
620         }
621
622         for (;;) {
623                 if (ctrl_ifname == NULL) {
624                         struct dirent *dent;
625                         DIR *dir = opendir(ctrl_iface_dir);
626                         if (dir) {
627                                 while ((dent = readdir(dir))) {
628                                         if (strcmp(dent->d_name, ".") == 0 ||
629                                             strcmp(dent->d_name, "..") == 0)
630                                                 continue;
631                                         printf("Selected interface '%s'\n",
632                                                dent->d_name);
633                                         ctrl_ifname = strdup(dent->d_name);
634                                         break;
635                                 }
636                                 closedir(dir);
637                         }
638                 }
639                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
640                 if (ctrl_conn) {
641                         if (warning_displayed)
642                                 printf("Connection established.\n");
643                         break;
644                 }
645
646                 if (!interactive) {
647                         perror("Failed to connect to hostapd - "
648                                "wpa_ctrl_open");
649                         return -1;
650                 }
651
652                 if (!warning_displayed) {
653                         printf("Could not connect to hostapd - re-trying\n");
654                         warning_displayed = 1;
655                 }
656                 sleep(1);
657                 continue;
658         }
659
660         signal(SIGINT, hostapd_cli_terminate);
661         signal(SIGTERM, hostapd_cli_terminate);
662         signal(SIGALRM, hostapd_cli_alarm);
663
664         if (interactive) {
665                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
666                         hostapd_cli_attached = 1;
667                 } else {
668                         printf("Warning: Failed to attach to hostapd.\n");
669                 }
670                 hostapd_cli_interactive();
671         } else
672                 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
673
674         free(ctrl_ifname);
675         hostapd_cli_close_connection();
676         return 0;
677 }