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