]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/hostapd/hostapd_cli.c
This commit was generated by cvs2svn to compensate for changes in r155290,
[FreeBSD/FreeBSD.git] / contrib / hostapd / 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 "hostapd_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 hostapd_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         printf("hostapd_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hv] "
104                "[command..]\n"
105                "  -h = help (show this usage text)\n"
106                "  -v = shown version information\n"
107                "  default path: /var/run/hostapd\n"
108                "  default interface: first interface found in socket path\n"
109                "%s",
110                commands_help);
111 }
112
113
114 static struct hostapd_ctrl * hostapd_cli_open_connection(const char *ifname)
115 {
116         char *cfile;
117         int flen;
118
119         if (ifname == NULL)
120                 return NULL;
121
122         flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
123         cfile = malloc(flen);
124         if (cfile == NULL)
125                 return NULL;
126         snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
127
128         ctrl_conn = hostapd_ctrl_open(cfile);
129         free(cfile);
130         return ctrl_conn;
131 }
132
133
134 static void hostapd_cli_close_connection(void)
135 {
136         if (ctrl_conn == NULL)
137                 return;
138
139         if (hostapd_cli_attached) {
140                 hostapd_ctrl_detach(ctrl_conn);
141                 hostapd_cli_attached = 0;
142         }
143         hostapd_ctrl_close(ctrl_conn);
144         ctrl_conn = NULL;
145 }
146
147
148 static void hostapd_cli_msg_cb(char *msg, size_t len)
149 {
150         printf("%s\n", msg);
151 }
152
153
154 static int _hostapd_ctrl_command(struct hostapd_ctrl *ctrl, char *cmd,
155                                  int print)
156 {
157         char buf[4096];
158         size_t len;
159         int ret;
160
161         if (ctrl_conn == NULL) {
162                 printf("Not connected to hostapd - command dropped.\n");
163                 return -1;
164         }
165         len = sizeof(buf) - 1;
166         ret = hostapd_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
167                                hostapd_cli_msg_cb);
168         if (ret == -2) {
169                 printf("'%s' command timed out.\n", cmd);
170                 return -2;
171         } else if (ret < 0) {
172                 printf("'%s' command failed.\n", cmd);
173                 return -1;
174         }
175         if (print) {
176                 buf[len] = '\0';
177                 printf("%s", buf);
178         }
179         return 0;
180 }
181
182
183 static inline int hostapd_ctrl_command(struct hostapd_ctrl *ctrl, char *cmd)
184 {
185         return _hostapd_ctrl_command(ctrl, cmd, 1);
186 }
187
188
189 static int hostapd_cli_cmd_ping(struct hostapd_ctrl *ctrl, int argc,
190                                 char *argv[])
191 {
192         return hostapd_ctrl_command(ctrl, "PING");
193 }
194
195
196 static int hostapd_cli_cmd_mib(struct hostapd_ctrl *ctrl, int argc,
197                                char *argv[])
198 {
199         return hostapd_ctrl_command(ctrl, "MIB");
200 }
201
202
203 static int hostapd_cli_cmd_sta(struct hostapd_ctrl *ctrl, int argc,
204                                char *argv[])
205 {
206         char buf[64];
207         if (argc != 1) {
208                 printf("Invalid 'sta' command - exactly one argument, STA "
209                        "address, is required.\n");
210                 return -1;
211         }
212         snprintf(buf, sizeof(buf), "STA %s", argv[0]);
213         return hostapd_ctrl_command(ctrl, buf);
214 }
215
216
217 static int hostapd_ctrl_command_sta(struct hostapd_ctrl *ctrl, char *cmd,
218                                     char *addr, size_t addr_len)
219 {
220         char buf[4096], *pos;
221         size_t len;
222         int ret;
223
224         if (ctrl_conn == NULL) {
225                 printf("Not connected to hostapd - command dropped.\n");
226                 return -1;
227         }
228         len = sizeof(buf) - 1;
229         ret = hostapd_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
230                                hostapd_cli_msg_cb);
231         if (ret == -2) {
232                 printf("'%s' command timed out.\n", cmd);
233                 return -2;
234         } else if (ret < 0) {
235                 printf("'%s' command failed.\n", cmd);
236                 return -1;
237         }
238
239         buf[len] = '\0';
240         if (memcmp(buf, "FAIL", 4) == 0)
241                 return -1;
242         printf("%s", buf);
243
244         pos = buf;
245         while (*pos != '\0' && *pos != '\n')
246                 pos++;
247         *pos = '\0';
248         snprintf(addr, addr_len, "%s", buf);
249         return 0;
250 }
251
252
253 static int hostapd_cli_cmd_all_sta(struct hostapd_ctrl *ctrl, int argc,
254                                     char *argv[])
255 {
256         char addr[32], cmd[64];
257
258         if (hostapd_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
259                 return 0;
260         do {
261                 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
262         } while (hostapd_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
263
264         return -1;
265 }
266
267
268 static int hostapd_cli_cmd_help(struct hostapd_ctrl *ctrl, int argc,
269                                 char *argv[])
270 {
271         printf("%s", commands_help);
272         return 0;
273 }
274
275
276 static int hostapd_cli_cmd_license(struct hostapd_ctrl *ctrl, int argc,
277                                    char *argv[])
278 {
279         printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
280         return 0;
281 }
282
283
284 static int hostapd_cli_cmd_quit(struct hostapd_ctrl *ctrl, int argc,
285                                 char *argv[])
286 {
287         hostapd_cli_quit = 1;
288         return 0;
289 }
290
291
292 static int hostapd_cli_cmd_level(struct hostapd_ctrl *ctrl, int argc,
293                                  char *argv[])
294 {
295         char cmd[256];
296         if (argc != 1) {
297                 printf("Invalid LEVEL command: needs one argument (debug "
298                        "level)\n");
299                 return 0;
300         }
301         snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
302         return hostapd_ctrl_command(ctrl, cmd);
303 }
304
305
306 static void hostapd_cli_list_interfaces(struct hostapd_ctrl *ctrl)
307 {
308         struct dirent *dent;
309         DIR *dir;
310
311         dir = opendir(ctrl_iface_dir);
312         if (dir == NULL) {
313                 printf("Control interface directory '%s' could not be "
314                        "openned.\n", ctrl_iface_dir);
315                 return;
316         }
317
318         printf("Available interfaces:\n");
319         while ((dent = readdir(dir))) {
320                 if (strcmp(dent->d_name, ".") == 0 ||
321                     strcmp(dent->d_name, "..") == 0)
322                         continue;
323                 printf("%s\n", dent->d_name);
324         }
325         closedir(dir);
326 }
327
328
329 static int hostapd_cli_cmd_interface(struct hostapd_ctrl *ctrl, int argc,
330                                      char *argv[])
331 {
332         if (argc < 1) {
333                 hostapd_cli_list_interfaces(ctrl);
334                 return 0;
335         }
336
337         hostapd_cli_close_connection();
338         free(ctrl_ifname);
339         ctrl_ifname = strdup(argv[0]);
340
341         if (hostapd_cli_open_connection(ctrl_ifname)) {
342                 printf("Connected to interface '%s.\n", ctrl_ifname);
343                 if (hostapd_ctrl_attach(ctrl_conn) == 0) {
344                         hostapd_cli_attached = 1;
345                 } else {
346                         printf("Warning: Failed to attach to "
347                                "hostapd.\n");
348                 }
349         } else {
350                 printf("Could not connect to interface '%s' - re-trying\n",
351                         ctrl_ifname);
352         }
353         return 0;
354 }
355
356
357 struct hostapd_cli_cmd {
358         const char *cmd;
359         int (*handler)(struct hostapd_ctrl *ctrl, int argc, char *argv[]);
360 };
361
362 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
363         { "ping", hostapd_cli_cmd_ping },
364         { "mib", hostapd_cli_cmd_mib },
365         { "sta", hostapd_cli_cmd_sta },
366         { "all_sta", hostapd_cli_cmd_all_sta },
367         { "help", hostapd_cli_cmd_help },
368         { "interface", hostapd_cli_cmd_interface },
369         { "level", hostapd_cli_cmd_level },
370         { "license", hostapd_cli_cmd_license },
371         { "quit", hostapd_cli_cmd_quit },
372         { NULL, NULL }
373 };
374
375
376 static void wpa_request(struct hostapd_ctrl *ctrl, int argc, char *argv[])
377 {
378         struct hostapd_cli_cmd *cmd, *match = NULL;
379         int count;
380
381         count = 0;
382         cmd = hostapd_cli_commands;
383         while (cmd->cmd) {
384                 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
385                         match = cmd;
386                         count++;
387                 }
388                 cmd++;
389         }
390
391         if (count > 1) {
392                 printf("Ambiguous command '%s'; possible commands:", argv[0]);
393                 cmd = hostapd_cli_commands;
394                 while (cmd->cmd) {
395                         if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
396                             0) {
397                                 printf(" %s", cmd->cmd);
398                         }
399                         cmd++;
400                 }
401                 printf("\n");
402         } else if (count == 0) {
403                 printf("Unknown command '%s'\n", argv[0]);
404         } else {
405                 match->handler(ctrl, argc - 1, &argv[1]);
406         }
407 }
408
409
410 static void hostapd_cli_recv_pending(struct hostapd_ctrl *ctrl, int in_read)
411 {
412         int first = 1;
413         if (ctrl_conn == NULL)
414                 return;
415         while (hostapd_ctrl_pending(ctrl)) {
416                 char buf[256];
417                 size_t len = sizeof(buf) - 1;
418                 if (hostapd_ctrl_recv(ctrl, buf, &len) == 0) {
419                         buf[len] = '\0';
420                         if (in_read && first)
421                                 printf("\n");
422                         first = 0;
423                         printf("%s\n", buf);
424                 } else {
425                         printf("Could not read pending message.\n");
426                         break;
427                 }
428         }
429 }
430
431
432 static void hostapd_cli_interactive(void)
433 {
434         const int max_args = 10;
435         char cmd[256], *res, *argv[max_args], *pos;
436         int argc;
437
438         printf("\nInteractive mode\n\n");
439
440         do {
441                 hostapd_cli_recv_pending(ctrl_conn, 0);
442                 printf("> ");
443                 alarm(1);
444                 res = fgets(cmd, sizeof(cmd), stdin);
445                 alarm(0);
446                 if (res == NULL)
447                         break;
448                 pos = cmd;
449                 while (*pos != '\0') {
450                         if (*pos == '\n') {
451                                 *pos = '\0';
452                                 break;
453                         }
454                         pos++;
455                 }
456                 argc = 0;
457                 pos = cmd;
458                 for (;;) {
459                         while (*pos == ' ')
460                                 pos++;
461                         if (*pos == '\0')
462                                 break;
463                         argv[argc] = pos;
464                         argc++;
465                         if (argc == max_args)
466                                 break;
467                         while (*pos != '\0' && *pos != ' ')
468                                 pos++;
469                         if (*pos == ' ')
470                                 *pos++ = '\0';
471                 }
472                 if (argc)
473                         wpa_request(ctrl_conn, argc, argv);
474         } while (!hostapd_cli_quit);
475 }
476
477
478 static void hostapd_cli_terminate(int sig)
479 {
480         hostapd_cli_close_connection();
481         exit(0);
482 }
483
484
485 static void hostapd_cli_alarm(int sig)
486 {
487         if (ctrl_conn && _hostapd_ctrl_command(ctrl_conn, "PING", 0)) {
488                 printf("Connection to hostapd lost - trying to reconnect\n");
489                 hostapd_cli_close_connection();
490         }
491         if (!ctrl_conn) {
492                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
493                 if (ctrl_conn) {
494                         printf("Connection to hostapd re-established\n");
495                         if (hostapd_ctrl_attach(ctrl_conn) == 0) {
496                                 hostapd_cli_attached = 1;
497                         } else {
498                                 printf("Warning: Failed to attach to "
499                                        "hostapd.\n");
500                         }
501                 }
502         }
503         if (ctrl_conn)
504                 hostapd_cli_recv_pending(ctrl_conn, 1);
505         alarm(1);
506 }
507
508
509 int main(int argc, char *argv[])
510 {
511         int interactive;
512         int warning_displayed = 0;
513         int c;
514
515         for (;;) {
516                 c = getopt(argc, argv, "hi:p:v");
517                 if (c < 0)
518                         break;
519                 switch (c) {
520                 case 'h':
521                         usage();
522                         return 0;
523                 case 'v':
524                         printf("%s\n", hostapd_cli_version);
525                         return 0;
526                 case 'i':
527                         ctrl_ifname = strdup(optarg);
528                         break;
529                 case 'p':
530                         ctrl_iface_dir = optarg;
531                         break;
532                 default:
533                         usage();
534                         return -1;
535                 }
536         }
537
538         interactive = argc == optind;
539
540         if (interactive) {
541                 printf("%s\n\n%s\n\n", hostapd_cli_version,
542                        hostapd_cli_license);
543         }
544
545         for (;;) {
546                 if (ctrl_ifname == NULL) {
547                         struct dirent *dent;
548                         DIR *dir = opendir(ctrl_iface_dir);
549                         if (dir) {
550                                 while ((dent = readdir(dir))) {
551                                         if (strcmp(dent->d_name, ".") == 0 ||
552                                             strcmp(dent->d_name, "..") == 0)
553                                                 continue;
554                                         printf("Selected interface '%s'\n",
555                                                dent->d_name);
556                                         ctrl_ifname = strdup(dent->d_name);
557                                         break;
558                                 }
559                                 closedir(dir);
560                         }
561                 }
562                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
563                 if (ctrl_conn) {
564                         if (warning_displayed)
565                                 printf("Connection established.\n");
566                         break;
567                 }
568
569                 if (!interactive) {
570                         perror("Failed to connect to hostapd - "
571                                "hostapd_ctrl_open");
572                         return -1;
573                 }
574
575                 if (!warning_displayed) {
576                         printf("Could not connect to hostapd - re-trying\n");
577                         warning_displayed = 1;
578                 }
579                 sleep(1);
580                 continue;
581         }
582
583         signal(SIGINT, hostapd_cli_terminate);
584         signal(SIGTERM, hostapd_cli_terminate);
585         signal(SIGALRM, hostapd_cli_alarm);
586
587         if (interactive) {
588                 if (hostapd_ctrl_attach(ctrl_conn) == 0) {
589                         hostapd_cli_attached = 1;
590                 } else {
591                         printf("Warning: Failed to attach to hostapd.\n");
592                 }
593                 hostapd_cli_interactive();
594         } else
595                 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
596
597         free(ctrl_ifname);
598         hostapd_cli_close_connection();
599         return 0;
600 }