blob: c488b4fd7f0ebf6c3f63130ccfb8a74503aeb553 [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 Shmidtdf5a7e42014-04-02 12:59:59 -0700943static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
944{
945 char cmd[256];
946 int res;
947
948 if (argc < 2 || argc > 3) {
949 printf("Invalid vendor command\n"
950 "usage: <vendor id> <command id> [<hex formatted command argument>]\n");
951 return -1;
952 }
953
954 res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
955 argc == 3 ? argv[2] : "");
956 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
957 printf("Too long VENDOR command.\n");
958 return -1;
959 }
960 return wpa_ctrl_command(ctrl, cmd);
961}
962
963
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700964struct hostapd_cli_cmd {
965 const char *cmd;
966 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
967};
968
969static struct hostapd_cli_cmd hostapd_cli_commands[] = {
970 { "ping", hostapd_cli_cmd_ping },
971 { "mib", hostapd_cli_cmd_mib },
972 { "relog", hostapd_cli_cmd_relog },
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800973 { "status", hostapd_cli_cmd_status },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700974 { "sta", hostapd_cli_cmd_sta },
975 { "all_sta", hostapd_cli_cmd_all_sta },
976 { "new_sta", hostapd_cli_cmd_new_sta },
977 { "deauthenticate", hostapd_cli_cmd_deauthenticate },
978 { "disassociate", hostapd_cli_cmd_disassociate },
979#ifdef CONFIG_IEEE80211W
980 { "sa_query", hostapd_cli_cmd_sa_query },
981#endif /* CONFIG_IEEE80211W */
982#ifdef CONFIG_WPS
983 { "wps_pin", hostapd_cli_cmd_wps_pin },
984 { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
985 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
Dmitry Shmidt04949592012-07-19 12:16:46 -0700986 { "wps_cancel", hostapd_cli_cmd_wps_cancel },
Dmitry Shmidt04949592012-07-19 12:16:46 -0700987#ifdef CONFIG_WPS_NFC
988 { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
989 { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
990 { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800991 { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
Dmitry Shmidt04949592012-07-19 12:16:46 -0700992#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700993 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
994 { "wps_config", hostapd_cli_cmd_wps_config },
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700995 { "wps_get_status", hostapd_cli_cmd_wps_get_status },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700996#endif /* CONFIG_WPS */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800997 { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800998 { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700999 { "get_config", hostapd_cli_cmd_get_config },
1000 { "help", hostapd_cli_cmd_help },
1001 { "interface", hostapd_cli_cmd_interface },
1002 { "level", hostapd_cli_cmd_level },
1003 { "license", hostapd_cli_cmd_license },
1004 { "quit", hostapd_cli_cmd_quit },
1005 { "set", hostapd_cli_cmd_set },
1006 { "get", hostapd_cli_cmd_get },
Dmitry Shmidt051af732013-10-22 13:52:46 -07001007 { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
1008 { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001009 { "chan_switch", hostapd_cli_cmd_chan_switch },
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001010 { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif },
1011 { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req },
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001012 { "vendor", hostapd_cli_cmd_vendor },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001013 { NULL, NULL }
1014};
1015
1016
1017static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
1018{
1019 struct hostapd_cli_cmd *cmd, *match = NULL;
1020 int count;
1021
1022 count = 0;
1023 cmd = hostapd_cli_commands;
1024 while (cmd->cmd) {
1025 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
1026 match = cmd;
1027 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1028 /* we have an exact match */
1029 count = 1;
1030 break;
1031 }
1032 count++;
1033 }
1034 cmd++;
1035 }
1036
1037 if (count > 1) {
1038 printf("Ambiguous command '%s'; possible commands:", argv[0]);
1039 cmd = hostapd_cli_commands;
1040 while (cmd->cmd) {
1041 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
1042 0) {
1043 printf(" %s", cmd->cmd);
1044 }
1045 cmd++;
1046 }
1047 printf("\n");
1048 } else if (count == 0) {
1049 printf("Unknown command '%s'\n", argv[0]);
1050 } else {
1051 match->handler(ctrl, argc - 1, &argv[1]);
1052 }
1053}
1054
1055
1056static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
1057 int action_monitor)
1058{
1059 int first = 1;
1060 if (ctrl_conn == NULL)
1061 return;
1062 while (wpa_ctrl_pending(ctrl)) {
1063 char buf[256];
1064 size_t len = sizeof(buf) - 1;
1065 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
1066 buf[len] = '\0';
1067 if (action_monitor)
1068 hostapd_cli_action_process(buf, len);
1069 else {
1070 if (in_read && first)
1071 printf("\n");
1072 first = 0;
1073 printf("%s\n", buf);
1074 }
1075 } else {
1076 printf("Could not read pending message.\n");
1077 break;
1078 }
1079 }
1080}
1081
1082
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001083#define max_args 10
1084
1085static int tokenize_cmd(char *cmd, char *argv[])
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001086{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001087 char *pos;
1088 int argc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001089
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001090 pos = cmd;
1091 for (;;) {
1092 while (*pos == ' ')
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001093 pos++;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001094 if (*pos == '\0')
1095 break;
1096 argv[argc] = pos;
1097 argc++;
1098 if (argc == max_args)
1099 break;
1100 if (*pos == '"') {
1101 char *pos2 = os_strrchr(pos, '"');
1102 if (pos2)
1103 pos = pos2 + 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001104 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001105 while (*pos != '\0' && *pos != ' ')
1106 pos++;
1107 if (*pos == ' ')
1108 *pos++ = '\0';
1109 }
1110
1111 return argc;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001112}
1113
1114
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001115static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001116{
1117 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
1118 printf("Connection to hostapd lost - trying to reconnect\n");
1119 hostapd_cli_close_connection();
1120 }
1121 if (!ctrl_conn) {
1122 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1123 if (ctrl_conn) {
1124 printf("Connection to hostapd re-established\n");
1125 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1126 hostapd_cli_attached = 1;
1127 } else {
1128 printf("Warning: Failed to attach to "
1129 "hostapd.\n");
1130 }
1131 }
1132 }
1133 if (ctrl_conn)
1134 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001135 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1136}
1137
1138
1139static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
1140{
1141 eloop_terminate();
1142}
1143
1144
1145static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
1146{
1147 char *argv[max_args];
1148 int argc;
1149 argc = tokenize_cmd(cmd, argv);
1150 if (argc)
1151 wpa_request(ctrl_conn, argc, argv);
1152}
1153
1154
1155static void hostapd_cli_edit_eof_cb(void *ctx)
1156{
1157 eloop_terminate();
1158}
1159
1160
1161static void hostapd_cli_interactive(void)
1162{
1163 printf("\nInteractive mode\n\n");
1164
1165 eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
1166 edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001167 NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001168 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1169
1170 eloop_run();
1171
1172 edit_deinit(NULL, NULL);
1173 eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
1174}
1175
1176
1177static void hostapd_cli_cleanup(void)
1178{
1179 hostapd_cli_close_connection();
1180 if (pid_file)
1181 os_daemonize_terminate(pid_file);
1182
1183 os_program_deinit();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001184}
1185
1186
1187static void hostapd_cli_action(struct wpa_ctrl *ctrl)
1188{
1189 fd_set rfds;
1190 int fd, res;
1191 struct timeval tv;
1192 char buf[256];
1193 size_t len;
1194
1195 fd = wpa_ctrl_get_fd(ctrl);
1196
1197 while (!hostapd_cli_quit) {
1198 FD_ZERO(&rfds);
1199 FD_SET(fd, &rfds);
1200 tv.tv_sec = ping_interval;
1201 tv.tv_usec = 0;
1202 res = select(fd + 1, &rfds, NULL, NULL, &tv);
1203 if (res < 0 && errno != EINTR) {
1204 perror("select");
1205 break;
1206 }
1207
1208 if (FD_ISSET(fd, &rfds))
1209 hostapd_cli_recv_pending(ctrl, 0, 1);
1210 else {
1211 len = sizeof(buf) - 1;
1212 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1213 hostapd_cli_action_process) < 0 ||
1214 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
1215 printf("hostapd did not reply to PING "
1216 "command - exiting\n");
1217 break;
1218 }
1219 }
1220 }
1221}
1222
1223
1224int main(int argc, char *argv[])
1225{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001226 int warning_displayed = 0;
1227 int c;
1228 int daemonize = 0;
1229
1230 if (os_program_init())
1231 return -1;
1232
1233 for (;;) {
1234 c = getopt(argc, argv, "a:BhG:i:p:v");
1235 if (c < 0)
1236 break;
1237 switch (c) {
1238 case 'a':
1239 action_file = optarg;
1240 break;
1241 case 'B':
1242 daemonize = 1;
1243 break;
1244 case 'G':
1245 ping_interval = atoi(optarg);
1246 break;
1247 case 'h':
1248 usage();
1249 return 0;
1250 case 'v':
1251 printf("%s\n", hostapd_cli_version);
1252 return 0;
1253 case 'i':
1254 os_free(ctrl_ifname);
1255 ctrl_ifname = os_strdup(optarg);
1256 break;
1257 case 'p':
1258 ctrl_iface_dir = optarg;
1259 break;
1260 default:
1261 usage();
1262 return -1;
1263 }
1264 }
1265
1266 interactive = (argc == optind) && (action_file == NULL);
1267
1268 if (interactive) {
1269 printf("%s\n\n%s\n\n", hostapd_cli_version,
1270 hostapd_cli_license);
1271 }
1272
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001273 if (eloop_init())
1274 return -1;
1275
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001276 for (;;) {
1277 if (ctrl_ifname == NULL) {
1278 struct dirent *dent;
1279 DIR *dir = opendir(ctrl_iface_dir);
1280 if (dir) {
1281 while ((dent = readdir(dir))) {
1282 if (os_strcmp(dent->d_name, ".") == 0
1283 ||
1284 os_strcmp(dent->d_name, "..") == 0)
1285 continue;
1286 printf("Selected interface '%s'\n",
1287 dent->d_name);
1288 ctrl_ifname = os_strdup(dent->d_name);
1289 break;
1290 }
1291 closedir(dir);
1292 }
1293 }
1294 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1295 if (ctrl_conn) {
1296 if (warning_displayed)
1297 printf("Connection established.\n");
1298 break;
1299 }
1300
1301 if (!interactive) {
1302 perror("Failed to connect to hostapd - "
1303 "wpa_ctrl_open");
1304 return -1;
1305 }
1306
1307 if (!warning_displayed) {
1308 printf("Could not connect to hostapd - re-trying\n");
1309 warning_displayed = 1;
1310 }
1311 os_sleep(1, 0);
1312 continue;
1313 }
1314
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001315 if (interactive || action_file) {
1316 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1317 hostapd_cli_attached = 1;
1318 } else {
1319 printf("Warning: Failed to attach to hostapd.\n");
1320 if (action_file)
1321 return -1;
1322 }
1323 }
1324
1325 if (daemonize && os_daemonize(pid_file))
1326 return -1;
1327
1328 if (interactive)
1329 hostapd_cli_interactive();
1330 else if (action_file)
1331 hostapd_cli_action(ctrl_conn);
1332 else
1333 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1334
1335 os_free(ctrl_ifname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001336 eloop_destroy();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001337 hostapd_cli_cleanup();
1338 return 0;
1339}