blob: eee85041b6adc04dbfe88dda230ed89434b71799 [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 Shmidt8d520ff2011-05-09 14:06:53 -0700746static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
747{
748 hostapd_cli_quit = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800749 if (interactive)
750 eloop_terminate();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700751 return 0;
752}
753
754
755static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
756{
757 char cmd[256];
758 if (argc != 1) {
759 printf("Invalid LEVEL command: needs one argument (debug "
760 "level)\n");
761 return 0;
762 }
763 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
764 return wpa_ctrl_command(ctrl, cmd);
765}
766
767
768static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
769{
770 struct dirent *dent;
771 DIR *dir;
772
773 dir = opendir(ctrl_iface_dir);
774 if (dir == NULL) {
775 printf("Control interface directory '%s' could not be "
776 "openned.\n", ctrl_iface_dir);
777 return;
778 }
779
780 printf("Available interfaces:\n");
781 while ((dent = readdir(dir))) {
782 if (strcmp(dent->d_name, ".") == 0 ||
783 strcmp(dent->d_name, "..") == 0)
784 continue;
785 printf("%s\n", dent->d_name);
786 }
787 closedir(dir);
788}
789
790
791static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
792 char *argv[])
793{
794 if (argc < 1) {
795 hostapd_cli_list_interfaces(ctrl);
796 return 0;
797 }
798
799 hostapd_cli_close_connection();
800 free(ctrl_ifname);
801 ctrl_ifname = strdup(argv[0]);
802
803 if (hostapd_cli_open_connection(ctrl_ifname)) {
804 printf("Connected to interface '%s.\n", ctrl_ifname);
805 if (wpa_ctrl_attach(ctrl_conn) == 0) {
806 hostapd_cli_attached = 1;
807 } else {
808 printf("Warning: Failed to attach to "
809 "hostapd.\n");
810 }
811 } else {
812 printf("Could not connect to interface '%s' - re-trying\n",
813 ctrl_ifname);
814 }
815 return 0;
816}
817
818
819static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
820{
821 char cmd[256];
822 int res;
823
824 if (argc != 2) {
825 printf("Invalid SET command: needs two arguments (variable "
826 "name and value)\n");
827 return -1;
828 }
829
830 res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
831 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
832 printf("Too long SET command.\n");
833 return -1;
834 }
835 return wpa_ctrl_command(ctrl, cmd);
836}
837
838
839static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
840{
841 char cmd[256];
842 int res;
843
844 if (argc != 1) {
845 printf("Invalid GET command: needs one argument (variable "
846 "name)\n");
847 return -1;
848 }
849
850 res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
851 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
852 printf("Too long GET command.\n");
853 return -1;
854 }
855 return wpa_ctrl_command(ctrl, cmd);
856}
857
858
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800859static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
860 int argc, char *argv[])
861{
862 char cmd[256];
863 int res;
864 int i;
865 char *tmp;
866 int total;
867
868 if (argc < 2) {
869 printf("Invalid chan_switch command: needs at least two "
870 "arguments (count and freq)\n"
871 "usage: <cs_count> <freq> [sec_channel_offset=] "
872 "[center_freq1=] [center_freq2=] [bandwidth=] "
873 "[blocktx] [ht|vht]\n");
874 return -1;
875 }
876
877 res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
878 argv[0], argv[1]);
879 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
880 printf("Too long CHAN_SWITCH command.\n");
881 return -1;
882 }
883
884 total = res;
885 for (i = 2; i < argc; i++) {
886 tmp = cmd + total;
887 res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
888 if (res < 0 || (size_t) res >= sizeof(cmd) - total - 1) {
889 printf("Too long CHAN_SWITCH command.\n");
890 return -1;
891 }
892 total += res;
893 }
894 return wpa_ctrl_command(ctrl, cmd);
895}
896
897
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700898struct hostapd_cli_cmd {
899 const char *cmd;
900 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
901};
902
903static struct hostapd_cli_cmd hostapd_cli_commands[] = {
904 { "ping", hostapd_cli_cmd_ping },
905 { "mib", hostapd_cli_cmd_mib },
906 { "relog", hostapd_cli_cmd_relog },
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800907 { "status", hostapd_cli_cmd_status },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700908 { "sta", hostapd_cli_cmd_sta },
909 { "all_sta", hostapd_cli_cmd_all_sta },
910 { "new_sta", hostapd_cli_cmd_new_sta },
911 { "deauthenticate", hostapd_cli_cmd_deauthenticate },
912 { "disassociate", hostapd_cli_cmd_disassociate },
913#ifdef CONFIG_IEEE80211W
914 { "sa_query", hostapd_cli_cmd_sa_query },
915#endif /* CONFIG_IEEE80211W */
916#ifdef CONFIG_WPS
917 { "wps_pin", hostapd_cli_cmd_wps_pin },
918 { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
919 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
Dmitry Shmidt04949592012-07-19 12:16:46 -0700920 { "wps_cancel", hostapd_cli_cmd_wps_cancel },
Dmitry Shmidt04949592012-07-19 12:16:46 -0700921#ifdef CONFIG_WPS_NFC
922 { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
923 { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
924 { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800925 { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
Dmitry Shmidt04949592012-07-19 12:16:46 -0700926#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700927 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
928 { "wps_config", hostapd_cli_cmd_wps_config },
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700929 { "wps_get_status", hostapd_cli_cmd_wps_get_status },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700930#endif /* CONFIG_WPS */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800931 { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800932 { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700933 { "get_config", hostapd_cli_cmd_get_config },
934 { "help", hostapd_cli_cmd_help },
935 { "interface", hostapd_cli_cmd_interface },
936 { "level", hostapd_cli_cmd_level },
937 { "license", hostapd_cli_cmd_license },
938 { "quit", hostapd_cli_cmd_quit },
939 { "set", hostapd_cli_cmd_set },
940 { "get", hostapd_cli_cmd_get },
Dmitry Shmidt051af732013-10-22 13:52:46 -0700941 { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
942 { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800943 { "chan_switch", hostapd_cli_cmd_chan_switch },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700944 { NULL, NULL }
945};
946
947
948static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
949{
950 struct hostapd_cli_cmd *cmd, *match = NULL;
951 int count;
952
953 count = 0;
954 cmd = hostapd_cli_commands;
955 while (cmd->cmd) {
956 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
957 match = cmd;
958 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
959 /* we have an exact match */
960 count = 1;
961 break;
962 }
963 count++;
964 }
965 cmd++;
966 }
967
968 if (count > 1) {
969 printf("Ambiguous command '%s'; possible commands:", argv[0]);
970 cmd = hostapd_cli_commands;
971 while (cmd->cmd) {
972 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
973 0) {
974 printf(" %s", cmd->cmd);
975 }
976 cmd++;
977 }
978 printf("\n");
979 } else if (count == 0) {
980 printf("Unknown command '%s'\n", argv[0]);
981 } else {
982 match->handler(ctrl, argc - 1, &argv[1]);
983 }
984}
985
986
987static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
988 int action_monitor)
989{
990 int first = 1;
991 if (ctrl_conn == NULL)
992 return;
993 while (wpa_ctrl_pending(ctrl)) {
994 char buf[256];
995 size_t len = sizeof(buf) - 1;
996 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
997 buf[len] = '\0';
998 if (action_monitor)
999 hostapd_cli_action_process(buf, len);
1000 else {
1001 if (in_read && first)
1002 printf("\n");
1003 first = 0;
1004 printf("%s\n", buf);
1005 }
1006 } else {
1007 printf("Could not read pending message.\n");
1008 break;
1009 }
1010 }
1011}
1012
1013
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001014#define max_args 10
1015
1016static int tokenize_cmd(char *cmd, char *argv[])
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001017{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001018 char *pos;
1019 int argc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001020
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001021 pos = cmd;
1022 for (;;) {
1023 while (*pos == ' ')
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001024 pos++;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001025 if (*pos == '\0')
1026 break;
1027 argv[argc] = pos;
1028 argc++;
1029 if (argc == max_args)
1030 break;
1031 if (*pos == '"') {
1032 char *pos2 = os_strrchr(pos, '"');
1033 if (pos2)
1034 pos = pos2 + 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001035 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001036 while (*pos != '\0' && *pos != ' ')
1037 pos++;
1038 if (*pos == ' ')
1039 *pos++ = '\0';
1040 }
1041
1042 return argc;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001043}
1044
1045
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001046static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001047{
1048 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
1049 printf("Connection to hostapd lost - trying to reconnect\n");
1050 hostapd_cli_close_connection();
1051 }
1052 if (!ctrl_conn) {
1053 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1054 if (ctrl_conn) {
1055 printf("Connection to hostapd re-established\n");
1056 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1057 hostapd_cli_attached = 1;
1058 } else {
1059 printf("Warning: Failed to attach to "
1060 "hostapd.\n");
1061 }
1062 }
1063 }
1064 if (ctrl_conn)
1065 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001066 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1067}
1068
1069
1070static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
1071{
1072 eloop_terminate();
1073}
1074
1075
1076static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
1077{
1078 char *argv[max_args];
1079 int argc;
1080 argc = tokenize_cmd(cmd, argv);
1081 if (argc)
1082 wpa_request(ctrl_conn, argc, argv);
1083}
1084
1085
1086static void hostapd_cli_edit_eof_cb(void *ctx)
1087{
1088 eloop_terminate();
1089}
1090
1091
1092static void hostapd_cli_interactive(void)
1093{
1094 printf("\nInteractive mode\n\n");
1095
1096 eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
1097 edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001098 NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001099 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1100
1101 eloop_run();
1102
1103 edit_deinit(NULL, NULL);
1104 eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
1105}
1106
1107
1108static void hostapd_cli_cleanup(void)
1109{
1110 hostapd_cli_close_connection();
1111 if (pid_file)
1112 os_daemonize_terminate(pid_file);
1113
1114 os_program_deinit();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001115}
1116
1117
1118static void hostapd_cli_action(struct wpa_ctrl *ctrl)
1119{
1120 fd_set rfds;
1121 int fd, res;
1122 struct timeval tv;
1123 char buf[256];
1124 size_t len;
1125
1126 fd = wpa_ctrl_get_fd(ctrl);
1127
1128 while (!hostapd_cli_quit) {
1129 FD_ZERO(&rfds);
1130 FD_SET(fd, &rfds);
1131 tv.tv_sec = ping_interval;
1132 tv.tv_usec = 0;
1133 res = select(fd + 1, &rfds, NULL, NULL, &tv);
1134 if (res < 0 && errno != EINTR) {
1135 perror("select");
1136 break;
1137 }
1138
1139 if (FD_ISSET(fd, &rfds))
1140 hostapd_cli_recv_pending(ctrl, 0, 1);
1141 else {
1142 len = sizeof(buf) - 1;
1143 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1144 hostapd_cli_action_process) < 0 ||
1145 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
1146 printf("hostapd did not reply to PING "
1147 "command - exiting\n");
1148 break;
1149 }
1150 }
1151 }
1152}
1153
1154
1155int main(int argc, char *argv[])
1156{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001157 int warning_displayed = 0;
1158 int c;
1159 int daemonize = 0;
1160
1161 if (os_program_init())
1162 return -1;
1163
1164 for (;;) {
1165 c = getopt(argc, argv, "a:BhG:i:p:v");
1166 if (c < 0)
1167 break;
1168 switch (c) {
1169 case 'a':
1170 action_file = optarg;
1171 break;
1172 case 'B':
1173 daemonize = 1;
1174 break;
1175 case 'G':
1176 ping_interval = atoi(optarg);
1177 break;
1178 case 'h':
1179 usage();
1180 return 0;
1181 case 'v':
1182 printf("%s\n", hostapd_cli_version);
1183 return 0;
1184 case 'i':
1185 os_free(ctrl_ifname);
1186 ctrl_ifname = os_strdup(optarg);
1187 break;
1188 case 'p':
1189 ctrl_iface_dir = optarg;
1190 break;
1191 default:
1192 usage();
1193 return -1;
1194 }
1195 }
1196
1197 interactive = (argc == optind) && (action_file == NULL);
1198
1199 if (interactive) {
1200 printf("%s\n\n%s\n\n", hostapd_cli_version,
1201 hostapd_cli_license);
1202 }
1203
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001204 if (eloop_init())
1205 return -1;
1206
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001207 for (;;) {
1208 if (ctrl_ifname == NULL) {
1209 struct dirent *dent;
1210 DIR *dir = opendir(ctrl_iface_dir);
1211 if (dir) {
1212 while ((dent = readdir(dir))) {
1213 if (os_strcmp(dent->d_name, ".") == 0
1214 ||
1215 os_strcmp(dent->d_name, "..") == 0)
1216 continue;
1217 printf("Selected interface '%s'\n",
1218 dent->d_name);
1219 ctrl_ifname = os_strdup(dent->d_name);
1220 break;
1221 }
1222 closedir(dir);
1223 }
1224 }
1225 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1226 if (ctrl_conn) {
1227 if (warning_displayed)
1228 printf("Connection established.\n");
1229 break;
1230 }
1231
1232 if (!interactive) {
1233 perror("Failed to connect to hostapd - "
1234 "wpa_ctrl_open");
1235 return -1;
1236 }
1237
1238 if (!warning_displayed) {
1239 printf("Could not connect to hostapd - re-trying\n");
1240 warning_displayed = 1;
1241 }
1242 os_sleep(1, 0);
1243 continue;
1244 }
1245
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001246 if (interactive || action_file) {
1247 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1248 hostapd_cli_attached = 1;
1249 } else {
1250 printf("Warning: Failed to attach to hostapd.\n");
1251 if (action_file)
1252 return -1;
1253 }
1254 }
1255
1256 if (daemonize && os_daemonize(pid_file))
1257 return -1;
1258
1259 if (interactive)
1260 hostapd_cli_interactive();
1261 else if (action_file)
1262 hostapd_cli_action(ctrl_conn);
1263 else
1264 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1265
1266 os_free(ctrl_ifname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001267 eloop_destroy();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001268 hostapd_cli_cleanup();
1269 return 0;
1270}