]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/wpa/hostapd/hostapd_cli.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / contrib / wpa / 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> 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 - exactly two arguments, "
265                        "UUID and PIN, are required.\n");
266                 return -1;
267         }
268         snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
269         return wpa_ctrl_command(ctrl, buf);
270 }
271
272
273 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
274                                    char *argv[])
275 {
276         return wpa_ctrl_command(ctrl, "WPS_PBC");
277 }
278 #endif /* CONFIG_WPS */
279
280
281 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
282                                 char *addr, size_t addr_len)
283 {
284         char buf[4096], *pos;
285         size_t len;
286         int ret;
287
288         if (ctrl_conn == NULL) {
289                 printf("Not connected to hostapd - command dropped.\n");
290                 return -1;
291         }
292         len = sizeof(buf) - 1;
293         ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
294                                hostapd_cli_msg_cb);
295         if (ret == -2) {
296                 printf("'%s' command timed out.\n", cmd);
297                 return -2;
298         } else if (ret < 0) {
299                 printf("'%s' command failed.\n", cmd);
300                 return -1;
301         }
302
303         buf[len] = '\0';
304         if (memcmp(buf, "FAIL", 4) == 0)
305                 return -1;
306         printf("%s", buf);
307
308         pos = buf;
309         while (*pos != '\0' && *pos != '\n')
310                 pos++;
311         *pos = '\0';
312         os_strlcpy(addr, buf, addr_len);
313         return 0;
314 }
315
316
317 static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
318                                    char *argv[])
319 {
320         char addr[32], cmd[64];
321
322         if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
323                 return 0;
324         do {
325                 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
326         } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
327
328         return -1;
329 }
330
331
332 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
333 {
334         printf("%s", commands_help);
335         return 0;
336 }
337
338
339 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
340                                    char *argv[])
341 {
342         printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
343         return 0;
344 }
345
346
347 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
348 {
349         hostapd_cli_quit = 1;
350         return 0;
351 }
352
353
354 static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
355 {
356         char cmd[256];
357         if (argc != 1) {
358                 printf("Invalid LEVEL command: needs one argument (debug "
359                        "level)\n");
360                 return 0;
361         }
362         snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
363         return wpa_ctrl_command(ctrl, cmd);
364 }
365
366
367 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
368 {
369         struct dirent *dent;
370         DIR *dir;
371
372         dir = opendir(ctrl_iface_dir);
373         if (dir == NULL) {
374                 printf("Control interface directory '%s' could not be "
375                        "openned.\n", ctrl_iface_dir);
376                 return;
377         }
378
379         printf("Available interfaces:\n");
380         while ((dent = readdir(dir))) {
381                 if (strcmp(dent->d_name, ".") == 0 ||
382                     strcmp(dent->d_name, "..") == 0)
383                         continue;
384                 printf("%s\n", dent->d_name);
385         }
386         closedir(dir);
387 }
388
389
390 static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
391                                      char *argv[])
392 {
393         if (argc < 1) {
394                 hostapd_cli_list_interfaces(ctrl);
395                 return 0;
396         }
397
398         hostapd_cli_close_connection();
399         free(ctrl_ifname);
400         ctrl_ifname = strdup(argv[0]);
401
402         if (hostapd_cli_open_connection(ctrl_ifname)) {
403                 printf("Connected to interface '%s.\n", ctrl_ifname);
404                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
405                         hostapd_cli_attached = 1;
406                 } else {
407                         printf("Warning: Failed to attach to "
408                                "hostapd.\n");
409                 }
410         } else {
411                 printf("Could not connect to interface '%s' - re-trying\n",
412                         ctrl_ifname);
413         }
414         return 0;
415 }
416
417
418 struct hostapd_cli_cmd {
419         const char *cmd;
420         int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
421 };
422
423 static struct hostapd_cli_cmd hostapd_cli_commands[] = {
424         { "ping", hostapd_cli_cmd_ping },
425         { "mib", hostapd_cli_cmd_mib },
426         { "sta", hostapd_cli_cmd_sta },
427         { "all_sta", hostapd_cli_cmd_all_sta },
428         { "new_sta", hostapd_cli_cmd_new_sta },
429 #ifdef CONFIG_IEEE80211W
430         { "sa_query", hostapd_cli_cmd_sa_query },
431 #endif /* CONFIG_IEEE80211W */
432 #ifdef CONFIG_WPS
433         { "wps_pin", hostapd_cli_cmd_wps_pin },
434         { "wps_pbc", hostapd_cli_cmd_wps_pbc },
435 #endif /* CONFIG_WPS */
436         { "help", hostapd_cli_cmd_help },
437         { "interface", hostapd_cli_cmd_interface },
438         { "level", hostapd_cli_cmd_level },
439         { "license", hostapd_cli_cmd_license },
440         { "quit", hostapd_cli_cmd_quit },
441         { NULL, NULL }
442 };
443
444
445 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
446 {
447         struct hostapd_cli_cmd *cmd, *match = NULL;
448         int count;
449
450         count = 0;
451         cmd = hostapd_cli_commands;
452         while (cmd->cmd) {
453                 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
454                         match = cmd;
455                         count++;
456                 }
457                 cmd++;
458         }
459
460         if (count > 1) {
461                 printf("Ambiguous command '%s'; possible commands:", argv[0]);
462                 cmd = hostapd_cli_commands;
463                 while (cmd->cmd) {
464                         if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
465                             0) {
466                                 printf(" %s", cmd->cmd);
467                         }
468                         cmd++;
469                 }
470                 printf("\n");
471         } else if (count == 0) {
472                 printf("Unknown command '%s'\n", argv[0]);
473         } else {
474                 match->handler(ctrl, argc - 1, &argv[1]);
475         }
476 }
477
478
479 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read)
480 {
481         int first = 1;
482         if (ctrl_conn == NULL)
483                 return;
484         while (wpa_ctrl_pending(ctrl)) {
485                 char buf[256];
486                 size_t len = sizeof(buf) - 1;
487                 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
488                         buf[len] = '\0';
489                         if (in_read && first)
490                                 printf("\n");
491                         first = 0;
492                         printf("%s\n", buf);
493                 } else {
494                         printf("Could not read pending message.\n");
495                         break;
496                 }
497         }
498 }
499
500
501 static void hostapd_cli_interactive(void)
502 {
503         const int max_args = 10;
504         char cmd[256], *res, *argv[max_args], *pos;
505         int argc;
506
507         printf("\nInteractive mode\n\n");
508
509         do {
510                 hostapd_cli_recv_pending(ctrl_conn, 0);
511                 printf("> ");
512                 alarm(ping_interval);
513                 res = fgets(cmd, sizeof(cmd), stdin);
514                 alarm(0);
515                 if (res == NULL)
516                         break;
517                 pos = cmd;
518                 while (*pos != '\0') {
519                         if (*pos == '\n') {
520                                 *pos = '\0';
521                                 break;
522                         }
523                         pos++;
524                 }
525                 argc = 0;
526                 pos = cmd;
527                 for (;;) {
528                         while (*pos == ' ')
529                                 pos++;
530                         if (*pos == '\0')
531                                 break;
532                         argv[argc] = pos;
533                         argc++;
534                         if (argc == max_args)
535                                 break;
536                         while (*pos != '\0' && *pos != ' ')
537                                 pos++;
538                         if (*pos == ' ')
539                                 *pos++ = '\0';
540                 }
541                 if (argc)
542                         wpa_request(ctrl_conn, argc, argv);
543         } while (!hostapd_cli_quit);
544 }
545
546
547 static void hostapd_cli_terminate(int sig)
548 {
549         hostapd_cli_close_connection();
550         exit(0);
551 }
552
553
554 static void hostapd_cli_alarm(int sig)
555 {
556         if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
557                 printf("Connection to hostapd lost - trying to reconnect\n");
558                 hostapd_cli_close_connection();
559         }
560         if (!ctrl_conn) {
561                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
562                 if (ctrl_conn) {
563                         printf("Connection to hostapd re-established\n");
564                         if (wpa_ctrl_attach(ctrl_conn) == 0) {
565                                 hostapd_cli_attached = 1;
566                         } else {
567                                 printf("Warning: Failed to attach to "
568                                        "hostapd.\n");
569                         }
570                 }
571         }
572         if (ctrl_conn)
573                 hostapd_cli_recv_pending(ctrl_conn, 1);
574         alarm(ping_interval);
575 }
576
577
578 int main(int argc, char *argv[])
579 {
580         int interactive;
581         int warning_displayed = 0;
582         int c;
583
584         for (;;) {
585                 c = getopt(argc, argv, "hG:i:p:v");
586                 if (c < 0)
587                         break;
588                 switch (c) {
589                 case 'G':
590                         ping_interval = atoi(optarg);
591                         break;
592                 case 'h':
593                         usage();
594                         return 0;
595                 case 'v':
596                         printf("%s\n", hostapd_cli_version);
597                         return 0;
598                 case 'i':
599                         free(ctrl_ifname);
600                         ctrl_ifname = strdup(optarg);
601                         break;
602                 case 'p':
603                         ctrl_iface_dir = optarg;
604                         break;
605                 default:
606                         usage();
607                         return -1;
608                 }
609         }
610
611         interactive = argc == optind;
612
613         if (interactive) {
614                 printf("%s\n\n%s\n\n", hostapd_cli_version,
615                        hostapd_cli_license);
616         }
617
618         for (;;) {
619                 if (ctrl_ifname == NULL) {
620                         struct dirent *dent;
621                         DIR *dir = opendir(ctrl_iface_dir);
622                         if (dir) {
623                                 while ((dent = readdir(dir))) {
624                                         if (strcmp(dent->d_name, ".") == 0 ||
625                                             strcmp(dent->d_name, "..") == 0)
626                                                 continue;
627                                         printf("Selected interface '%s'\n",
628                                                dent->d_name);
629                                         ctrl_ifname = strdup(dent->d_name);
630                                         break;
631                                 }
632                                 closedir(dir);
633                         }
634                 }
635                 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
636                 if (ctrl_conn) {
637                         if (warning_displayed)
638                                 printf("Connection established.\n");
639                         break;
640                 }
641
642                 if (!interactive) {
643                         perror("Failed to connect to hostapd - "
644                                "wpa_ctrl_open");
645                         return -1;
646                 }
647
648                 if (!warning_displayed) {
649                         printf("Could not connect to hostapd - re-trying\n");
650                         warning_displayed = 1;
651                 }
652                 sleep(1);
653                 continue;
654         }
655
656         signal(SIGINT, hostapd_cli_terminate);
657         signal(SIGTERM, hostapd_cli_terminate);
658         signal(SIGALRM, hostapd_cli_alarm);
659
660         if (interactive) {
661                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
662                         hostapd_cli_attached = 1;
663                 } else {
664                         printf("Warning: Failed to attach to hostapd.\n");
665                 }
666                 hostapd_cli_interactive();
667         } else
668                 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
669
670         free(ctrl_ifname);
671         hostapd_cli_close_connection();
672         return 0;
673 }