blob: 5e6254244b3166316c72e647d0b7649f3ba2379b [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * hostapd - command line interface for hostapd daemon
Dmitry Shmidtde47be72016-01-07 12:52:55 -08003 * Copyright (c) 2004-2016, 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 Shmidt9d9e6022015-04-23 10:34:55 -070013#include "common/ieee802_11_defs.h"
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080014#include "utils/common.h"
15#include "utils/eloop.h"
16#include "utils/edit.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070017#include "common/version.h"
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -070018#include "common/cli.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070019
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -080020#ifndef CONFIG_NO_CTRL_IFACE
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070021
Dmitry Shmidt1d755d02015-04-28 10:34:29 -070022static const char *const hostapd_cli_version =
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070023"hostapd_cli v" VERSION_STR "\n"
Dmitry Shmidtde47be72016-01-07 12:52:55 -080024"Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070025
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070026static struct wpa_ctrl *ctrl_conn;
27static int hostapd_cli_quit = 0;
28static int hostapd_cli_attached = 0;
Jeff Johnson205f2142012-09-03 22:12:17 -070029
30#ifndef CONFIG_CTRL_IFACE_DIR
31#define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd"
32#endif /* CONFIG_CTRL_IFACE_DIR */
33static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080034static const char *client_socket_dir = NULL;
Jeff Johnson205f2142012-09-03 22:12:17 -070035
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070036static char *ctrl_ifname = NULL;
37static const char *pid_file = NULL;
38static const char *action_file = NULL;
39static int ping_interval = 5;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080040static int interactive = 0;
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -070041static int event_handler_registered = 0;
42
43static DEFINE_DL_LIST(stations); /* struct cli_txt_entry */
44
45static void print_help(FILE *stream, const char *cmd);
46static char ** list_cmd_list(void);
47static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070048
49
50static void usage(void)
51{
52 fprintf(stderr, "%s\n", hostapd_cli_version);
53 fprintf(stderr,
54 "\n"
55 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
56 "[-a<path>] \\\n"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080057 " [-P<pid file>] [-G<ping interval>] [command..]\n"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070058 "\n"
59 "Options:\n"
60 " -h help (show this usage text)\n"
61 " -v shown version information\n"
62 " -p<path> path to find control sockets (default: "
63 "/var/run/hostapd)\n"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080064 " -s<dir_path> dir path to open client sockets (default: "
65 CONFIG_CTRL_IFACE_DIR ")\n"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070066 " -a<file> run in daemon mode executing the action file "
67 "based on events\n"
68 " from hostapd\n"
69 " -B run a daemon in the background\n"
70 " -i<ifname> Interface to listen on (default: first "
71 "interface found in the\n"
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -070072 " socket path)\n\n");
73 print_help(stderr, NULL);
74}
75
76
77static void register_event_handler(struct wpa_ctrl *ctrl)
78{
79 if (!ctrl_conn)
80 return;
81 if (interactive) {
82 event_handler_registered =
83 !eloop_register_read_sock(wpa_ctrl_get_fd(ctrl),
84 hostapd_cli_receive,
85 NULL, NULL);
86 }
87}
88
89
90static void unregister_event_handler(struct wpa_ctrl *ctrl)
91{
92 if (!ctrl_conn)
93 return;
94 if (interactive && event_handler_registered) {
95 eloop_unregister_read_sock(wpa_ctrl_get_fd(ctrl));
96 event_handler_registered = 0;
97 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070098}
99
100
101static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
102{
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -0800103#ifndef CONFIG_CTRL_IFACE_UDP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700104 char *cfile;
105 int flen;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -0800106#endif /* !CONFIG_CTRL_IFACE_UDP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700107
108 if (ifname == NULL)
109 return NULL;
110
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -0800111#ifdef CONFIG_CTRL_IFACE_UDP
112 ctrl_conn = wpa_ctrl_open(ifname);
113 return ctrl_conn;
114#else /* CONFIG_CTRL_IFACE_UDP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700115 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
116 cfile = malloc(flen);
117 if (cfile == NULL)
118 return NULL;
119 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
120
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800121 if (client_socket_dir && client_socket_dir[0] &&
122 access(client_socket_dir, F_OK) < 0) {
123 perror(client_socket_dir);
124 free(cfile);
125 return NULL;
126 }
127
128 ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700129 free(cfile);
130 return ctrl_conn;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -0800131#endif /* CONFIG_CTRL_IFACE_UDP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700132}
133
134
135static void hostapd_cli_close_connection(void)
136{
137 if (ctrl_conn == NULL)
138 return;
139
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -0700140 unregister_event_handler(ctrl_conn);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700141 if (hostapd_cli_attached) {
142 wpa_ctrl_detach(ctrl_conn);
143 hostapd_cli_attached = 0;
144 }
145 wpa_ctrl_close(ctrl_conn);
146 ctrl_conn = NULL;
147}
148
149
150static void hostapd_cli_msg_cb(char *msg, size_t len)
151{
152 printf("%s\n", msg);
153}
154
155
156static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
157{
158 char buf[4096];
159 size_t len;
160 int ret;
161
162 if (ctrl_conn == NULL) {
163 printf("Not connected to hostapd - command dropped.\n");
164 return -1;
165 }
166 len = sizeof(buf) - 1;
167 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
168 hostapd_cli_msg_cb);
169 if (ret == -2) {
170 printf("'%s' command timed out.\n", cmd);
171 return -2;
172 } else if (ret < 0) {
173 printf("'%s' command failed.\n", cmd);
174 return -1;
175 }
176 if (print) {
177 buf[len] = '\0';
178 printf("%s", buf);
179 }
180 return 0;
181}
182
183
184static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
185{
186 return _wpa_ctrl_command(ctrl, cmd, 1);
187}
188
189
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800190static int hostapd_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd,
191 int min_args, int argc, char *argv[])
192{
193 char buf[4096];
194
195 if (argc < min_args) {
196 printf("Invalid %s command - at least %d argument%s required.\n",
197 cmd, min_args, min_args > 1 ? "s are" : " is");
198 return -1;
199 }
200 if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0)
201 return -1;
202 return wpa_ctrl_command(ctrl, buf);
203}
204
205
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700206static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
207{
208 return wpa_ctrl_command(ctrl, "PING");
209}
210
211
212static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
213{
214 return wpa_ctrl_command(ctrl, "RELOG");
215}
216
217
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800218static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
219{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800220 if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
221 return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800222 return wpa_ctrl_command(ctrl, "STATUS");
223}
224
225
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700226static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
227{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800228 if (argc > 0) {
229 char buf[100];
230 os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]);
231 return wpa_ctrl_command(ctrl, buf);
232 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700233 return wpa_ctrl_command(ctrl, "MIB");
234}
235
236
237static int hostapd_cli_exec(const char *program, const char *arg1,
238 const char *arg2)
239{
Jouni Malinen772e12c2014-10-07 10:29:35 -0700240 char *arg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700241 size_t len;
242 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700243
Jouni Malinen772e12c2014-10-07 10:29:35 -0700244 len = os_strlen(arg1) + os_strlen(arg2) + 2;
245 arg = os_malloc(len);
246 if (arg == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700247 return -1;
Jouni Malinen772e12c2014-10-07 10:29:35 -0700248 os_snprintf(arg, len, "%s %s", arg1, arg2);
249 res = os_exec(program, arg, 1);
250 os_free(arg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700251
Jouni Malinen772e12c2014-10-07 10:29:35 -0700252 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700253}
254
255
256static void hostapd_cli_action_process(char *msg, size_t len)
257{
258 const char *pos;
259
260 pos = msg;
261 if (*pos == '<') {
262 pos = os_strchr(pos, '>');
263 if (pos)
264 pos++;
265 else
266 pos = msg;
267 }
268
269 hostapd_cli_exec(action_file, ctrl_ifname, pos);
270}
271
272
273static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
274{
275 char buf[64];
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800276 if (argc < 1) {
277 printf("Invalid 'sta' command - at least one argument, STA "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700278 "address, is required.\n");
279 return -1;
280 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800281 if (argc > 1)
282 snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]);
283 else
284 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700285 return wpa_ctrl_command(ctrl, buf);
286}
287
288
289static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
290 char *argv[])
291{
292 char buf[64];
293 if (argc != 1) {
294 printf("Invalid 'new_sta' command - exactly one argument, STA "
295 "address, is required.\n");
296 return -1;
297 }
298 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
299 return wpa_ctrl_command(ctrl, buf);
300}
301
302
303static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
304 char *argv[])
305{
306 char buf[64];
307 if (argc < 1) {
308 printf("Invalid 'deauthenticate' command - exactly one "
309 "argument, STA address, is required.\n");
310 return -1;
311 }
312 if (argc > 1)
313 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
314 argv[0], argv[1]);
315 else
316 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
317 return wpa_ctrl_command(ctrl, buf);
318}
319
320
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -0700321static char ** hostapd_complete_deauthenticate(const char *str, int pos)
322{
323 int arg = get_cmd_arg_num(str, pos);
324 char **res = NULL;
325
326 switch (arg) {
327 case 1:
328 res = cli_txt_list_array(&stations);
329 break;
330 }
331
332 return res;
333}
334
335
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700336static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
337 char *argv[])
338{
339 char buf[64];
340 if (argc < 1) {
341 printf("Invalid 'disassociate' command - exactly one "
342 "argument, STA address, is required.\n");
343 return -1;
344 }
345 if (argc > 1)
346 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
347 argv[0], argv[1]);
348 else
349 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
350 return wpa_ctrl_command(ctrl, buf);
351}
352
353
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -0700354static char ** hostapd_complete_disassociate(const char *str, int pos)
355{
356 int arg = get_cmd_arg_num(str, pos);
357 char **res = NULL;
358
359 switch (arg) {
360 case 1:
361 res = cli_txt_list_array(&stations);
362 break;
363 }
364
365 return res;
366}
367
368
Dmitry Shmidtaca489e2016-09-28 15:44:14 -0700369#ifdef CONFIG_TAXONOMY
370static int hostapd_cli_cmd_signature(struct wpa_ctrl *ctrl, int argc,
371 char *argv[])
372{
373 char buf[64];
374
375 if (argc != 1) {
376 printf("Invalid 'signature' command - exactly one argument, STA address, is required.\n");
377 return -1;
378 }
379 os_snprintf(buf, sizeof(buf), "SIGNATURE %s", argv[0]);
380 return wpa_ctrl_command(ctrl, buf);
381}
382#endif /* CONFIG_TAXONOMY */
383
384
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700385#ifdef CONFIG_IEEE80211W
386static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
387 char *argv[])
388{
389 char buf[64];
390 if (argc != 1) {
391 printf("Invalid 'sa_query' command - exactly one argument, "
392 "STA address, is required.\n");
393 return -1;
394 }
395 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
396 return wpa_ctrl_command(ctrl, buf);
397}
398#endif /* CONFIG_IEEE80211W */
399
400
401#ifdef CONFIG_WPS
402static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
403 char *argv[])
404{
405 char buf[256];
406 if (argc < 2) {
407 printf("Invalid 'wps_pin' command - at least two arguments, "
408 "UUID and PIN, are required.\n");
409 return -1;
410 }
411 if (argc > 3)
412 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
413 argv[0], argv[1], argv[2], argv[3]);
414 else if (argc > 2)
415 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
416 argv[0], argv[1], argv[2]);
417 else
418 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
419 return wpa_ctrl_command(ctrl, buf);
420}
421
422
423static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
424 char *argv[])
425{
426 char cmd[256];
427 int res;
428
429 if (argc != 1 && argc != 2) {
430 printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
431 "- PIN to be verified\n");
432 return -1;
433 }
434
435 if (argc == 2)
436 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
437 argv[0], argv[1]);
438 else
439 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
440 argv[0]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800441 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700442 printf("Too long WPS_CHECK_PIN command.\n");
443 return -1;
444 }
445 return wpa_ctrl_command(ctrl, cmd);
446}
447
448
449static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
450 char *argv[])
451{
452 return wpa_ctrl_command(ctrl, "WPS_PBC");
453}
454
455
Dmitry Shmidt04949592012-07-19 12:16:46 -0700456static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
457 char *argv[])
458{
459 return wpa_ctrl_command(ctrl, "WPS_CANCEL");
460}
461
462
Dmitry Shmidt04949592012-07-19 12:16:46 -0700463#ifdef CONFIG_WPS_NFC
464static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
465 char *argv[])
466{
467 int ret;
468 char *buf;
469 size_t buflen;
470
471 if (argc != 1) {
472 printf("Invalid 'wps_nfc_tag_read' command - one argument "
473 "is required.\n");
474 return -1;
475 }
476
477 buflen = 18 + os_strlen(argv[0]);
478 buf = os_malloc(buflen);
479 if (buf == NULL)
480 return -1;
481 os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
482
483 ret = wpa_ctrl_command(ctrl, buf);
484 os_free(buf);
485
486 return ret;
487}
488
489
490static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
491 int argc, char *argv[])
492{
493 char cmd[64];
494 int res;
495
496 if (argc != 1) {
497 printf("Invalid 'wps_nfc_config_token' command - one argument "
498 "is required.\n");
499 return -1;
500 }
501
502 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
503 argv[0]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800504 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700505 printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
506 return -1;
507 }
508 return wpa_ctrl_command(ctrl, cmd);
509}
510
511
512static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
513 int argc, char *argv[])
514{
515 char cmd[64];
516 int res;
517
518 if (argc != 1) {
519 printf("Invalid 'wps_nfc_token' command - one argument is "
520 "required.\n");
521 return -1;
522 }
523
524 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800525 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700526 printf("Too long WPS_NFC_TOKEN command.\n");
527 return -1;
528 }
529 return wpa_ctrl_command(ctrl, cmd);
530}
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800531
532
533static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
534 int argc, char *argv[])
535{
536 char cmd[64];
537 int res;
538
539 if (argc != 2) {
540 printf("Invalid 'nfc_get_handover_sel' command - two arguments "
541 "are required.\n");
542 return -1;
543 }
544
545 res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
546 argv[0], argv[1]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800547 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800548 printf("Too long NFC_GET_HANDOVER_SEL command.\n");
549 return -1;
550 }
551 return wpa_ctrl_command(ctrl, cmd);
552}
553
Dmitry Shmidt04949592012-07-19 12:16:46 -0700554#endif /* CONFIG_WPS_NFC */
555
556
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700557static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
558 char *argv[])
559{
560 char buf[64];
561 if (argc < 1) {
562 printf("Invalid 'wps_ap_pin' command - at least one argument "
563 "is required.\n");
564 return -1;
565 }
566 if (argc > 2)
567 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
568 argv[0], argv[1], argv[2]);
569 else if (argc > 1)
570 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
571 argv[0], argv[1]);
572 else
573 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
574 return wpa_ctrl_command(ctrl, buf);
575}
576
577
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700578static int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc,
579 char *argv[])
580{
581 return wpa_ctrl_command(ctrl, "WPS_GET_STATUS");
582}
583
584
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700585static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
586 char *argv[])
587{
588 char buf[256];
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700589 char ssid_hex[2 * SSID_MAX_LEN + 1];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700590 char key_hex[2 * 64 + 1];
591 int i;
592
593 if (argc < 1) {
594 printf("Invalid 'wps_config' command - at least two arguments "
595 "are required.\n");
596 return -1;
597 }
598
599 ssid_hex[0] = '\0';
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700600 for (i = 0; i < SSID_MAX_LEN; i++) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700601 if (argv[0][i] == '\0')
602 break;
603 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
604 }
605
606 key_hex[0] = '\0';
607 if (argc > 3) {
608 for (i = 0; i < 64; i++) {
609 if (argv[3][i] == '\0')
610 break;
611 os_snprintf(&key_hex[i * 2], 3, "%02x",
612 argv[3][i]);
613 }
614 }
615
616 if (argc > 3)
617 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
618 ssid_hex, argv[1], argv[2], key_hex);
619 else if (argc > 2)
620 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
621 ssid_hex, argv[1], argv[2]);
622 else
623 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
624 ssid_hex, argv[1]);
625 return wpa_ctrl_command(ctrl, buf);
626}
627#endif /* CONFIG_WPS */
628
629
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800630static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
631 char *argv[])
632{
633 char buf[300];
634 int res;
635
636 if (argc < 2) {
637 printf("Invalid 'disassoc_imminent' command - two arguments "
638 "(STA addr and Disassociation Timer) are needed\n");
639 return -1;
640 }
641
642 res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
643 argv[0], argv[1]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800644 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800645 return -1;
646 return wpa_ctrl_command(ctrl, buf);
647}
648
649
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800650static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
651 char *argv[])
652{
653 char buf[300];
654 int res;
655
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700656 if (argc < 3) {
657 printf("Invalid 'ess_disassoc' command - three arguments (STA "
658 "addr, disassoc timer, and URL) are needed\n");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800659 return -1;
660 }
661
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700662 res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
663 argv[0], argv[1], argv[2]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800664 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800665 return -1;
666 return wpa_ctrl_command(ctrl, buf);
667}
668
669
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800670static int hostapd_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc,
671 char *argv[])
672{
673 char buf[2000], *tmp;
674 int res, i, total;
675
676 if (argc < 1) {
677 printf("Invalid 'bss_tm_req' command - at least one argument (STA addr) is needed\n");
678 return -1;
679 }
680
681 res = os_snprintf(buf, sizeof(buf), "BSS_TM_REQ %s", argv[0]);
682 if (os_snprintf_error(sizeof(buf), res))
683 return -1;
684
685 total = res;
686 for (i = 1; i < argc; i++) {
687 tmp = &buf[total];
688 res = os_snprintf(tmp, sizeof(buf) - total, " %s", argv[i]);
689 if (os_snprintf_error(sizeof(buf) - total, res))
690 return -1;
691 total += res;
692 }
693 return wpa_ctrl_command(ctrl, buf);
694}
695
696
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700697static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
698 char *argv[])
699{
700 return wpa_ctrl_command(ctrl, "GET_CONFIG");
701}
702
703
704static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
705 char *addr, size_t addr_len)
706{
707 char buf[4096], *pos;
708 size_t len;
709 int ret;
710
711 if (ctrl_conn == NULL) {
712 printf("Not connected to hostapd - command dropped.\n");
713 return -1;
714 }
715 len = sizeof(buf) - 1;
716 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
717 hostapd_cli_msg_cb);
718 if (ret == -2) {
719 printf("'%s' command timed out.\n", cmd);
720 return -2;
721 } else if (ret < 0) {
722 printf("'%s' command failed.\n", cmd);
723 return -1;
724 }
725
726 buf[len] = '\0';
727 if (memcmp(buf, "FAIL", 4) == 0)
728 return -1;
729 printf("%s", buf);
730
731 pos = buf;
732 while (*pos != '\0' && *pos != '\n')
733 pos++;
734 *pos = '\0';
735 os_strlcpy(addr, buf, addr_len);
736 return 0;
737}
738
739
740static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
741 char *argv[])
742{
743 char addr[32], cmd[64];
744
745 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
746 return 0;
747 do {
748 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
749 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
750
751 return -1;
752}
753
754
755static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
756{
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -0700757 print_help(stdout, argc > 0 ? argv[0] : NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700758 return 0;
759}
760
761
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -0700762static char ** hostapd_cli_complete_help(const char *str, int pos)
763{
764 int arg = get_cmd_arg_num(str, pos);
765 char **res = NULL;
766
767 switch (arg) {
768 case 1:
769 res = list_cmd_list();
770 break;
771 }
772
773 return res;
774}
775
776
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700777static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
778 char *argv[])
779{
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -0700780 printf("%s\n\n%s\n", hostapd_cli_version, cli_full_license);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700781 return 0;
782}
783
784
Dmitry Shmidt051af732013-10-22 13:52:46 -0700785static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl,
786 int argc, char *argv[])
787{
788 char buf[200];
789 int res;
790
791 if (argc != 1) {
792 printf("Invalid 'set_qos_map_set' command - "
793 "one argument (comma delimited QoS map set) "
794 "is needed\n");
795 return -1;
796 }
797
798 res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800799 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidt051af732013-10-22 13:52:46 -0700800 return -1;
801 return wpa_ctrl_command(ctrl, buf);
802}
803
804
805static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
806 int argc, char *argv[])
807{
808 char buf[50];
809 int res;
810
811 if (argc != 1) {
812 printf("Invalid 'send_qos_map_conf' command - "
813 "one argument (STA addr) is needed\n");
814 return -1;
815 }
816
817 res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800818 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidt051af732013-10-22 13:52:46 -0700819 return -1;
820 return wpa_ctrl_command(ctrl, buf);
821}
822
823
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800824static int hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc,
825 char *argv[])
826{
827 char buf[300];
828 int res;
829
830 if (argc < 2) {
831 printf("Invalid 'hs20_wnm_notif' command - two arguments (STA "
832 "addr and URL) are needed\n");
833 return -1;
834 }
835
836 res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s",
837 argv[0], argv[1]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800838 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800839 return -1;
840 return wpa_ctrl_command(ctrl, buf);
841}
842
843
844static int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc,
845 char *argv[])
846{
847 char buf[300];
848 int res;
849
850 if (argc < 3) {
851 printf("Invalid 'hs20_deauth_req' command - at least three arguments (STA addr, Code, Re-auth Delay) are needed\n");
852 return -1;
853 }
854
855 if (argc > 3)
856 res = os_snprintf(buf, sizeof(buf),
857 "HS20_DEAUTH_REQ %s %s %s %s",
858 argv[0], argv[1], argv[2], argv[3]);
859 else
860 res = os_snprintf(buf, sizeof(buf),
861 "HS20_DEAUTH_REQ %s %s %s",
862 argv[0], argv[1], argv[2]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800863 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800864 return -1;
865 return wpa_ctrl_command(ctrl, buf);
866}
867
868
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700869static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
870{
871 hostapd_cli_quit = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800872 if (interactive)
873 eloop_terminate();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700874 return 0;
875}
876
877
878static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
879{
880 char cmd[256];
881 if (argc != 1) {
882 printf("Invalid LEVEL command: needs one argument (debug "
883 "level)\n");
884 return 0;
885 }
886 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
887 return wpa_ctrl_command(ctrl, cmd);
888}
889
890
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -0700891static void hostapd_cli_get_interfaces(struct wpa_ctrl *ctrl,
892 struct dl_list *interfaces)
893{
894 struct dirent *dent;
895 DIR *dir;
896
897 if (!ctrl || !interfaces)
898 return;
899 dir = opendir(ctrl_iface_dir);
900 if (dir == NULL)
901 return;
902
903 while ((dent = readdir(dir))) {
904 if (strcmp(dent->d_name, ".") == 0 ||
905 strcmp(dent->d_name, "..") == 0)
906 continue;
907 cli_txt_list_add(interfaces, dent->d_name);
908 }
909 closedir(dir);
910}
911
912
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700913static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
914{
915 struct dirent *dent;
916 DIR *dir;
917
918 dir = opendir(ctrl_iface_dir);
919 if (dir == NULL) {
920 printf("Control interface directory '%s' could not be "
921 "openned.\n", ctrl_iface_dir);
922 return;
923 }
924
925 printf("Available interfaces:\n");
926 while ((dent = readdir(dir))) {
927 if (strcmp(dent->d_name, ".") == 0 ||
928 strcmp(dent->d_name, "..") == 0)
929 continue;
930 printf("%s\n", dent->d_name);
931 }
932 closedir(dir);
933}
934
935
936static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
937 char *argv[])
938{
939 if (argc < 1) {
940 hostapd_cli_list_interfaces(ctrl);
941 return 0;
942 }
943
944 hostapd_cli_close_connection();
Dmitry Shmidt71757432014-06-02 13:50:35 -0700945 os_free(ctrl_ifname);
946 ctrl_ifname = os_strdup(argv[0]);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -0700947 if (ctrl_ifname == NULL)
948 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700949
950 if (hostapd_cli_open_connection(ctrl_ifname)) {
951 printf("Connected to interface '%s.\n", ctrl_ifname);
952 if (wpa_ctrl_attach(ctrl_conn) == 0) {
953 hostapd_cli_attached = 1;
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -0700954 register_event_handler(ctrl_conn);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700955 } else {
956 printf("Warning: Failed to attach to "
957 "hostapd.\n");
958 }
959 } else {
960 printf("Could not connect to interface '%s' - re-trying\n",
961 ctrl_ifname);
962 }
963 return 0;
964}
965
966
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -0700967static char ** hostapd_complete_interface(const char *str, int pos)
968{
969 int arg = get_cmd_arg_num(str, pos);
970 char **res = NULL;
971 DEFINE_DL_LIST(interfaces);
972
973 switch (arg) {
974 case 1:
975 hostapd_cli_get_interfaces(ctrl_conn, &interfaces);
976 res = cli_txt_list_array(&interfaces);
977 cli_txt_list_flush(&interfaces);
978 break;
979 }
980
981 return res;
982}
983
984
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700985static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
986{
987 char cmd[256];
988 int res;
989
990 if (argc != 2) {
991 printf("Invalid SET command: needs two arguments (variable "
992 "name and value)\n");
993 return -1;
994 }
995
996 res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800997 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700998 printf("Too long SET command.\n");
999 return -1;
1000 }
1001 return wpa_ctrl_command(ctrl, cmd);
1002}
1003
1004
1005static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
1006{
1007 char cmd[256];
1008 int res;
1009
1010 if (argc != 1) {
1011 printf("Invalid GET command: needs one argument (variable "
1012 "name)\n");
1013 return -1;
1014 }
1015
1016 res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001017 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001018 printf("Too long GET command.\n");
1019 return -1;
1020 }
1021 return wpa_ctrl_command(ctrl, cmd);
1022}
1023
1024
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001025#ifdef CONFIG_FST
1026static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[])
1027{
1028 char cmd[256];
1029 int res;
1030 int i;
1031 int total;
1032
1033 if (argc <= 0) {
1034 printf("FST command: parameters are required.\n");
1035 return -1;
1036 }
1037
1038 total = os_snprintf(cmd, sizeof(cmd), "FST-MANAGER");
1039
1040 for (i = 0; i < argc; i++) {
1041 res = os_snprintf(cmd + total, sizeof(cmd) - total, " %s",
1042 argv[i]);
1043 if (os_snprintf_error(sizeof(cmd) - total, res)) {
1044 printf("Too long fst command.\n");
1045 return -1;
1046 }
1047 total += res;
1048 }
1049 return wpa_ctrl_command(ctrl, cmd);
1050}
1051#endif /* CONFIG_FST */
1052
1053
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001054static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
1055 int argc, char *argv[])
1056{
1057 char cmd[256];
1058 int res;
1059 int i;
1060 char *tmp;
1061 int total;
1062
1063 if (argc < 2) {
1064 printf("Invalid chan_switch command: needs at least two "
1065 "arguments (count and freq)\n"
1066 "usage: <cs_count> <freq> [sec_channel_offset=] "
1067 "[center_freq1=] [center_freq2=] [bandwidth=] "
1068 "[blocktx] [ht|vht]\n");
1069 return -1;
1070 }
1071
1072 res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
1073 argv[0], argv[1]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001074 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001075 printf("Too long CHAN_SWITCH command.\n");
1076 return -1;
1077 }
1078
1079 total = res;
1080 for (i = 2; i < argc; i++) {
1081 tmp = cmd + total;
1082 res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001083 if (os_snprintf_error(sizeof(cmd) - total, res)) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001084 printf("Too long CHAN_SWITCH command.\n");
1085 return -1;
1086 }
1087 total += res;
1088 }
1089 return wpa_ctrl_command(ctrl, cmd);
1090}
1091
1092
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001093static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc,
1094 char *argv[])
1095{
1096 return wpa_ctrl_command(ctrl, "ENABLE");
1097}
1098
1099
1100static int hostapd_cli_cmd_reload(struct wpa_ctrl *ctrl, int argc,
1101 char *argv[])
1102{
1103 return wpa_ctrl_command(ctrl, "RELOAD");
1104}
1105
1106
1107static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc,
1108 char *argv[])
1109{
1110 return wpa_ctrl_command(ctrl, "DISABLE");
1111}
1112
1113
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001114static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
1115{
1116 char cmd[256];
1117 int res;
1118
1119 if (argc < 2 || argc > 3) {
1120 printf("Invalid vendor command\n"
1121 "usage: <vendor id> <command id> [<hex formatted command argument>]\n");
1122 return -1;
1123 }
1124
1125 res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
1126 argc == 3 ? argv[2] : "");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001127 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001128 printf("Too long VENDOR command.\n");
1129 return -1;
1130 }
1131 return wpa_ctrl_command(ctrl, cmd);
1132}
1133
1134
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001135static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc,
1136 char *argv[])
1137{
1138 return wpa_ctrl_command(ctrl, "ERP_FLUSH");
1139}
1140
1141
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001142static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc,
1143 char *argv[])
1144{
1145 char cmd[256];
1146 int res;
1147
1148 res = os_snprintf(cmd, sizeof(cmd), "LOG_LEVEL%s%s%s%s",
1149 argc >= 1 ? " " : "",
1150 argc >= 1 ? argv[0] : "",
1151 argc == 2 ? " " : "",
1152 argc == 2 ? argv[1] : "");
1153 if (os_snprintf_error(sizeof(cmd), res)) {
1154 printf("Too long option\n");
1155 return -1;
1156 }
1157 return wpa_ctrl_command(ctrl, cmd);
1158}
1159
1160
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001161static int hostapd_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
1162{
1163 if (argc == 0)
1164 return -1;
1165 return hostapd_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]);
1166}
1167
1168
Dmitry Shmidte4663042016-04-04 10:07:49 -07001169static int hostapd_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
1170{
1171 return wpa_ctrl_command(ctrl, "PMKSA");
1172}
1173
1174
1175static int hostapd_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc,
1176 char *argv[])
1177{
1178 return wpa_ctrl_command(ctrl, "PMKSA_FLUSH");
1179}
1180
1181
Dmitry Shmidt849734c2016-05-27 09:59:01 -07001182static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc,
1183 char *argv[])
1184{
1185 char cmd[2048];
1186 int res;
1187
1188 if (argc < 3 || argc > 5) {
1189 printf("Invalid set_neighbor command: needs 3-5 arguments\n");
1190 return -1;
1191 }
1192
1193 res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s",
1194 argv[0], argv[1], argv[2], argc >= 4 ? argv[3] : "",
1195 argc == 5 ? argv[4] : "");
1196 if (os_snprintf_error(sizeof(cmd), res)) {
1197 printf("Too long SET_NEIGHBOR command.\n");
1198 return -1;
1199 }
1200 return wpa_ctrl_command(ctrl, cmd);
1201}
1202
1203
1204static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc,
1205 char *argv[])
1206{
1207 char cmd[400];
1208 int res;
1209
1210 if (argc != 2) {
1211 printf("Invalid remove_neighbor command: needs 2 arguments\n");
1212 return -1;
1213 }
1214
1215 res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NEIGHBOR %s %s",
1216 argv[0], argv[1]);
1217 if (os_snprintf_error(sizeof(cmd), res)) {
1218 printf("Too long REMOVE_NEIGHBOR command.\n");
1219 return -1;
1220 }
1221 return wpa_ctrl_command(ctrl, cmd);
1222}
1223
1224
1225static int hostapd_cli_cmd_req_lci(struct wpa_ctrl *ctrl, int argc,
1226 char *argv[])
1227{
1228 char cmd[256];
1229 int res;
1230
1231 if (argc != 1) {
1232 printf("Invalid req_lci command - requires destination address\n");
1233 return -1;
1234 }
1235
1236 res = os_snprintf(cmd, sizeof(cmd), "REQ_LCI %s", argv[0]);
1237 if (os_snprintf_error(sizeof(cmd), res)) {
1238 printf("Too long REQ_LCI command.\n");
1239 return -1;
1240 }
1241 return wpa_ctrl_command(ctrl, cmd);
1242}
1243
1244
1245static int hostapd_cli_cmd_req_range(struct wpa_ctrl *ctrl, int argc,
1246 char *argv[])
1247{
1248 if (argc < 4) {
1249 printf("Invalid req_range command: needs at least 4 arguments - dest address, randomization interval, min AP count, and 1 to 16 AP addresses\n");
1250 return -1;
1251 }
1252
1253 return hostapd_cli_cmd(ctrl, "REQ_RANGE", 4, argc, argv);
1254}
1255
1256
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07001257static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
1258 char *argv[])
1259{
1260 return wpa_ctrl_command(ctrl, "DRIVER_FLAGS");
1261}
1262
1263
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001264struct hostapd_cli_cmd {
1265 const char *cmd;
1266 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001267 char ** (*completion)(const char *str, int pos);
1268 const char *usage;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001269};
1270
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07001271static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001272 { "ping", hostapd_cli_cmd_ping, NULL,
1273 "= pings hostapd" },
1274 { "mib", hostapd_cli_cmd_mib, NULL,
1275 "= get MIB variables (dot1x, dot11, radius)" },
1276 { "relog", hostapd_cli_cmd_relog, NULL, NULL },
1277 { "status", hostapd_cli_cmd_status, NULL, NULL },
1278 { "sta", hostapd_cli_cmd_sta, NULL,
1279 "<addr> = get MIB variables for one station" },
1280 { "all_sta", hostapd_cli_cmd_all_sta, NULL,
1281 "= get MIB variables for all stations" },
1282 { "new_sta", hostapd_cli_cmd_new_sta, NULL,
1283 "<addr> = add a new station" },
1284 { "deauthenticate", hostapd_cli_cmd_deauthenticate,
1285 hostapd_complete_deauthenticate,
1286 "<addr> = deauthenticate a station" },
1287 { "disassociate", hostapd_cli_cmd_disassociate,
1288 hostapd_complete_disassociate,
1289 "<addr> = disassociate a station" },
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07001290#ifdef CONFIG_TAXONOMY
1291 { "signature", hostapd_cli_cmd_signature, NULL,
1292 "<addr> = get taxonomy signature for a station" },
1293#endif /* CONFIG_TAXONOMY */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001294#ifdef CONFIG_IEEE80211W
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001295 { "sa_query", hostapd_cli_cmd_sa_query, NULL,
1296 "<addr> = send SA Query to a station" },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001297#endif /* CONFIG_IEEE80211W */
1298#ifdef CONFIG_WPS
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001299 { "wps_pin", hostapd_cli_cmd_wps_pin, NULL,
1300 "<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" },
1301 { "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL,
1302 "<PIN> = verify PIN checksum" },
1303 { "wps_pbc", hostapd_cli_cmd_wps_pbc, NULL,
1304 "= indicate button pushed to initiate PBC" },
1305 { "wps_cancel", hostapd_cli_cmd_wps_cancel, NULL,
1306 "= cancel the pending WPS operation" },
Dmitry Shmidt04949592012-07-19 12:16:46 -07001307#ifdef CONFIG_WPS_NFC
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001308 { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read, NULL,
1309 "<hexdump> = report read NFC tag with WPS data" },
1310 { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token, NULL,
1311 "<WPS/NDEF> = build NFC configuration token" },
1312 { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token, NULL,
1313 "<WPS/NDEF/enable/disable> = manager NFC password token" },
1314 { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel, NULL,
1315 NULL },
Dmitry Shmidt04949592012-07-19 12:16:46 -07001316#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001317 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin, NULL,
1318 "<cmd> [params..] = enable/disable AP PIN" },
1319 { "wps_config", hostapd_cli_cmd_wps_config, NULL,
1320 "<SSID> <auth> <encr> <key> = configure AP" },
1321 { "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL,
1322 "= show current WPS status" },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001323#endif /* CONFIG_WPS */
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001324 { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL, NULL },
1325 { "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL, NULL },
1326 { "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL, NULL },
1327 { "get_config", hostapd_cli_cmd_get_config, NULL,
1328 "= show current configuration" },
1329 { "help", hostapd_cli_cmd_help, hostapd_cli_complete_help,
1330 "= show this usage help" },
1331 { "interface", hostapd_cli_cmd_interface, hostapd_complete_interface,
1332 "[ifname] = show interfaces/select interface" },
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001333#ifdef CONFIG_FST
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001334 { "fst", hostapd_cli_cmd_fst, NULL, NULL },
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001335#endif /* CONFIG_FST */
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001336 { "raw", hostapd_cli_cmd_raw, NULL, NULL },
1337 { "level", hostapd_cli_cmd_level, NULL,
1338 "<debug level> = change debug level" },
1339 { "license", hostapd_cli_cmd_license, NULL,
1340 "= show full hostapd_cli license" },
1341 { "quit", hostapd_cli_cmd_quit, NULL,
1342 "= exit hostapd_cli" },
1343 { "set", hostapd_cli_cmd_set, NULL, NULL },
1344 { "get", hostapd_cli_cmd_get, NULL, NULL },
1345 { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL, NULL },
1346 { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf, NULL, NULL },
1347 { "chan_switch", hostapd_cli_cmd_chan_switch, NULL, NULL },
1348 { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL, NULL },
1349 { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL, NULL },
1350 { "vendor", hostapd_cli_cmd_vendor, NULL, NULL },
1351 { "enable", hostapd_cli_cmd_enable, NULL, NULL },
1352 { "reload", hostapd_cli_cmd_reload, NULL, NULL },
1353 { "disable", hostapd_cli_cmd_disable, NULL, NULL },
1354 { "erp_flush", hostapd_cli_cmd_erp_flush, NULL, NULL },
1355 { "log_level", hostapd_cli_cmd_log_level, NULL, NULL },
1356 { "pmksa", hostapd_cli_cmd_pmksa, NULL, NULL },
1357 { "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL, NULL },
1358 { "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL, NULL },
1359 { "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL, NULL },
1360 { "req_lci", hostapd_cli_cmd_req_lci, NULL, NULL },
1361 { "req_range", hostapd_cli_cmd_req_range, NULL, NULL },
1362 { "driver_flags", hostapd_cli_cmd_driver_flags, NULL, NULL },
1363 { NULL, NULL, NULL, NULL }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001364};
1365
1366
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001367/*
1368 * Prints command usage, lines are padded with the specified string.
1369 */
1370static void print_cmd_help(FILE *stream, const struct hostapd_cli_cmd *cmd,
1371 const char *pad)
1372{
1373 char c;
1374 size_t n;
1375
1376 if (cmd->usage == NULL)
1377 return;
1378 fprintf(stream, "%s%s ", pad, cmd->cmd);
1379 for (n = 0; (c = cmd->usage[n]); n++) {
1380 fprintf(stream, "%c", c);
1381 if (c == '\n')
1382 fprintf(stream, "%s", pad);
1383 }
1384 fprintf(stream, "\n");
1385}
1386
1387
1388static void print_help(FILE *stream, const char *cmd)
1389{
1390 int n;
1391
1392 fprintf(stream, "commands:\n");
1393 for (n = 0; hostapd_cli_commands[n].cmd; n++) {
1394 if (cmd == NULL || str_starts(hostapd_cli_commands[n].cmd, cmd))
1395 print_cmd_help(stream, &hostapd_cli_commands[n], " ");
1396 }
1397}
1398
1399
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001400static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
1401{
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07001402 const struct hostapd_cli_cmd *cmd, *match = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001403 int count;
1404
1405 count = 0;
1406 cmd = hostapd_cli_commands;
1407 while (cmd->cmd) {
1408 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
1409 match = cmd;
1410 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1411 /* we have an exact match */
1412 count = 1;
1413 break;
1414 }
1415 count++;
1416 }
1417 cmd++;
1418 }
1419
1420 if (count > 1) {
1421 printf("Ambiguous command '%s'; possible commands:", argv[0]);
1422 cmd = hostapd_cli_commands;
1423 while (cmd->cmd) {
1424 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
1425 0) {
1426 printf(" %s", cmd->cmd);
1427 }
1428 cmd++;
1429 }
1430 printf("\n");
1431 } else if (count == 0) {
1432 printf("Unknown command '%s'\n", argv[0]);
1433 } else {
1434 match->handler(ctrl, argc - 1, &argv[1]);
1435 }
1436}
1437
1438
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001439static void cli_event(const char *str)
1440{
1441 const char *start, *s;
1442
1443 start = os_strchr(str, '>');
1444 if (start == NULL)
1445 return;
1446
1447 start++;
1448
1449 if (str_starts(start, AP_STA_CONNECTED)) {
1450 s = os_strchr(start, ' ');
1451 if (s == NULL)
1452 return;
1453 cli_txt_list_add(&stations, s + 1);
1454 return;
1455 }
1456
1457 if (str_starts(start, AP_STA_DISCONNECTED)) {
1458 s = os_strchr(start, ' ');
1459 if (s == NULL)
1460 return;
1461 cli_txt_list_del_addr(&stations, s + 1);
1462 return;
1463 }
1464}
1465
1466
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001467static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
1468 int action_monitor)
1469{
1470 int first = 1;
1471 if (ctrl_conn == NULL)
1472 return;
1473 while (wpa_ctrl_pending(ctrl)) {
1474 char buf[256];
1475 size_t len = sizeof(buf) - 1;
1476 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
1477 buf[len] = '\0';
1478 if (action_monitor)
1479 hostapd_cli_action_process(buf, len);
1480 else {
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001481 cli_event(buf);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001482 if (in_read && first)
1483 printf("\n");
1484 first = 0;
1485 printf("%s\n", buf);
1486 }
1487 } else {
1488 printf("Could not read pending message.\n");
1489 break;
1490 }
1491 }
1492}
1493
1494
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001495static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001496{
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001497 hostapd_cli_recv_pending(ctrl_conn, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001498}
1499
1500
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001501static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001502{
1503 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
1504 printf("Connection to hostapd lost - trying to reconnect\n");
1505 hostapd_cli_close_connection();
1506 }
1507 if (!ctrl_conn) {
1508 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1509 if (ctrl_conn) {
1510 printf("Connection to hostapd re-established\n");
1511 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1512 hostapd_cli_attached = 1;
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001513 register_event_handler(ctrl_conn);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001514 } else {
1515 printf("Warning: Failed to attach to "
1516 "hostapd.\n");
1517 }
1518 }
1519 }
1520 if (ctrl_conn)
1521 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001522 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1523}
1524
1525
1526static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
1527{
1528 eloop_terminate();
1529}
1530
1531
1532static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
1533{
1534 char *argv[max_args];
1535 int argc;
1536 argc = tokenize_cmd(cmd, argv);
1537 if (argc)
1538 wpa_request(ctrl_conn, argc, argv);
1539}
1540
1541
1542static void hostapd_cli_edit_eof_cb(void *ctx)
1543{
1544 eloop_terminate();
1545}
1546
1547
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001548static char ** list_cmd_list(void)
1549{
1550 char **res;
1551 int i, count;
1552
1553 count = ARRAY_SIZE(hostapd_cli_commands);
1554 res = os_calloc(count + 1, sizeof(char *));
1555 if (res == NULL)
1556 return NULL;
1557
1558 for (i = 0; hostapd_cli_commands[i].cmd; i++) {
1559 res[i] = os_strdup(hostapd_cli_commands[i].cmd);
1560 if (res[i] == NULL)
1561 break;
1562 }
1563
1564 return res;
1565}
1566
1567
1568static char ** hostapd_cli_cmd_completion(const char *cmd, const char *str,
1569 int pos)
1570{
1571 int i;
1572
1573 for (i = 0; hostapd_cli_commands[i].cmd; i++) {
1574 if (os_strcasecmp(hostapd_cli_commands[i].cmd, cmd) != 0)
1575 continue;
1576 if (hostapd_cli_commands[i].completion)
1577 return hostapd_cli_commands[i].completion(str, pos);
1578 if (!hostapd_cli_commands[i].usage)
1579 return NULL;
1580 edit_clear_line();
1581 printf("\r%s\n", hostapd_cli_commands[i].usage);
1582 edit_redraw();
1583 break;
1584 }
1585
1586 return NULL;
1587}
1588
1589
1590static char ** hostapd_cli_edit_completion_cb(void *ctx, const char *str,
1591 int pos)
1592{
1593 char **res;
1594 const char *end;
1595 char *cmd;
1596
1597 end = os_strchr(str, ' ');
1598 if (end == NULL || str + pos < end)
1599 return list_cmd_list();
1600
1601 cmd = os_malloc(pos + 1);
1602 if (cmd == NULL)
1603 return NULL;
1604 os_memcpy(cmd, str, pos);
1605 cmd[end - str] = '\0';
1606 res = hostapd_cli_cmd_completion(cmd, str, pos);
1607 os_free(cmd);
1608 return res;
1609}
1610
1611
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001612static void hostapd_cli_interactive(void)
1613{
1614 printf("\nInteractive mode\n\n");
1615
1616 eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
1617 edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001618 hostapd_cli_edit_completion_cb, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001619 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1620
1621 eloop_run();
1622
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001623 cli_txt_list_flush(&stations);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001624 edit_deinit(NULL, NULL);
1625 eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
1626}
1627
1628
1629static void hostapd_cli_cleanup(void)
1630{
1631 hostapd_cli_close_connection();
1632 if (pid_file)
1633 os_daemonize_terminate(pid_file);
1634
1635 os_program_deinit();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001636}
1637
1638
1639static void hostapd_cli_action(struct wpa_ctrl *ctrl)
1640{
1641 fd_set rfds;
1642 int fd, res;
1643 struct timeval tv;
1644 char buf[256];
1645 size_t len;
1646
1647 fd = wpa_ctrl_get_fd(ctrl);
1648
1649 while (!hostapd_cli_quit) {
1650 FD_ZERO(&rfds);
1651 FD_SET(fd, &rfds);
1652 tv.tv_sec = ping_interval;
1653 tv.tv_usec = 0;
1654 res = select(fd + 1, &rfds, NULL, NULL, &tv);
1655 if (res < 0 && errno != EINTR) {
1656 perror("select");
1657 break;
1658 }
1659
1660 if (FD_ISSET(fd, &rfds))
1661 hostapd_cli_recv_pending(ctrl, 0, 1);
1662 else {
1663 len = sizeof(buf) - 1;
1664 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1665 hostapd_cli_action_process) < 0 ||
1666 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
1667 printf("hostapd did not reply to PING "
1668 "command - exiting\n");
1669 break;
1670 }
1671 }
1672 }
1673}
1674
1675
1676int main(int argc, char *argv[])
1677{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001678 int warning_displayed = 0;
1679 int c;
1680 int daemonize = 0;
1681
1682 if (os_program_init())
1683 return -1;
1684
1685 for (;;) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001686 c = getopt(argc, argv, "a:BhG:i:p:P:s:v");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001687 if (c < 0)
1688 break;
1689 switch (c) {
1690 case 'a':
1691 action_file = optarg;
1692 break;
1693 case 'B':
1694 daemonize = 1;
1695 break;
1696 case 'G':
1697 ping_interval = atoi(optarg);
1698 break;
1699 case 'h':
1700 usage();
1701 return 0;
1702 case 'v':
1703 printf("%s\n", hostapd_cli_version);
1704 return 0;
1705 case 'i':
1706 os_free(ctrl_ifname);
1707 ctrl_ifname = os_strdup(optarg);
1708 break;
1709 case 'p':
1710 ctrl_iface_dir = optarg;
1711 break;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001712 case 'P':
1713 pid_file = optarg;
1714 break;
1715 case 's':
1716 client_socket_dir = optarg;
1717 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001718 default:
1719 usage();
1720 return -1;
1721 }
1722 }
1723
1724 interactive = (argc == optind) && (action_file == NULL);
1725
1726 if (interactive) {
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001727 printf("%s\n\n%s\n\n", hostapd_cli_version, cli_license);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001728 }
1729
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001730 if (eloop_init())
1731 return -1;
1732
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001733 for (;;) {
1734 if (ctrl_ifname == NULL) {
1735 struct dirent *dent;
1736 DIR *dir = opendir(ctrl_iface_dir);
1737 if (dir) {
1738 while ((dent = readdir(dir))) {
1739 if (os_strcmp(dent->d_name, ".") == 0
1740 ||
1741 os_strcmp(dent->d_name, "..") == 0)
1742 continue;
1743 printf("Selected interface '%s'\n",
1744 dent->d_name);
1745 ctrl_ifname = os_strdup(dent->d_name);
1746 break;
1747 }
1748 closedir(dir);
1749 }
1750 }
1751 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1752 if (ctrl_conn) {
1753 if (warning_displayed)
1754 printf("Connection established.\n");
1755 break;
1756 }
1757
1758 if (!interactive) {
1759 perror("Failed to connect to hostapd - "
1760 "wpa_ctrl_open");
1761 return -1;
1762 }
1763
1764 if (!warning_displayed) {
1765 printf("Could not connect to hostapd - re-trying\n");
1766 warning_displayed = 1;
1767 }
1768 os_sleep(1, 0);
1769 continue;
1770 }
1771
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001772 if (interactive || action_file) {
1773 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1774 hostapd_cli_attached = 1;
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001775 register_event_handler(ctrl_conn);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001776 } else {
1777 printf("Warning: Failed to attach to hostapd.\n");
1778 if (action_file)
1779 return -1;
1780 }
1781 }
1782
Dmitry Shmidtb97e4282016-02-08 10:16:07 -08001783 if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001784 return -1;
1785
1786 if (interactive)
1787 hostapd_cli_interactive();
1788 else if (action_file)
1789 hostapd_cli_action(ctrl_conn);
1790 else
1791 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1792
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07001793 unregister_event_handler(ctrl_conn);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001794 os_free(ctrl_ifname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001795 eloop_destroy();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001796 hostapd_cli_cleanup();
1797 return 0;
1798}
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08001799
1800#else /* CONFIG_NO_CTRL_IFACE */
1801
1802int main(int argc, char *argv[])
1803{
1804 return -1;
1805}
1806
1807#endif /* CONFIG_NO_CTRL_IFACE */