blob: 8caca4f6a4684cc63082406b3b8b9634a1358d16 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * hostapd - command line interface for hostapd daemon
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003 * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "includes.h"
10#include <dirent.h>
11
12#include "common/wpa_ctrl.h"
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080013#include "utils/common.h"
14#include "utils/eloop.h"
15#include "utils/edit.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070016#include "common/version.h"
17
18
19static const char *hostapd_cli_version =
20"hostapd_cli v" VERSION_STR "\n"
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080021"Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> and contributors";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070022
23
24static const char *hostapd_cli_license =
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -080025"This software may be distributed under the terms of the BSD license.\n"
26"See README for more details.\n";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070027
28static const char *hostapd_cli_full_license =
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -080029"This software may be distributed under the terms of the BSD license.\n"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070030"\n"
31"Redistribution and use in source and binary forms, with or without\n"
32"modification, are permitted provided that the following conditions are\n"
33"met:\n"
34"\n"
35"1. Redistributions of source code must retain the above copyright\n"
36" notice, this list of conditions and the following disclaimer.\n"
37"\n"
38"2. Redistributions in binary form must reproduce the above copyright\n"
39" notice, this list of conditions and the following disclaimer in the\n"
40" documentation and/or other materials provided with the distribution.\n"
41"\n"
42"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
43" names of its contributors may be used to endorse or promote products\n"
44" derived from this software without specific prior written permission.\n"
45"\n"
46"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
47"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
48"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
49"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
50"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
51"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
52"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
53"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
54"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
55"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
56"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
57"\n";
58
59static const char *commands_help =
60"Commands:\n"
61" mib get MIB variables (dot1x, dot11, radius)\n"
62" sta <addr> get MIB variables for one station\n"
63" all_sta get MIB variables for all stations\n"
64" new_sta <addr> add a new station\n"
65" deauthenticate <addr> deauthenticate a station\n"
66" disassociate <addr> disassociate a station\n"
67#ifdef CONFIG_IEEE80211W
68" sa_query <addr> send SA Query to a station\n"
69#endif /* CONFIG_IEEE80211W */
70#ifdef CONFIG_WPS
71" wps_pin <uuid> <pin> [timeout] [addr] add WPS Enrollee PIN\n"
72" wps_check_pin <PIN> verify PIN checksum\n"
73" wps_pbc indicate button pushed to initiate PBC\n"
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070074" wps_cancel cancel the pending WPS operation\n"
Dmitry Shmidt04949592012-07-19 12:16:46 -070075#ifdef CONFIG_WPS_NFC
76" wps_nfc_tag_read <hexdump> report read NFC tag with WPS data\n"
77" wps_nfc_config_token <WPS/NDEF> build NFC configuration token\n"
78" wps_nfc_token <WPS/NDEF/enable/disable> manager NFC password token\n"
79#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070080" wps_ap_pin <cmd> [params..] enable/disable AP PIN\n"
81" wps_config <SSID> <auth> <encr> <key> configure AP\n"
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070082" wps_get_status show current WPS status\n"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070083#endif /* CONFIG_WPS */
84" get_config show current configuration\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
91static struct wpa_ctrl *ctrl_conn;
92static int hostapd_cli_quit = 0;
93static int hostapd_cli_attached = 0;
Jeff Johnson205f2142012-09-03 22:12:17 -070094
95#ifndef CONFIG_CTRL_IFACE_DIR
96#define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd"
97#endif /* CONFIG_CTRL_IFACE_DIR */
98static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
99
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700100static char *ctrl_ifname = NULL;
101static const char *pid_file = NULL;
102static const char *action_file = NULL;
103static int ping_interval = 5;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800104static int interactive = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700105
106
107static 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>] [-hvB] "
113 "[-a<path>] \\\n"
114 " [-G<ping interval>] [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 " -a<file> run in daemon mode executing the action file "
122 "based on events\n"
123 " from hostapd\n"
124 " -B run a daemon in the background\n"
125 " -i<ifname> Interface to listen on (default: first "
126 "interface found in the\n"
127 " socket path)\n\n"
128 "%s",
129 commands_help);
130}
131
132
133static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
134{
135 char *cfile;
136 int flen;
137
138 if (ifname == NULL)
139 return NULL;
140
141 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
142 cfile = malloc(flen);
143 if (cfile == NULL)
144 return NULL;
145 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
146
147 ctrl_conn = wpa_ctrl_open(cfile);
148 free(cfile);
149 return ctrl_conn;
150}
151
152
153static void hostapd_cli_close_connection(void)
154{
155 if (ctrl_conn == NULL)
156 return;
157
158 if (hostapd_cli_attached) {
159 wpa_ctrl_detach(ctrl_conn);
160 hostapd_cli_attached = 0;
161 }
162 wpa_ctrl_close(ctrl_conn);
163 ctrl_conn = NULL;
164}
165
166
167static void hostapd_cli_msg_cb(char *msg, size_t len)
168{
169 printf("%s\n", msg);
170}
171
172
173static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
174{
175 char buf[4096];
176 size_t len;
177 int ret;
178
179 if (ctrl_conn == NULL) {
180 printf("Not connected to hostapd - command dropped.\n");
181 return -1;
182 }
183 len = sizeof(buf) - 1;
184 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
185 hostapd_cli_msg_cb);
186 if (ret == -2) {
187 printf("'%s' command timed out.\n", cmd);
188 return -2;
189 } else if (ret < 0) {
190 printf("'%s' command failed.\n", cmd);
191 return -1;
192 }
193 if (print) {
194 buf[len] = '\0';
195 printf("%s", buf);
196 }
197 return 0;
198}
199
200
201static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
202{
203 return _wpa_ctrl_command(ctrl, cmd, 1);
204}
205
206
207static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
208{
209 return wpa_ctrl_command(ctrl, "PING");
210}
211
212
213static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
214{
215 return wpa_ctrl_command(ctrl, "RELOG");
216}
217
218
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800219static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
220{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800221 if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
222 return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800223 return wpa_ctrl_command(ctrl, "STATUS");
224}
225
226
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700227static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
228{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800229 if (argc > 0) {
230 char buf[100];
231 os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]);
232 return wpa_ctrl_command(ctrl, buf);
233 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700234 return wpa_ctrl_command(ctrl, "MIB");
235}
236
237
238static int hostapd_cli_exec(const char *program, const char *arg1,
239 const char *arg2)
240{
241 char *cmd;
242 size_t len;
243 int res;
244 int ret = 0;
245
246 len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
247 cmd = os_malloc(len);
248 if (cmd == NULL)
249 return -1;
250 res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
251 if (res < 0 || (size_t) res >= len) {
252 os_free(cmd);
253 return -1;
254 }
255 cmd[len - 1] = '\0';
256#ifndef _WIN32_WCE
257 if (system(cmd) < 0)
258 ret = -1;
259#endif /* _WIN32_WCE */
260 os_free(cmd);
261
262 return ret;
263}
264
265
266static void hostapd_cli_action_process(char *msg, size_t len)
267{
268 const char *pos;
269
270 pos = msg;
271 if (*pos == '<') {
272 pos = os_strchr(pos, '>');
273 if (pos)
274 pos++;
275 else
276 pos = msg;
277 }
278
279 hostapd_cli_exec(action_file, ctrl_ifname, pos);
280}
281
282
283static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
284{
285 char buf[64];
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800286 if (argc < 1) {
287 printf("Invalid 'sta' command - at least one argument, STA "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700288 "address, is required.\n");
289 return -1;
290 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800291 if (argc > 1)
292 snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]);
293 else
294 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700295 return wpa_ctrl_command(ctrl, buf);
296}
297
298
299static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
300 char *argv[])
301{
302 char buf[64];
303 if (argc != 1) {
304 printf("Invalid 'new_sta' command - exactly one argument, STA "
305 "address, is required.\n");
306 return -1;
307 }
308 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
309 return wpa_ctrl_command(ctrl, buf);
310}
311
312
313static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
314 char *argv[])
315{
316 char buf[64];
317 if (argc < 1) {
318 printf("Invalid 'deauthenticate' command - exactly one "
319 "argument, STA address, is required.\n");
320 return -1;
321 }
322 if (argc > 1)
323 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
324 argv[0], argv[1]);
325 else
326 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
327 return wpa_ctrl_command(ctrl, buf);
328}
329
330
331static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
332 char *argv[])
333{
334 char buf[64];
335 if (argc < 1) {
336 printf("Invalid 'disassociate' command - exactly one "
337 "argument, STA address, is required.\n");
338 return -1;
339 }
340 if (argc > 1)
341 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
342 argv[0], argv[1]);
343 else
344 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
345 return wpa_ctrl_command(ctrl, buf);
346}
347
348
349#ifdef CONFIG_IEEE80211W
350static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
351 char *argv[])
352{
353 char buf[64];
354 if (argc != 1) {
355 printf("Invalid 'sa_query' command - exactly one argument, "
356 "STA address, is required.\n");
357 return -1;
358 }
359 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
360 return wpa_ctrl_command(ctrl, buf);
361}
362#endif /* CONFIG_IEEE80211W */
363
364
365#ifdef CONFIG_WPS
366static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
367 char *argv[])
368{
369 char buf[256];
370 if (argc < 2) {
371 printf("Invalid 'wps_pin' command - at least two arguments, "
372 "UUID and PIN, are required.\n");
373 return -1;
374 }
375 if (argc > 3)
376 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
377 argv[0], argv[1], argv[2], argv[3]);
378 else if (argc > 2)
379 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
380 argv[0], argv[1], argv[2]);
381 else
382 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
383 return wpa_ctrl_command(ctrl, buf);
384}
385
386
387static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
388 char *argv[])
389{
390 char cmd[256];
391 int res;
392
393 if (argc != 1 && argc != 2) {
394 printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
395 "- PIN to be verified\n");
396 return -1;
397 }
398
399 if (argc == 2)
400 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
401 argv[0], argv[1]);
402 else
403 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
404 argv[0]);
405 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
406 printf("Too long WPS_CHECK_PIN command.\n");
407 return -1;
408 }
409 return wpa_ctrl_command(ctrl, cmd);
410}
411
412
413static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
414 char *argv[])
415{
416 return wpa_ctrl_command(ctrl, "WPS_PBC");
417}
418
419
Dmitry Shmidt04949592012-07-19 12:16:46 -0700420static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
421 char *argv[])
422{
423 return wpa_ctrl_command(ctrl, "WPS_CANCEL");
424}
425
426
Dmitry Shmidt04949592012-07-19 12:16:46 -0700427#ifdef CONFIG_WPS_NFC
428static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
429 char *argv[])
430{
431 int ret;
432 char *buf;
433 size_t buflen;
434
435 if (argc != 1) {
436 printf("Invalid 'wps_nfc_tag_read' command - one argument "
437 "is required.\n");
438 return -1;
439 }
440
441 buflen = 18 + os_strlen(argv[0]);
442 buf = os_malloc(buflen);
443 if (buf == NULL)
444 return -1;
445 os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
446
447 ret = wpa_ctrl_command(ctrl, buf);
448 os_free(buf);
449
450 return ret;
451}
452
453
454static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
455 int argc, char *argv[])
456{
457 char cmd[64];
458 int res;
459
460 if (argc != 1) {
461 printf("Invalid 'wps_nfc_config_token' command - one argument "
462 "is required.\n");
463 return -1;
464 }
465
466 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
467 argv[0]);
468 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
469 printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
470 return -1;
471 }
472 return wpa_ctrl_command(ctrl, cmd);
473}
474
475
476static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
477 int argc, char *argv[])
478{
479 char cmd[64];
480 int res;
481
482 if (argc != 1) {
483 printf("Invalid 'wps_nfc_token' command - one argument is "
484 "required.\n");
485 return -1;
486 }
487
488 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
489 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
490 printf("Too long WPS_NFC_TOKEN command.\n");
491 return -1;
492 }
493 return wpa_ctrl_command(ctrl, cmd);
494}
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800495
496
497static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
498 int argc, char *argv[])
499{
500 char cmd[64];
501 int res;
502
503 if (argc != 2) {
504 printf("Invalid 'nfc_get_handover_sel' command - two arguments "
505 "are required.\n");
506 return -1;
507 }
508
509 res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
510 argv[0], argv[1]);
511 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
512 printf("Too long NFC_GET_HANDOVER_SEL command.\n");
513 return -1;
514 }
515 return wpa_ctrl_command(ctrl, cmd);
516}
517
Dmitry Shmidt04949592012-07-19 12:16:46 -0700518#endif /* CONFIG_WPS_NFC */
519
520
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700521static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
522 char *argv[])
523{
524 char buf[64];
525 if (argc < 1) {
526 printf("Invalid 'wps_ap_pin' command - at least one argument "
527 "is required.\n");
528 return -1;
529 }
530 if (argc > 2)
531 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
532 argv[0], argv[1], argv[2]);
533 else if (argc > 1)
534 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
535 argv[0], argv[1]);
536 else
537 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
538 return wpa_ctrl_command(ctrl, buf);
539}
540
541
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700542static int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc,
543 char *argv[])
544{
545 return wpa_ctrl_command(ctrl, "WPS_GET_STATUS");
546}
547
548
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700549static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
550 char *argv[])
551{
552 char buf[256];
553 char ssid_hex[2 * 32 + 1];
554 char key_hex[2 * 64 + 1];
555 int i;
556
557 if (argc < 1) {
558 printf("Invalid 'wps_config' command - at least two arguments "
559 "are required.\n");
560 return -1;
561 }
562
563 ssid_hex[0] = '\0';
564 for (i = 0; i < 32; i++) {
565 if (argv[0][i] == '\0')
566 break;
567 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
568 }
569
570 key_hex[0] = '\0';
571 if (argc > 3) {
572 for (i = 0; i < 64; i++) {
573 if (argv[3][i] == '\0')
574 break;
575 os_snprintf(&key_hex[i * 2], 3, "%02x",
576 argv[3][i]);
577 }
578 }
579
580 if (argc > 3)
581 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
582 ssid_hex, argv[1], argv[2], key_hex);
583 else if (argc > 2)
584 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
585 ssid_hex, argv[1], argv[2]);
586 else
587 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
588 ssid_hex, argv[1]);
589 return wpa_ctrl_command(ctrl, buf);
590}
591#endif /* CONFIG_WPS */
592
593
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800594static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
595 char *argv[])
596{
597 char buf[300];
598 int res;
599
600 if (argc < 2) {
601 printf("Invalid 'disassoc_imminent' command - two arguments "
602 "(STA addr and Disassociation Timer) are needed\n");
603 return -1;
604 }
605
606 res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
607 argv[0], argv[1]);
608 if (res < 0 || res >= (int) sizeof(buf))
609 return -1;
610 return wpa_ctrl_command(ctrl, buf);
611}
612
613
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800614static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
615 char *argv[])
616{
617 char buf[300];
618 int res;
619
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700620 if (argc < 3) {
621 printf("Invalid 'ess_disassoc' command - three arguments (STA "
622 "addr, disassoc timer, and URL) are needed\n");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800623 return -1;
624 }
625
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700626 res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
627 argv[0], argv[1], argv[2]);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800628 if (res < 0 || res >= (int) sizeof(buf))
629 return -1;
630 return wpa_ctrl_command(ctrl, buf);
631}
632
633
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700634static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
635 char *argv[])
636{
637 return wpa_ctrl_command(ctrl, "GET_CONFIG");
638}
639
640
641static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
642 char *addr, size_t addr_len)
643{
644 char buf[4096], *pos;
645 size_t len;
646 int ret;
647
648 if (ctrl_conn == NULL) {
649 printf("Not connected to hostapd - command dropped.\n");
650 return -1;
651 }
652 len = sizeof(buf) - 1;
653 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
654 hostapd_cli_msg_cb);
655 if (ret == -2) {
656 printf("'%s' command timed out.\n", cmd);
657 return -2;
658 } else if (ret < 0) {
659 printf("'%s' command failed.\n", cmd);
660 return -1;
661 }
662
663 buf[len] = '\0';
664 if (memcmp(buf, "FAIL", 4) == 0)
665 return -1;
666 printf("%s", buf);
667
668 pos = buf;
669 while (*pos != '\0' && *pos != '\n')
670 pos++;
671 *pos = '\0';
672 os_strlcpy(addr, buf, addr_len);
673 return 0;
674}
675
676
677static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
678 char *argv[])
679{
680 char addr[32], cmd[64];
681
682 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
683 return 0;
684 do {
685 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
686 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
687
688 return -1;
689}
690
691
692static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
693{
694 printf("%s", commands_help);
695 return 0;
696}
697
698
699static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
700 char *argv[])
701{
702 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
703 return 0;
704}
705
706
Dmitry Shmidt051af732013-10-22 13:52:46 -0700707static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl,
708 int argc, char *argv[])
709{
710 char buf[200];
711 int res;
712
713 if (argc != 1) {
714 printf("Invalid 'set_qos_map_set' command - "
715 "one argument (comma delimited QoS map set) "
716 "is needed\n");
717 return -1;
718 }
719
720 res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
721 if (res < 0 || res >= (int) sizeof(buf))
722 return -1;
723 return wpa_ctrl_command(ctrl, buf);
724}
725
726
727static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
728 int argc, char *argv[])
729{
730 char buf[50];
731 int res;
732
733 if (argc != 1) {
734 printf("Invalid 'send_qos_map_conf' command - "
735 "one argument (STA addr) is needed\n");
736 return -1;
737 }
738
739 res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
740 if (res < 0 || res >= (int) sizeof(buf))
741 return -1;
742 return wpa_ctrl_command(ctrl, buf);
743}
744
745
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800746static int hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc,
747 char *argv[])
748{
749 char buf[300];
750 int res;
751
752 if (argc < 2) {
753 printf("Invalid 'hs20_wnm_notif' command - two arguments (STA "
754 "addr and URL) are needed\n");
755 return -1;
756 }
757
758 res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s",
759 argv[0], argv[1]);
760 if (res < 0 || res >= (int) sizeof(buf))
761 return -1;
762 return wpa_ctrl_command(ctrl, buf);
763}
764
765
766static int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc,
767 char *argv[])
768{
769 char buf[300];
770 int res;
771
772 if (argc < 3) {
773 printf("Invalid 'hs20_deauth_req' command - at least three arguments (STA addr, Code, Re-auth Delay) are needed\n");
774 return -1;
775 }
776
777 if (argc > 3)
778 res = os_snprintf(buf, sizeof(buf),
779 "HS20_DEAUTH_REQ %s %s %s %s",
780 argv[0], argv[1], argv[2], argv[3]);
781 else
782 res = os_snprintf(buf, sizeof(buf),
783 "HS20_DEAUTH_REQ %s %s %s",
784 argv[0], argv[1], argv[2]);
785 if (res < 0 || res >= (int) sizeof(buf))
786 return -1;
787 return wpa_ctrl_command(ctrl, buf);
788}
789
790
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700791static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
792{
793 hostapd_cli_quit = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800794 if (interactive)
795 eloop_terminate();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700796 return 0;
797}
798
799
800static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
801{
802 char cmd[256];
803 if (argc != 1) {
804 printf("Invalid LEVEL command: needs one argument (debug "
805 "level)\n");
806 return 0;
807 }
808 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
809 return wpa_ctrl_command(ctrl, cmd);
810}
811
812
813static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
814{
815 struct dirent *dent;
816 DIR *dir;
817
818 dir = opendir(ctrl_iface_dir);
819 if (dir == NULL) {
820 printf("Control interface directory '%s' could not be "
821 "openned.\n", ctrl_iface_dir);
822 return;
823 }
824
825 printf("Available interfaces:\n");
826 while ((dent = readdir(dir))) {
827 if (strcmp(dent->d_name, ".") == 0 ||
828 strcmp(dent->d_name, "..") == 0)
829 continue;
830 printf("%s\n", dent->d_name);
831 }
832 closedir(dir);
833}
834
835
836static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
837 char *argv[])
838{
839 if (argc < 1) {
840 hostapd_cli_list_interfaces(ctrl);
841 return 0;
842 }
843
844 hostapd_cli_close_connection();
845 free(ctrl_ifname);
846 ctrl_ifname = strdup(argv[0]);
847
848 if (hostapd_cli_open_connection(ctrl_ifname)) {
849 printf("Connected to interface '%s.\n", ctrl_ifname);
850 if (wpa_ctrl_attach(ctrl_conn) == 0) {
851 hostapd_cli_attached = 1;
852 } else {
853 printf("Warning: Failed to attach to "
854 "hostapd.\n");
855 }
856 } else {
857 printf("Could not connect to interface '%s' - re-trying\n",
858 ctrl_ifname);
859 }
860 return 0;
861}
862
863
864static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
865{
866 char cmd[256];
867 int res;
868
869 if (argc != 2) {
870 printf("Invalid SET command: needs two arguments (variable "
871 "name and value)\n");
872 return -1;
873 }
874
875 res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
876 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
877 printf("Too long SET command.\n");
878 return -1;
879 }
880 return wpa_ctrl_command(ctrl, cmd);
881}
882
883
884static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
885{
886 char cmd[256];
887 int res;
888
889 if (argc != 1) {
890 printf("Invalid GET command: needs one argument (variable "
891 "name)\n");
892 return -1;
893 }
894
895 res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
896 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
897 printf("Too long GET command.\n");
898 return -1;
899 }
900 return wpa_ctrl_command(ctrl, cmd);
901}
902
903
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800904static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
905 int argc, char *argv[])
906{
907 char cmd[256];
908 int res;
909 int i;
910 char *tmp;
911 int total;
912
913 if (argc < 2) {
914 printf("Invalid chan_switch command: needs at least two "
915 "arguments (count and freq)\n"
916 "usage: <cs_count> <freq> [sec_channel_offset=] "
917 "[center_freq1=] [center_freq2=] [bandwidth=] "
918 "[blocktx] [ht|vht]\n");
919 return -1;
920 }
921
922 res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
923 argv[0], argv[1]);
924 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
925 printf("Too long CHAN_SWITCH command.\n");
926 return -1;
927 }
928
929 total = res;
930 for (i = 2; i < argc; i++) {
931 tmp = cmd + total;
932 res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
933 if (res < 0 || (size_t) res >= sizeof(cmd) - total - 1) {
934 printf("Too long CHAN_SWITCH command.\n");
935 return -1;
936 }
937 total += res;
938 }
939 return wpa_ctrl_command(ctrl, cmd);
940}
941
942
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700943struct hostapd_cli_cmd {
944 const char *cmd;
945 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
946};
947
948static struct hostapd_cli_cmd hostapd_cli_commands[] = {
949 { "ping", hostapd_cli_cmd_ping },
950 { "mib", hostapd_cli_cmd_mib },
951 { "relog", hostapd_cli_cmd_relog },
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800952 { "status", hostapd_cli_cmd_status },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700953 { "sta", hostapd_cli_cmd_sta },
954 { "all_sta", hostapd_cli_cmd_all_sta },
955 { "new_sta", hostapd_cli_cmd_new_sta },
956 { "deauthenticate", hostapd_cli_cmd_deauthenticate },
957 { "disassociate", hostapd_cli_cmd_disassociate },
958#ifdef CONFIG_IEEE80211W
959 { "sa_query", hostapd_cli_cmd_sa_query },
960#endif /* CONFIG_IEEE80211W */
961#ifdef CONFIG_WPS
962 { "wps_pin", hostapd_cli_cmd_wps_pin },
963 { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
964 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
Dmitry Shmidt04949592012-07-19 12:16:46 -0700965 { "wps_cancel", hostapd_cli_cmd_wps_cancel },
Dmitry Shmidt04949592012-07-19 12:16:46 -0700966#ifdef CONFIG_WPS_NFC
967 { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
968 { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
969 { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800970 { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
Dmitry Shmidt04949592012-07-19 12:16:46 -0700971#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700972 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
973 { "wps_config", hostapd_cli_cmd_wps_config },
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700974 { "wps_get_status", hostapd_cli_cmd_wps_get_status },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700975#endif /* CONFIG_WPS */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800976 { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800977 { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700978 { "get_config", hostapd_cli_cmd_get_config },
979 { "help", hostapd_cli_cmd_help },
980 { "interface", hostapd_cli_cmd_interface },
981 { "level", hostapd_cli_cmd_level },
982 { "license", hostapd_cli_cmd_license },
983 { "quit", hostapd_cli_cmd_quit },
984 { "set", hostapd_cli_cmd_set },
985 { "get", hostapd_cli_cmd_get },
Dmitry Shmidt051af732013-10-22 13:52:46 -0700986 { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
987 { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800988 { "chan_switch", hostapd_cli_cmd_chan_switch },
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800989 { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif },
990 { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700991 { NULL, NULL }
992};
993
994
995static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
996{
997 struct hostapd_cli_cmd *cmd, *match = NULL;
998 int count;
999
1000 count = 0;
1001 cmd = hostapd_cli_commands;
1002 while (cmd->cmd) {
1003 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
1004 match = cmd;
1005 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1006 /* we have an exact match */
1007 count = 1;
1008 break;
1009 }
1010 count++;
1011 }
1012 cmd++;
1013 }
1014
1015 if (count > 1) {
1016 printf("Ambiguous command '%s'; possible commands:", argv[0]);
1017 cmd = hostapd_cli_commands;
1018 while (cmd->cmd) {
1019 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
1020 0) {
1021 printf(" %s", cmd->cmd);
1022 }
1023 cmd++;
1024 }
1025 printf("\n");
1026 } else if (count == 0) {
1027 printf("Unknown command '%s'\n", argv[0]);
1028 } else {
1029 match->handler(ctrl, argc - 1, &argv[1]);
1030 }
1031}
1032
1033
1034static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
1035 int action_monitor)
1036{
1037 int first = 1;
1038 if (ctrl_conn == NULL)
1039 return;
1040 while (wpa_ctrl_pending(ctrl)) {
1041 char buf[256];
1042 size_t len = sizeof(buf) - 1;
1043 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
1044 buf[len] = '\0';
1045 if (action_monitor)
1046 hostapd_cli_action_process(buf, len);
1047 else {
1048 if (in_read && first)
1049 printf("\n");
1050 first = 0;
1051 printf("%s\n", buf);
1052 }
1053 } else {
1054 printf("Could not read pending message.\n");
1055 break;
1056 }
1057 }
1058}
1059
1060
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001061#define max_args 10
1062
1063static int tokenize_cmd(char *cmd, char *argv[])
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001064{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001065 char *pos;
1066 int argc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001067
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001068 pos = cmd;
1069 for (;;) {
1070 while (*pos == ' ')
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001071 pos++;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001072 if (*pos == '\0')
1073 break;
1074 argv[argc] = pos;
1075 argc++;
1076 if (argc == max_args)
1077 break;
1078 if (*pos == '"') {
1079 char *pos2 = os_strrchr(pos, '"');
1080 if (pos2)
1081 pos = pos2 + 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001082 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001083 while (*pos != '\0' && *pos != ' ')
1084 pos++;
1085 if (*pos == ' ')
1086 *pos++ = '\0';
1087 }
1088
1089 return argc;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001090}
1091
1092
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001093static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001094{
1095 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
1096 printf("Connection to hostapd lost - trying to reconnect\n");
1097 hostapd_cli_close_connection();
1098 }
1099 if (!ctrl_conn) {
1100 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1101 if (ctrl_conn) {
1102 printf("Connection to hostapd re-established\n");
1103 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1104 hostapd_cli_attached = 1;
1105 } else {
1106 printf("Warning: Failed to attach to "
1107 "hostapd.\n");
1108 }
1109 }
1110 }
1111 if (ctrl_conn)
1112 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001113 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1114}
1115
1116
1117static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
1118{
1119 eloop_terminate();
1120}
1121
1122
1123static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
1124{
1125 char *argv[max_args];
1126 int argc;
1127 argc = tokenize_cmd(cmd, argv);
1128 if (argc)
1129 wpa_request(ctrl_conn, argc, argv);
1130}
1131
1132
1133static void hostapd_cli_edit_eof_cb(void *ctx)
1134{
1135 eloop_terminate();
1136}
1137
1138
1139static void hostapd_cli_interactive(void)
1140{
1141 printf("\nInteractive mode\n\n");
1142
1143 eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
1144 edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001145 NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001146 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1147
1148 eloop_run();
1149
1150 edit_deinit(NULL, NULL);
1151 eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
1152}
1153
1154
1155static void hostapd_cli_cleanup(void)
1156{
1157 hostapd_cli_close_connection();
1158 if (pid_file)
1159 os_daemonize_terminate(pid_file);
1160
1161 os_program_deinit();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001162}
1163
1164
1165static void hostapd_cli_action(struct wpa_ctrl *ctrl)
1166{
1167 fd_set rfds;
1168 int fd, res;
1169 struct timeval tv;
1170 char buf[256];
1171 size_t len;
1172
1173 fd = wpa_ctrl_get_fd(ctrl);
1174
1175 while (!hostapd_cli_quit) {
1176 FD_ZERO(&rfds);
1177 FD_SET(fd, &rfds);
1178 tv.tv_sec = ping_interval;
1179 tv.tv_usec = 0;
1180 res = select(fd + 1, &rfds, NULL, NULL, &tv);
1181 if (res < 0 && errno != EINTR) {
1182 perror("select");
1183 break;
1184 }
1185
1186 if (FD_ISSET(fd, &rfds))
1187 hostapd_cli_recv_pending(ctrl, 0, 1);
1188 else {
1189 len = sizeof(buf) - 1;
1190 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1191 hostapd_cli_action_process) < 0 ||
1192 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
1193 printf("hostapd did not reply to PING "
1194 "command - exiting\n");
1195 break;
1196 }
1197 }
1198 }
1199}
1200
1201
1202int main(int argc, char *argv[])
1203{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001204 int warning_displayed = 0;
1205 int c;
1206 int daemonize = 0;
1207
1208 if (os_program_init())
1209 return -1;
1210
1211 for (;;) {
1212 c = getopt(argc, argv, "a:BhG:i:p:v");
1213 if (c < 0)
1214 break;
1215 switch (c) {
1216 case 'a':
1217 action_file = optarg;
1218 break;
1219 case 'B':
1220 daemonize = 1;
1221 break;
1222 case 'G':
1223 ping_interval = atoi(optarg);
1224 break;
1225 case 'h':
1226 usage();
1227 return 0;
1228 case 'v':
1229 printf("%s\n", hostapd_cli_version);
1230 return 0;
1231 case 'i':
1232 os_free(ctrl_ifname);
1233 ctrl_ifname = os_strdup(optarg);
1234 break;
1235 case 'p':
1236 ctrl_iface_dir = optarg;
1237 break;
1238 default:
1239 usage();
1240 return -1;
1241 }
1242 }
1243
1244 interactive = (argc == optind) && (action_file == NULL);
1245
1246 if (interactive) {
1247 printf("%s\n\n%s\n\n", hostapd_cli_version,
1248 hostapd_cli_license);
1249 }
1250
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001251 if (eloop_init())
1252 return -1;
1253
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001254 for (;;) {
1255 if (ctrl_ifname == NULL) {
1256 struct dirent *dent;
1257 DIR *dir = opendir(ctrl_iface_dir);
1258 if (dir) {
1259 while ((dent = readdir(dir))) {
1260 if (os_strcmp(dent->d_name, ".") == 0
1261 ||
1262 os_strcmp(dent->d_name, "..") == 0)
1263 continue;
1264 printf("Selected interface '%s'\n",
1265 dent->d_name);
1266 ctrl_ifname = os_strdup(dent->d_name);
1267 break;
1268 }
1269 closedir(dir);
1270 }
1271 }
1272 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1273 if (ctrl_conn) {
1274 if (warning_displayed)
1275 printf("Connection established.\n");
1276 break;
1277 }
1278
1279 if (!interactive) {
1280 perror("Failed to connect to hostapd - "
1281 "wpa_ctrl_open");
1282 return -1;
1283 }
1284
1285 if (!warning_displayed) {
1286 printf("Could not connect to hostapd - re-trying\n");
1287 warning_displayed = 1;
1288 }
1289 os_sleep(1, 0);
1290 continue;
1291 }
1292
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001293 if (interactive || action_file) {
1294 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1295 hostapd_cli_attached = 1;
1296 } else {
1297 printf("Warning: Failed to attach to hostapd.\n");
1298 if (action_file)
1299 return -1;
1300 }
1301 }
1302
1303 if (daemonize && os_daemonize(pid_file))
1304 return -1;
1305
1306 if (interactive)
1307 hostapd_cli_interactive();
1308 else if (action_file)
1309 hostapd_cli_action(ctrl_conn);
1310 else
1311 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1312
1313 os_free(ctrl_ifname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001314 eloop_destroy();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001315 hostapd_cli_cleanup();
1316 return 0;
1317}