blob: 95f28d33dbcb7d8058644cc4a1ff8fa0960e1bee [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{
Jouni Malinen772e12c2014-10-07 10:29:35 -0700241 char *arg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700242 size_t len;
243 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700244
Jouni Malinen772e12c2014-10-07 10:29:35 -0700245 len = os_strlen(arg1) + os_strlen(arg2) + 2;
246 arg = os_malloc(len);
247 if (arg == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700248 return -1;
Jouni Malinen772e12c2014-10-07 10:29:35 -0700249 os_snprintf(arg, len, "%s %s", arg1, arg2);
250 res = os_exec(program, arg, 1);
251 os_free(arg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700252
Jouni Malinen772e12c2014-10-07 10:29:35 -0700253 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700254}
255
256
257static void hostapd_cli_action_process(char *msg, size_t len)
258{
259 const char *pos;
260
261 pos = msg;
262 if (*pos == '<') {
263 pos = os_strchr(pos, '>');
264 if (pos)
265 pos++;
266 else
267 pos = msg;
268 }
269
270 hostapd_cli_exec(action_file, ctrl_ifname, pos);
271}
272
273
274static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
275{
276 char buf[64];
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800277 if (argc < 1) {
278 printf("Invalid 'sta' command - at least one argument, STA "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700279 "address, is required.\n");
280 return -1;
281 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800282 if (argc > 1)
283 snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]);
284 else
285 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700286 return wpa_ctrl_command(ctrl, buf);
287}
288
289
290static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
291 char *argv[])
292{
293 char buf[64];
294 if (argc != 1) {
295 printf("Invalid 'new_sta' command - exactly one argument, STA "
296 "address, is required.\n");
297 return -1;
298 }
299 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
300 return wpa_ctrl_command(ctrl, buf);
301}
302
303
304static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
305 char *argv[])
306{
307 char buf[64];
308 if (argc < 1) {
309 printf("Invalid 'deauthenticate' command - exactly one "
310 "argument, STA address, is required.\n");
311 return -1;
312 }
313 if (argc > 1)
314 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
315 argv[0], argv[1]);
316 else
317 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
318 return wpa_ctrl_command(ctrl, buf);
319}
320
321
322static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
323 char *argv[])
324{
325 char buf[64];
326 if (argc < 1) {
327 printf("Invalid 'disassociate' command - exactly one "
328 "argument, STA address, is required.\n");
329 return -1;
330 }
331 if (argc > 1)
332 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
333 argv[0], argv[1]);
334 else
335 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
336 return wpa_ctrl_command(ctrl, buf);
337}
338
339
340#ifdef CONFIG_IEEE80211W
341static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
342 char *argv[])
343{
344 char buf[64];
345 if (argc != 1) {
346 printf("Invalid 'sa_query' command - exactly one argument, "
347 "STA address, is required.\n");
348 return -1;
349 }
350 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
351 return wpa_ctrl_command(ctrl, buf);
352}
353#endif /* CONFIG_IEEE80211W */
354
355
356#ifdef CONFIG_WPS
357static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
358 char *argv[])
359{
360 char buf[256];
361 if (argc < 2) {
362 printf("Invalid 'wps_pin' command - at least two arguments, "
363 "UUID and PIN, are required.\n");
364 return -1;
365 }
366 if (argc > 3)
367 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
368 argv[0], argv[1], argv[2], argv[3]);
369 else if (argc > 2)
370 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
371 argv[0], argv[1], argv[2]);
372 else
373 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
374 return wpa_ctrl_command(ctrl, buf);
375}
376
377
378static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
379 char *argv[])
380{
381 char cmd[256];
382 int res;
383
384 if (argc != 1 && argc != 2) {
385 printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
386 "- PIN to be verified\n");
387 return -1;
388 }
389
390 if (argc == 2)
391 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
392 argv[0], argv[1]);
393 else
394 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
395 argv[0]);
396 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
397 printf("Too long WPS_CHECK_PIN command.\n");
398 return -1;
399 }
400 return wpa_ctrl_command(ctrl, cmd);
401}
402
403
404static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
405 char *argv[])
406{
407 return wpa_ctrl_command(ctrl, "WPS_PBC");
408}
409
410
Dmitry Shmidt04949592012-07-19 12:16:46 -0700411static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
412 char *argv[])
413{
414 return wpa_ctrl_command(ctrl, "WPS_CANCEL");
415}
416
417
Dmitry Shmidt04949592012-07-19 12:16:46 -0700418#ifdef CONFIG_WPS_NFC
419static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
420 char *argv[])
421{
422 int ret;
423 char *buf;
424 size_t buflen;
425
426 if (argc != 1) {
427 printf("Invalid 'wps_nfc_tag_read' command - one argument "
428 "is required.\n");
429 return -1;
430 }
431
432 buflen = 18 + os_strlen(argv[0]);
433 buf = os_malloc(buflen);
434 if (buf == NULL)
435 return -1;
436 os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
437
438 ret = wpa_ctrl_command(ctrl, buf);
439 os_free(buf);
440
441 return ret;
442}
443
444
445static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
446 int argc, char *argv[])
447{
448 char cmd[64];
449 int res;
450
451 if (argc != 1) {
452 printf("Invalid 'wps_nfc_config_token' command - one argument "
453 "is required.\n");
454 return -1;
455 }
456
457 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
458 argv[0]);
459 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
460 printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
461 return -1;
462 }
463 return wpa_ctrl_command(ctrl, cmd);
464}
465
466
467static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
468 int argc, char *argv[])
469{
470 char cmd[64];
471 int res;
472
473 if (argc != 1) {
474 printf("Invalid 'wps_nfc_token' command - one argument is "
475 "required.\n");
476 return -1;
477 }
478
479 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
480 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
481 printf("Too long WPS_NFC_TOKEN command.\n");
482 return -1;
483 }
484 return wpa_ctrl_command(ctrl, cmd);
485}
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800486
487
488static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
489 int argc, char *argv[])
490{
491 char cmd[64];
492 int res;
493
494 if (argc != 2) {
495 printf("Invalid 'nfc_get_handover_sel' command - two arguments "
496 "are required.\n");
497 return -1;
498 }
499
500 res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
501 argv[0], argv[1]);
502 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
503 printf("Too long NFC_GET_HANDOVER_SEL command.\n");
504 return -1;
505 }
506 return wpa_ctrl_command(ctrl, cmd);
507}
508
Dmitry Shmidt04949592012-07-19 12:16:46 -0700509#endif /* CONFIG_WPS_NFC */
510
511
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700512static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
513 char *argv[])
514{
515 char buf[64];
516 if (argc < 1) {
517 printf("Invalid 'wps_ap_pin' command - at least one argument "
518 "is required.\n");
519 return -1;
520 }
521 if (argc > 2)
522 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
523 argv[0], argv[1], argv[2]);
524 else if (argc > 1)
525 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
526 argv[0], argv[1]);
527 else
528 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
529 return wpa_ctrl_command(ctrl, buf);
530}
531
532
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700533static int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc,
534 char *argv[])
535{
536 return wpa_ctrl_command(ctrl, "WPS_GET_STATUS");
537}
538
539
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700540static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
541 char *argv[])
542{
543 char buf[256];
544 char ssid_hex[2 * 32 + 1];
545 char key_hex[2 * 64 + 1];
546 int i;
547
548 if (argc < 1) {
549 printf("Invalid 'wps_config' command - at least two arguments "
550 "are required.\n");
551 return -1;
552 }
553
554 ssid_hex[0] = '\0';
555 for (i = 0; i < 32; i++) {
556 if (argv[0][i] == '\0')
557 break;
558 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
559 }
560
561 key_hex[0] = '\0';
562 if (argc > 3) {
563 for (i = 0; i < 64; i++) {
564 if (argv[3][i] == '\0')
565 break;
566 os_snprintf(&key_hex[i * 2], 3, "%02x",
567 argv[3][i]);
568 }
569 }
570
571 if (argc > 3)
572 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
573 ssid_hex, argv[1], argv[2], key_hex);
574 else if (argc > 2)
575 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
576 ssid_hex, argv[1], argv[2]);
577 else
578 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
579 ssid_hex, argv[1]);
580 return wpa_ctrl_command(ctrl, buf);
581}
582#endif /* CONFIG_WPS */
583
584
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800585static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
586 char *argv[])
587{
588 char buf[300];
589 int res;
590
591 if (argc < 2) {
592 printf("Invalid 'disassoc_imminent' command - two arguments "
593 "(STA addr and Disassociation Timer) are needed\n");
594 return -1;
595 }
596
597 res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
598 argv[0], argv[1]);
599 if (res < 0 || res >= (int) sizeof(buf))
600 return -1;
601 return wpa_ctrl_command(ctrl, buf);
602}
603
604
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800605static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
606 char *argv[])
607{
608 char buf[300];
609 int res;
610
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700611 if (argc < 3) {
612 printf("Invalid 'ess_disassoc' command - three arguments (STA "
613 "addr, disassoc timer, and URL) are needed\n");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800614 return -1;
615 }
616
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700617 res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
618 argv[0], argv[1], argv[2]);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800619 if (res < 0 || res >= (int) sizeof(buf))
620 return -1;
621 return wpa_ctrl_command(ctrl, buf);
622}
623
624
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700625static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
626 char *argv[])
627{
628 return wpa_ctrl_command(ctrl, "GET_CONFIG");
629}
630
631
632static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
633 char *addr, size_t addr_len)
634{
635 char buf[4096], *pos;
636 size_t len;
637 int ret;
638
639 if (ctrl_conn == NULL) {
640 printf("Not connected to hostapd - command dropped.\n");
641 return -1;
642 }
643 len = sizeof(buf) - 1;
644 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
645 hostapd_cli_msg_cb);
646 if (ret == -2) {
647 printf("'%s' command timed out.\n", cmd);
648 return -2;
649 } else if (ret < 0) {
650 printf("'%s' command failed.\n", cmd);
651 return -1;
652 }
653
654 buf[len] = '\0';
655 if (memcmp(buf, "FAIL", 4) == 0)
656 return -1;
657 printf("%s", buf);
658
659 pos = buf;
660 while (*pos != '\0' && *pos != '\n')
661 pos++;
662 *pos = '\0';
663 os_strlcpy(addr, buf, addr_len);
664 return 0;
665}
666
667
668static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
669 char *argv[])
670{
671 char addr[32], cmd[64];
672
673 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
674 return 0;
675 do {
676 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
677 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
678
679 return -1;
680}
681
682
683static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
684{
685 printf("%s", commands_help);
686 return 0;
687}
688
689
690static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
691 char *argv[])
692{
693 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
694 return 0;
695}
696
697
Dmitry Shmidt051af732013-10-22 13:52:46 -0700698static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl,
699 int argc, char *argv[])
700{
701 char buf[200];
702 int res;
703
704 if (argc != 1) {
705 printf("Invalid 'set_qos_map_set' command - "
706 "one argument (comma delimited QoS map set) "
707 "is needed\n");
708 return -1;
709 }
710
711 res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
712 if (res < 0 || res >= (int) sizeof(buf))
713 return -1;
714 return wpa_ctrl_command(ctrl, buf);
715}
716
717
718static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
719 int argc, char *argv[])
720{
721 char buf[50];
722 int res;
723
724 if (argc != 1) {
725 printf("Invalid 'send_qos_map_conf' command - "
726 "one argument (STA addr) is needed\n");
727 return -1;
728 }
729
730 res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
731 if (res < 0 || res >= (int) sizeof(buf))
732 return -1;
733 return wpa_ctrl_command(ctrl, buf);
734}
735
736
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800737static int hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc,
738 char *argv[])
739{
740 char buf[300];
741 int res;
742
743 if (argc < 2) {
744 printf("Invalid 'hs20_wnm_notif' command - two arguments (STA "
745 "addr and URL) are needed\n");
746 return -1;
747 }
748
749 res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s",
750 argv[0], argv[1]);
751 if (res < 0 || res >= (int) sizeof(buf))
752 return -1;
753 return wpa_ctrl_command(ctrl, buf);
754}
755
756
757static int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc,
758 char *argv[])
759{
760 char buf[300];
761 int res;
762
763 if (argc < 3) {
764 printf("Invalid 'hs20_deauth_req' command - at least three arguments (STA addr, Code, Re-auth Delay) are needed\n");
765 return -1;
766 }
767
768 if (argc > 3)
769 res = os_snprintf(buf, sizeof(buf),
770 "HS20_DEAUTH_REQ %s %s %s %s",
771 argv[0], argv[1], argv[2], argv[3]);
772 else
773 res = os_snprintf(buf, sizeof(buf),
774 "HS20_DEAUTH_REQ %s %s %s",
775 argv[0], argv[1], argv[2]);
776 if (res < 0 || res >= (int) sizeof(buf))
777 return -1;
778 return wpa_ctrl_command(ctrl, buf);
779}
780
781
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700782static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
783{
784 hostapd_cli_quit = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800785 if (interactive)
786 eloop_terminate();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700787 return 0;
788}
789
790
791static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
792{
793 char cmd[256];
794 if (argc != 1) {
795 printf("Invalid LEVEL command: needs one argument (debug "
796 "level)\n");
797 return 0;
798 }
799 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
800 return wpa_ctrl_command(ctrl, cmd);
801}
802
803
804static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
805{
806 struct dirent *dent;
807 DIR *dir;
808
809 dir = opendir(ctrl_iface_dir);
810 if (dir == NULL) {
811 printf("Control interface directory '%s' could not be "
812 "openned.\n", ctrl_iface_dir);
813 return;
814 }
815
816 printf("Available interfaces:\n");
817 while ((dent = readdir(dir))) {
818 if (strcmp(dent->d_name, ".") == 0 ||
819 strcmp(dent->d_name, "..") == 0)
820 continue;
821 printf("%s\n", dent->d_name);
822 }
823 closedir(dir);
824}
825
826
827static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
828 char *argv[])
829{
830 if (argc < 1) {
831 hostapd_cli_list_interfaces(ctrl);
832 return 0;
833 }
834
835 hostapd_cli_close_connection();
Dmitry Shmidt71757432014-06-02 13:50:35 -0700836 os_free(ctrl_ifname);
837 ctrl_ifname = os_strdup(argv[0]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700838
839 if (hostapd_cli_open_connection(ctrl_ifname)) {
840 printf("Connected to interface '%s.\n", ctrl_ifname);
841 if (wpa_ctrl_attach(ctrl_conn) == 0) {
842 hostapd_cli_attached = 1;
843 } else {
844 printf("Warning: Failed to attach to "
845 "hostapd.\n");
846 }
847 } else {
848 printf("Could not connect to interface '%s' - re-trying\n",
849 ctrl_ifname);
850 }
851 return 0;
852}
853
854
855static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
856{
857 char cmd[256];
858 int res;
859
860 if (argc != 2) {
861 printf("Invalid SET command: needs two arguments (variable "
862 "name and value)\n");
863 return -1;
864 }
865
866 res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
867 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
868 printf("Too long SET command.\n");
869 return -1;
870 }
871 return wpa_ctrl_command(ctrl, cmd);
872}
873
874
875static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
876{
877 char cmd[256];
878 int res;
879
880 if (argc != 1) {
881 printf("Invalid GET command: needs one argument (variable "
882 "name)\n");
883 return -1;
884 }
885
886 res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
887 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
888 printf("Too long GET command.\n");
889 return -1;
890 }
891 return wpa_ctrl_command(ctrl, cmd);
892}
893
894
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800895static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
896 int argc, char *argv[])
897{
898 char cmd[256];
899 int res;
900 int i;
901 char *tmp;
902 int total;
903
904 if (argc < 2) {
905 printf("Invalid chan_switch command: needs at least two "
906 "arguments (count and freq)\n"
907 "usage: <cs_count> <freq> [sec_channel_offset=] "
908 "[center_freq1=] [center_freq2=] [bandwidth=] "
909 "[blocktx] [ht|vht]\n");
910 return -1;
911 }
912
913 res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
914 argv[0], argv[1]);
915 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
916 printf("Too long CHAN_SWITCH command.\n");
917 return -1;
918 }
919
920 total = res;
921 for (i = 2; i < argc; i++) {
922 tmp = cmd + total;
923 res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
924 if (res < 0 || (size_t) res >= sizeof(cmd) - total - 1) {
925 printf("Too long CHAN_SWITCH command.\n");
926 return -1;
927 }
928 total += res;
929 }
930 return wpa_ctrl_command(ctrl, cmd);
931}
932
933
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -0700934static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
935{
936 char cmd[256];
937 int res;
938
939 if (argc < 2 || argc > 3) {
940 printf("Invalid vendor command\n"
941 "usage: <vendor id> <command id> [<hex formatted command argument>]\n");
942 return -1;
943 }
944
945 res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
946 argc == 3 ? argv[2] : "");
947 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
948 printf("Too long VENDOR command.\n");
949 return -1;
950 }
951 return wpa_ctrl_command(ctrl, cmd);
952}
953
954
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700955struct hostapd_cli_cmd {
956 const char *cmd;
957 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
958};
959
960static struct hostapd_cli_cmd hostapd_cli_commands[] = {
961 { "ping", hostapd_cli_cmd_ping },
962 { "mib", hostapd_cli_cmd_mib },
963 { "relog", hostapd_cli_cmd_relog },
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800964 { "status", hostapd_cli_cmd_status },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700965 { "sta", hostapd_cli_cmd_sta },
966 { "all_sta", hostapd_cli_cmd_all_sta },
967 { "new_sta", hostapd_cli_cmd_new_sta },
968 { "deauthenticate", hostapd_cli_cmd_deauthenticate },
969 { "disassociate", hostapd_cli_cmd_disassociate },
970#ifdef CONFIG_IEEE80211W
971 { "sa_query", hostapd_cli_cmd_sa_query },
972#endif /* CONFIG_IEEE80211W */
973#ifdef CONFIG_WPS
974 { "wps_pin", hostapd_cli_cmd_wps_pin },
975 { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
976 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
Dmitry Shmidt04949592012-07-19 12:16:46 -0700977 { "wps_cancel", hostapd_cli_cmd_wps_cancel },
Dmitry Shmidt04949592012-07-19 12:16:46 -0700978#ifdef CONFIG_WPS_NFC
979 { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
980 { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
981 { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800982 { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
Dmitry Shmidt04949592012-07-19 12:16:46 -0700983#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700984 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
985 { "wps_config", hostapd_cli_cmd_wps_config },
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700986 { "wps_get_status", hostapd_cli_cmd_wps_get_status },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700987#endif /* CONFIG_WPS */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800988 { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800989 { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700990 { "get_config", hostapd_cli_cmd_get_config },
991 { "help", hostapd_cli_cmd_help },
992 { "interface", hostapd_cli_cmd_interface },
993 { "level", hostapd_cli_cmd_level },
994 { "license", hostapd_cli_cmd_license },
995 { "quit", hostapd_cli_cmd_quit },
996 { "set", hostapd_cli_cmd_set },
997 { "get", hostapd_cli_cmd_get },
Dmitry Shmidt051af732013-10-22 13:52:46 -0700998 { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
999 { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001000 { "chan_switch", hostapd_cli_cmd_chan_switch },
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001001 { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif },
1002 { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req },
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001003 { "vendor", hostapd_cli_cmd_vendor },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001004 { NULL, NULL }
1005};
1006
1007
1008static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
1009{
1010 struct hostapd_cli_cmd *cmd, *match = NULL;
1011 int count;
1012
1013 count = 0;
1014 cmd = hostapd_cli_commands;
1015 while (cmd->cmd) {
1016 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
1017 match = cmd;
1018 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1019 /* we have an exact match */
1020 count = 1;
1021 break;
1022 }
1023 count++;
1024 }
1025 cmd++;
1026 }
1027
1028 if (count > 1) {
1029 printf("Ambiguous command '%s'; possible commands:", argv[0]);
1030 cmd = hostapd_cli_commands;
1031 while (cmd->cmd) {
1032 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
1033 0) {
1034 printf(" %s", cmd->cmd);
1035 }
1036 cmd++;
1037 }
1038 printf("\n");
1039 } else if (count == 0) {
1040 printf("Unknown command '%s'\n", argv[0]);
1041 } else {
1042 match->handler(ctrl, argc - 1, &argv[1]);
1043 }
1044}
1045
1046
1047static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
1048 int action_monitor)
1049{
1050 int first = 1;
1051 if (ctrl_conn == NULL)
1052 return;
1053 while (wpa_ctrl_pending(ctrl)) {
1054 char buf[256];
1055 size_t len = sizeof(buf) - 1;
1056 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
1057 buf[len] = '\0';
1058 if (action_monitor)
1059 hostapd_cli_action_process(buf, len);
1060 else {
1061 if (in_read && first)
1062 printf("\n");
1063 first = 0;
1064 printf("%s\n", buf);
1065 }
1066 } else {
1067 printf("Could not read pending message.\n");
1068 break;
1069 }
1070 }
1071}
1072
1073
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001074#define max_args 10
1075
1076static int tokenize_cmd(char *cmd, char *argv[])
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001077{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001078 char *pos;
1079 int argc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001080
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001081 pos = cmd;
1082 for (;;) {
1083 while (*pos == ' ')
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001084 pos++;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001085 if (*pos == '\0')
1086 break;
1087 argv[argc] = pos;
1088 argc++;
1089 if (argc == max_args)
1090 break;
1091 if (*pos == '"') {
1092 char *pos2 = os_strrchr(pos, '"');
1093 if (pos2)
1094 pos = pos2 + 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001095 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001096 while (*pos != '\0' && *pos != ' ')
1097 pos++;
1098 if (*pos == ' ')
1099 *pos++ = '\0';
1100 }
1101
1102 return argc;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001103}
1104
1105
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001106static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001107{
1108 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
1109 printf("Connection to hostapd lost - trying to reconnect\n");
1110 hostapd_cli_close_connection();
1111 }
1112 if (!ctrl_conn) {
1113 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1114 if (ctrl_conn) {
1115 printf("Connection to hostapd re-established\n");
1116 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1117 hostapd_cli_attached = 1;
1118 } else {
1119 printf("Warning: Failed to attach to "
1120 "hostapd.\n");
1121 }
1122 }
1123 }
1124 if (ctrl_conn)
1125 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001126 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1127}
1128
1129
1130static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
1131{
1132 eloop_terminate();
1133}
1134
1135
1136static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
1137{
1138 char *argv[max_args];
1139 int argc;
1140 argc = tokenize_cmd(cmd, argv);
1141 if (argc)
1142 wpa_request(ctrl_conn, argc, argv);
1143}
1144
1145
1146static void hostapd_cli_edit_eof_cb(void *ctx)
1147{
1148 eloop_terminate();
1149}
1150
1151
1152static void hostapd_cli_interactive(void)
1153{
1154 printf("\nInteractive mode\n\n");
1155
1156 eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
1157 edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001158 NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001159 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1160
1161 eloop_run();
1162
1163 edit_deinit(NULL, NULL);
1164 eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
1165}
1166
1167
1168static void hostapd_cli_cleanup(void)
1169{
1170 hostapd_cli_close_connection();
1171 if (pid_file)
1172 os_daemonize_terminate(pid_file);
1173
1174 os_program_deinit();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001175}
1176
1177
1178static void hostapd_cli_action(struct wpa_ctrl *ctrl)
1179{
1180 fd_set rfds;
1181 int fd, res;
1182 struct timeval tv;
1183 char buf[256];
1184 size_t len;
1185
1186 fd = wpa_ctrl_get_fd(ctrl);
1187
1188 while (!hostapd_cli_quit) {
1189 FD_ZERO(&rfds);
1190 FD_SET(fd, &rfds);
1191 tv.tv_sec = ping_interval;
1192 tv.tv_usec = 0;
1193 res = select(fd + 1, &rfds, NULL, NULL, &tv);
1194 if (res < 0 && errno != EINTR) {
1195 perror("select");
1196 break;
1197 }
1198
1199 if (FD_ISSET(fd, &rfds))
1200 hostapd_cli_recv_pending(ctrl, 0, 1);
1201 else {
1202 len = sizeof(buf) - 1;
1203 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1204 hostapd_cli_action_process) < 0 ||
1205 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
1206 printf("hostapd did not reply to PING "
1207 "command - exiting\n");
1208 break;
1209 }
1210 }
1211 }
1212}
1213
1214
1215int main(int argc, char *argv[])
1216{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001217 int warning_displayed = 0;
1218 int c;
1219 int daemonize = 0;
1220
1221 if (os_program_init())
1222 return -1;
1223
1224 for (;;) {
1225 c = getopt(argc, argv, "a:BhG:i:p:v");
1226 if (c < 0)
1227 break;
1228 switch (c) {
1229 case 'a':
1230 action_file = optarg;
1231 break;
1232 case 'B':
1233 daemonize = 1;
1234 break;
1235 case 'G':
1236 ping_interval = atoi(optarg);
1237 break;
1238 case 'h':
1239 usage();
1240 return 0;
1241 case 'v':
1242 printf("%s\n", hostapd_cli_version);
1243 return 0;
1244 case 'i':
1245 os_free(ctrl_ifname);
1246 ctrl_ifname = os_strdup(optarg);
1247 break;
1248 case 'p':
1249 ctrl_iface_dir = optarg;
1250 break;
1251 default:
1252 usage();
1253 return -1;
1254 }
1255 }
1256
1257 interactive = (argc == optind) && (action_file == NULL);
1258
1259 if (interactive) {
1260 printf("%s\n\n%s\n\n", hostapd_cli_version,
1261 hostapd_cli_license);
1262 }
1263
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001264 if (eloop_init())
1265 return -1;
1266
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001267 for (;;) {
1268 if (ctrl_ifname == NULL) {
1269 struct dirent *dent;
1270 DIR *dir = opendir(ctrl_iface_dir);
1271 if (dir) {
1272 while ((dent = readdir(dir))) {
1273 if (os_strcmp(dent->d_name, ".") == 0
1274 ||
1275 os_strcmp(dent->d_name, "..") == 0)
1276 continue;
1277 printf("Selected interface '%s'\n",
1278 dent->d_name);
1279 ctrl_ifname = os_strdup(dent->d_name);
1280 break;
1281 }
1282 closedir(dir);
1283 }
1284 }
1285 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1286 if (ctrl_conn) {
1287 if (warning_displayed)
1288 printf("Connection established.\n");
1289 break;
1290 }
1291
1292 if (!interactive) {
1293 perror("Failed to connect to hostapd - "
1294 "wpa_ctrl_open");
1295 return -1;
1296 }
1297
1298 if (!warning_displayed) {
1299 printf("Could not connect to hostapd - re-trying\n");
1300 warning_displayed = 1;
1301 }
1302 os_sleep(1, 0);
1303 continue;
1304 }
1305
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001306 if (interactive || action_file) {
1307 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1308 hostapd_cli_attached = 1;
1309 } else {
1310 printf("Warning: Failed to attach to hostapd.\n");
1311 if (action_file)
1312 return -1;
1313 }
1314 }
1315
1316 if (daemonize && os_daemonize(pid_file))
1317 return -1;
1318
1319 if (interactive)
1320 hostapd_cli_interactive();
1321 else if (action_file)
1322 hostapd_cli_action(ctrl_conn);
1323 else
1324 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1325
1326 os_free(ctrl_ifname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001327 eloop_destroy();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001328 hostapd_cli_cleanup();
1329 return 0;
1330}