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