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