blob: 09b7284e5635796f81805cfea54aa7fc52130741 [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();
Dmitry Shmidt71757432014-06-02 13:50:35 -0700845 os_free(ctrl_ifname);
846 ctrl_ifname = os_strdup(argv[0]);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -0700847 if (ctrl_ifname == NULL)
848 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700849
850 if (hostapd_cli_open_connection(ctrl_ifname)) {
851 printf("Connected to interface '%s.\n", ctrl_ifname);
852 if (wpa_ctrl_attach(ctrl_conn) == 0) {
853 hostapd_cli_attached = 1;
854 } else {
855 printf("Warning: Failed to attach to "
856 "hostapd.\n");
857 }
858 } else {
859 printf("Could not connect to interface '%s' - re-trying\n",
860 ctrl_ifname);
861 }
862 return 0;
863}
864
865
866static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
867{
868 char cmd[256];
869 int res;
870
871 if (argc != 2) {
872 printf("Invalid SET command: needs two arguments (variable "
873 "name and value)\n");
874 return -1;
875 }
876
877 res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
878 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
879 printf("Too long SET command.\n");
880 return -1;
881 }
882 return wpa_ctrl_command(ctrl, cmd);
883}
884
885
886static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
887{
888 char cmd[256];
889 int res;
890
891 if (argc != 1) {
892 printf("Invalid GET command: needs one argument (variable "
893 "name)\n");
894 return -1;
895 }
896
897 res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
898 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
899 printf("Too long GET command.\n");
900 return -1;
901 }
902 return wpa_ctrl_command(ctrl, cmd);
903}
904
905
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800906static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
907 int argc, char *argv[])
908{
909 char cmd[256];
910 int res;
911 int i;
912 char *tmp;
913 int total;
914
915 if (argc < 2) {
916 printf("Invalid chan_switch command: needs at least two "
917 "arguments (count and freq)\n"
918 "usage: <cs_count> <freq> [sec_channel_offset=] "
919 "[center_freq1=] [center_freq2=] [bandwidth=] "
920 "[blocktx] [ht|vht]\n");
921 return -1;
922 }
923
924 res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
925 argv[0], argv[1]);
926 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
927 printf("Too long CHAN_SWITCH command.\n");
928 return -1;
929 }
930
931 total = res;
932 for (i = 2; i < argc; i++) {
933 tmp = cmd + total;
934 res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
935 if (res < 0 || (size_t) res >= sizeof(cmd) - total - 1) {
936 printf("Too long CHAN_SWITCH command.\n");
937 return -1;
938 }
939 total += res;
940 }
941 return wpa_ctrl_command(ctrl, cmd);
942}
943
944
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -0700945static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
946{
947 char cmd[256];
948 int res;
949
950 if (argc < 2 || argc > 3) {
951 printf("Invalid vendor command\n"
952 "usage: <vendor id> <command id> [<hex formatted command argument>]\n");
953 return -1;
954 }
955
956 res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
957 argc == 3 ? argv[2] : "");
958 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
959 printf("Too long VENDOR command.\n");
960 return -1;
961 }
962 return wpa_ctrl_command(ctrl, cmd);
963}
964
965
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700966struct hostapd_cli_cmd {
967 const char *cmd;
968 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
969};
970
971static struct hostapd_cli_cmd hostapd_cli_commands[] = {
972 { "ping", hostapd_cli_cmd_ping },
973 { "mib", hostapd_cli_cmd_mib },
974 { "relog", hostapd_cli_cmd_relog },
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800975 { "status", hostapd_cli_cmd_status },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700976 { "sta", hostapd_cli_cmd_sta },
977 { "all_sta", hostapd_cli_cmd_all_sta },
978 { "new_sta", hostapd_cli_cmd_new_sta },
979 { "deauthenticate", hostapd_cli_cmd_deauthenticate },
980 { "disassociate", hostapd_cli_cmd_disassociate },
981#ifdef CONFIG_IEEE80211W
982 { "sa_query", hostapd_cli_cmd_sa_query },
983#endif /* CONFIG_IEEE80211W */
984#ifdef CONFIG_WPS
985 { "wps_pin", hostapd_cli_cmd_wps_pin },
986 { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
987 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
Dmitry Shmidt04949592012-07-19 12:16:46 -0700988 { "wps_cancel", hostapd_cli_cmd_wps_cancel },
Dmitry Shmidt04949592012-07-19 12:16:46 -0700989#ifdef CONFIG_WPS_NFC
990 { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
991 { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
992 { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800993 { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
Dmitry Shmidt04949592012-07-19 12:16:46 -0700994#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700995 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
996 { "wps_config", hostapd_cli_cmd_wps_config },
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700997 { "wps_get_status", hostapd_cli_cmd_wps_get_status },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700998#endif /* CONFIG_WPS */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800999 { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001000 { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001001 { "get_config", hostapd_cli_cmd_get_config },
1002 { "help", hostapd_cli_cmd_help },
1003 { "interface", hostapd_cli_cmd_interface },
1004 { "level", hostapd_cli_cmd_level },
1005 { "license", hostapd_cli_cmd_license },
1006 { "quit", hostapd_cli_cmd_quit },
1007 { "set", hostapd_cli_cmd_set },
1008 { "get", hostapd_cli_cmd_get },
Dmitry Shmidt051af732013-10-22 13:52:46 -07001009 { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
1010 { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001011 { "chan_switch", hostapd_cli_cmd_chan_switch },
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001012 { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif },
1013 { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req },
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001014 { "vendor", hostapd_cli_cmd_vendor },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001015 { NULL, NULL }
1016};
1017
1018
1019static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
1020{
1021 struct hostapd_cli_cmd *cmd, *match = NULL;
1022 int count;
1023
1024 count = 0;
1025 cmd = hostapd_cli_commands;
1026 while (cmd->cmd) {
1027 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
1028 match = cmd;
1029 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1030 /* we have an exact match */
1031 count = 1;
1032 break;
1033 }
1034 count++;
1035 }
1036 cmd++;
1037 }
1038
1039 if (count > 1) {
1040 printf("Ambiguous command '%s'; possible commands:", argv[0]);
1041 cmd = hostapd_cli_commands;
1042 while (cmd->cmd) {
1043 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
1044 0) {
1045 printf(" %s", cmd->cmd);
1046 }
1047 cmd++;
1048 }
1049 printf("\n");
1050 } else if (count == 0) {
1051 printf("Unknown command '%s'\n", argv[0]);
1052 } else {
1053 match->handler(ctrl, argc - 1, &argv[1]);
1054 }
1055}
1056
1057
1058static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
1059 int action_monitor)
1060{
1061 int first = 1;
1062 if (ctrl_conn == NULL)
1063 return;
1064 while (wpa_ctrl_pending(ctrl)) {
1065 char buf[256];
1066 size_t len = sizeof(buf) - 1;
1067 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
1068 buf[len] = '\0';
1069 if (action_monitor)
1070 hostapd_cli_action_process(buf, len);
1071 else {
1072 if (in_read && first)
1073 printf("\n");
1074 first = 0;
1075 printf("%s\n", buf);
1076 }
1077 } else {
1078 printf("Could not read pending message.\n");
1079 break;
1080 }
1081 }
1082}
1083
1084
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001085#define max_args 10
1086
1087static int tokenize_cmd(char *cmd, char *argv[])
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001088{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001089 char *pos;
1090 int argc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001091
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001092 pos = cmd;
1093 for (;;) {
1094 while (*pos == ' ')
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001095 pos++;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001096 if (*pos == '\0')
1097 break;
1098 argv[argc] = pos;
1099 argc++;
1100 if (argc == max_args)
1101 break;
1102 if (*pos == '"') {
1103 char *pos2 = os_strrchr(pos, '"');
1104 if (pos2)
1105 pos = pos2 + 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001106 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001107 while (*pos != '\0' && *pos != ' ')
1108 pos++;
1109 if (*pos == ' ')
1110 *pos++ = '\0';
1111 }
1112
1113 return argc;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001114}
1115
1116
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001117static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001118{
1119 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
1120 printf("Connection to hostapd lost - trying to reconnect\n");
1121 hostapd_cli_close_connection();
1122 }
1123 if (!ctrl_conn) {
1124 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1125 if (ctrl_conn) {
1126 printf("Connection to hostapd re-established\n");
1127 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1128 hostapd_cli_attached = 1;
1129 } else {
1130 printf("Warning: Failed to attach to "
1131 "hostapd.\n");
1132 }
1133 }
1134 }
1135 if (ctrl_conn)
1136 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001137 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1138}
1139
1140
1141static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
1142{
1143 eloop_terminate();
1144}
1145
1146
1147static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
1148{
1149 char *argv[max_args];
1150 int argc;
1151 argc = tokenize_cmd(cmd, argv);
1152 if (argc)
1153 wpa_request(ctrl_conn, argc, argv);
1154}
1155
1156
1157static void hostapd_cli_edit_eof_cb(void *ctx)
1158{
1159 eloop_terminate();
1160}
1161
1162
1163static void hostapd_cli_interactive(void)
1164{
1165 printf("\nInteractive mode\n\n");
1166
1167 eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
1168 edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001169 NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001170 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1171
1172 eloop_run();
1173
1174 edit_deinit(NULL, NULL);
1175 eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
1176}
1177
1178
1179static void hostapd_cli_cleanup(void)
1180{
1181 hostapd_cli_close_connection();
1182 if (pid_file)
1183 os_daemonize_terminate(pid_file);
1184
1185 os_program_deinit();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001186}
1187
1188
1189static void hostapd_cli_action(struct wpa_ctrl *ctrl)
1190{
1191 fd_set rfds;
1192 int fd, res;
1193 struct timeval tv;
1194 char buf[256];
1195 size_t len;
1196
1197 fd = wpa_ctrl_get_fd(ctrl);
1198
1199 while (!hostapd_cli_quit) {
1200 FD_ZERO(&rfds);
1201 FD_SET(fd, &rfds);
1202 tv.tv_sec = ping_interval;
1203 tv.tv_usec = 0;
1204 res = select(fd + 1, &rfds, NULL, NULL, &tv);
1205 if (res < 0 && errno != EINTR) {
1206 perror("select");
1207 break;
1208 }
1209
1210 if (FD_ISSET(fd, &rfds))
1211 hostapd_cli_recv_pending(ctrl, 0, 1);
1212 else {
1213 len = sizeof(buf) - 1;
1214 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1215 hostapd_cli_action_process) < 0 ||
1216 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
1217 printf("hostapd did not reply to PING "
1218 "command - exiting\n");
1219 break;
1220 }
1221 }
1222 }
1223}
1224
1225
1226int main(int argc, char *argv[])
1227{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001228 int warning_displayed = 0;
1229 int c;
1230 int daemonize = 0;
1231
1232 if (os_program_init())
1233 return -1;
1234
1235 for (;;) {
1236 c = getopt(argc, argv, "a:BhG:i:p:v");
1237 if (c < 0)
1238 break;
1239 switch (c) {
1240 case 'a':
1241 action_file = optarg;
1242 break;
1243 case 'B':
1244 daemonize = 1;
1245 break;
1246 case 'G':
1247 ping_interval = atoi(optarg);
1248 break;
1249 case 'h':
1250 usage();
1251 return 0;
1252 case 'v':
1253 printf("%s\n", hostapd_cli_version);
1254 return 0;
1255 case 'i':
1256 os_free(ctrl_ifname);
1257 ctrl_ifname = os_strdup(optarg);
1258 break;
1259 case 'p':
1260 ctrl_iface_dir = optarg;
1261 break;
1262 default:
1263 usage();
1264 return -1;
1265 }
1266 }
1267
1268 interactive = (argc == optind) && (action_file == NULL);
1269
1270 if (interactive) {
1271 printf("%s\n\n%s\n\n", hostapd_cli_version,
1272 hostapd_cli_license);
1273 }
1274
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001275 if (eloop_init())
1276 return -1;
1277
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001278 for (;;) {
1279 if (ctrl_ifname == NULL) {
1280 struct dirent *dent;
1281 DIR *dir = opendir(ctrl_iface_dir);
1282 if (dir) {
1283 while ((dent = readdir(dir))) {
1284 if (os_strcmp(dent->d_name, ".") == 0
1285 ||
1286 os_strcmp(dent->d_name, "..") == 0)
1287 continue;
1288 printf("Selected interface '%s'\n",
1289 dent->d_name);
1290 ctrl_ifname = os_strdup(dent->d_name);
1291 break;
1292 }
1293 closedir(dir);
1294 }
1295 }
1296 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1297 if (ctrl_conn) {
1298 if (warning_displayed)
1299 printf("Connection established.\n");
1300 break;
1301 }
1302
1303 if (!interactive) {
1304 perror("Failed to connect to hostapd - "
1305 "wpa_ctrl_open");
1306 return -1;
1307 }
1308
1309 if (!warning_displayed) {
1310 printf("Could not connect to hostapd - re-trying\n");
1311 warning_displayed = 1;
1312 }
1313 os_sleep(1, 0);
1314 continue;
1315 }
1316
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001317 if (interactive || action_file) {
1318 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1319 hostapd_cli_attached = 1;
1320 } else {
1321 printf("Warning: Failed to attach to hostapd.\n");
1322 if (action_file)
1323 return -1;
1324 }
1325 }
1326
1327 if (daemonize && os_daemonize(pid_file))
1328 return -1;
1329
1330 if (interactive)
1331 hostapd_cli_interactive();
1332 else if (action_file)
1333 hostapd_cli_action(ctrl_conn);
1334 else
1335 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1336
1337 os_free(ctrl_ifname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001338 eloop_destroy();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001339 hostapd_cli_cleanup();
1340 return 0;
1341}