]> git.ipfire.org Git - thirdparty/hostap.git/blame - hostapd/hostapd_cli.c
hostapd_cli: Implement event handler
[thirdparty/hostap.git] / hostapd / hostapd_cli.c
CommitLineData
6fc6879b
JM
1/*
2 * hostapd - command line interface for hostapd daemon
15c56067 3 * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
6fc6879b 4 *
0f3d578e
JM
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
6fc6879b
JM
7 */
8
9#include "includes.h"
10#include <dirent.h>
11
90973fb2 12#include "common/wpa_ctrl.h"
d9d1b952 13#include "common/ieee802_11_defs.h"
42838059
JM
14#include "utils/common.h"
15#include "utils/eloop.h"
16#include "utils/edit.h"
90973fb2 17#include "common/version.h"
977c0796 18#include "common/cli.h"
6fc6879b 19
56885eec 20#ifndef CONFIG_NO_CTRL_IFACE
6fc6879b 21
8b423edb 22static const char *const hostapd_cli_version =
6fc6879b 23"hostapd_cli v" VERSION_STR "\n"
15c56067 24"Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors";
6fc6879b
JM
25
26
8b423edb 27static const char *const hostapd_cli_license =
331f89ff
JM
28"This software may be distributed under the terms of the BSD license.\n"
29"See README for more details.\n";
6fc6879b 30
8b423edb 31static const char *const hostapd_cli_full_license =
331f89ff 32"This software may be distributed under the terms of the BSD license.\n"
6fc6879b
JM
33"\n"
34"Redistribution and use in source and binary forms, with or without\n"
35"modification, are permitted provided that the following conditions are\n"
36"met:\n"
37"\n"
38"1. Redistributions of source code must retain the above copyright\n"
39" notice, this list of conditions and the following disclaimer.\n"
40"\n"
41"2. Redistributions in binary form must reproduce the above copyright\n"
42" notice, this list of conditions and the following disclaimer in the\n"
43" documentation and/or other materials provided with the distribution.\n"
44"\n"
45"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
46" names of its contributors may be used to endorse or promote products\n"
47" derived from this software without specific prior written permission.\n"
48"\n"
49"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
50"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
51"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
52"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
53"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
54"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
55"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
56"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
57"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
58"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
59"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
60"\n";
61
6fc6879b
JM
62static struct wpa_ctrl *ctrl_conn;
63static int hostapd_cli_quit = 0;
64static int hostapd_cli_attached = 0;
2d39a4d8
JJ
65
66#ifndef CONFIG_CTRL_IFACE_DIR
67#define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd"
68#endif /* CONFIG_CTRL_IFACE_DIR */
69static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
4ae71209 70static const char *client_socket_dir = NULL;
2d39a4d8 71
6fc6879b 72static char *ctrl_ifname = NULL;
bae92174
GD
73static const char *pid_file = NULL;
74static const char *action_file = NULL;
1cc84c1c 75static int ping_interval = 5;
42838059 76static int interactive = 0;
1cef253a 77static int event_handler_registered = 0;
6fc6879b 78
01938838 79static void print_help(FILE *stream, const char *cmd);
6cad0bff 80static char ** list_cmd_list(void);
1cef253a 81static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx);
01938838 82
6fc6879b
JM
83
84static void usage(void)
85{
86 fprintf(stderr, "%s\n", hostapd_cli_version);
bae92174
GD
87 fprintf(stderr,
88 "\n"
89 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
90 "[-a<path>] \\\n"
b8e5426d 91 " [-P<pid file>] [-G<ping interval>] [command..]\n"
6fc6879b
JM
92 "\n"
93 "Options:\n"
94 " -h help (show this usage text)\n"
95 " -v shown version information\n"
96 " -p<path> path to find control sockets (default: "
97 "/var/run/hostapd)\n"
4ae71209
MM
98 " -s<dir_path> dir path to open client sockets (default: "
99 CONFIG_CTRL_IFACE_DIR ")\n"
bae92174
GD
100 " -a<file> run in daemon mode executing the action file "
101 "based on events\n"
102 " from hostapd\n"
103 " -B run a daemon in the background\n"
6fc6879b
JM
104 " -i<ifname> Interface to listen on (default: first "
105 "interface found in the\n"
01938838
MK
106 " socket path)\n\n");
107 print_help(stderr, NULL);
108}
109
110
6cad0bff
MK
111static int get_cmd_arg_num(const char *str, int pos)
112{
113 int arg = 0, i;
114
115 for (i = 0; i <= pos; i++) {
116 if (str[i] != ' ') {
117 arg++;
118 while (i <= pos && str[i] != ' ')
119 i++;
120 }
121 }
122
123 if (arg > 0)
124 arg--;
125 return arg;
126}
127
128
01938838
MK
129static int str_starts(const char *src, const char *match)
130{
131 return os_strncmp(src, match, os_strlen(match)) == 0;
6fc6879b
JM
132}
133
134
1cef253a
MK
135static void register_event_handler(struct wpa_ctrl *ctrl)
136{
137 if (!ctrl_conn)
138 return;
139 if (interactive) {
140 event_handler_registered =
141 !eloop_register_read_sock(wpa_ctrl_get_fd(ctrl),
142 hostapd_cli_receive,
143 NULL, NULL);
144 }
145}
146
147
148static void unregister_event_handler(struct wpa_ctrl *ctrl)
149{
150 if (!ctrl_conn)
151 return;
152 if (interactive && event_handler_registered) {
153 eloop_unregister_read_sock(wpa_ctrl_get_fd(ctrl));
154 event_handler_registered = 0;
155 }
156}
157
158
6fc6879b
JM
159static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
160{
56885eec 161#ifndef CONFIG_CTRL_IFACE_UDP
6fc6879b
JM
162 char *cfile;
163 int flen;
56885eec 164#endif /* !CONFIG_CTRL_IFACE_UDP */
6fc6879b
JM
165
166 if (ifname == NULL)
167 return NULL;
168
56885eec
JD
169#ifdef CONFIG_CTRL_IFACE_UDP
170 ctrl_conn = wpa_ctrl_open(ifname);
171 return ctrl_conn;
172#else /* CONFIG_CTRL_IFACE_UDP */
6fc6879b
JM
173 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
174 cfile = malloc(flen);
175 if (cfile == NULL)
176 return NULL;
177 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
178
4ae71209
MM
179 if (client_socket_dir && client_socket_dir[0] &&
180 access(client_socket_dir, F_OK) < 0) {
181 perror(client_socket_dir);
182 free(cfile);
183 return NULL;
184 }
185
186 ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir);
6fc6879b
JM
187 free(cfile);
188 return ctrl_conn;
56885eec 189#endif /* CONFIG_CTRL_IFACE_UDP */
6fc6879b
JM
190}
191
192
193static void hostapd_cli_close_connection(void)
194{
195 if (ctrl_conn == NULL)
196 return;
197
1cef253a 198 unregister_event_handler(ctrl_conn);
6fc6879b
JM
199 if (hostapd_cli_attached) {
200 wpa_ctrl_detach(ctrl_conn);
201 hostapd_cli_attached = 0;
202 }
203 wpa_ctrl_close(ctrl_conn);
204 ctrl_conn = NULL;
205}
206
207
208static void hostapd_cli_msg_cb(char *msg, size_t len)
209{
210 printf("%s\n", msg);
211}
212
213
214static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
215{
216 char buf[4096];
217 size_t len;
218 int ret;
219
220 if (ctrl_conn == NULL) {
221 printf("Not connected to hostapd - command dropped.\n");
222 return -1;
223 }
224 len = sizeof(buf) - 1;
225 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
226 hostapd_cli_msg_cb);
227 if (ret == -2) {
228 printf("'%s' command timed out.\n", cmd);
229 return -2;
230 } else if (ret < 0) {
231 printf("'%s' command failed.\n", cmd);
232 return -1;
233 }
234 if (print) {
235 buf[len] = '\0';
236 printf("%s", buf);
237 }
238 return 0;
239}
240
241
242static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
243{
244 return _wpa_ctrl_command(ctrl, cmd, 1);
245}
246
247
12605642
DL
248static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
249 char *argv[])
250{
251 int i, res;
252 char *pos, *end;
253
254 pos = buf;
255 end = buf + buflen;
256
257 res = os_snprintf(pos, end - pos, "%s", cmd);
258 if (os_snprintf_error(end - pos, res))
259 goto fail;
260 pos += res;
261
262 for (i = 0; i < argc; i++) {
263 res = os_snprintf(pos, end - pos, " %s", argv[i]);
264 if (os_snprintf_error(end - pos, res))
265 goto fail;
266 pos += res;
267 }
268
269 buf[buflen - 1] = '\0';
270 return 0;
271
272fail:
273 printf("Too long command\n");
274 return -1;
275}
276
277
278static int hostapd_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd,
279 int min_args, int argc, char *argv[])
280{
281 char buf[4096];
282
283 if (argc < min_args) {
284 printf("Invalid %s command - at least %d argument%s required.\n",
285 cmd, min_args, min_args > 1 ? "s are" : " is");
286 return -1;
287 }
288 if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0)
289 return -1;
290 return wpa_ctrl_command(ctrl, buf);
291}
292
293
6fc6879b
JM
294static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
295{
296 return wpa_ctrl_command(ctrl, "PING");
297}
298
299
b41a47c0
BG
300static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
301{
302 return wpa_ctrl_command(ctrl, "RELOG");
303}
304
305
5ae6449c
JM
306static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
307{
f0cbb986
JM
308 if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
309 return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
5ae6449c
JM
310 return wpa_ctrl_command(ctrl, "STATUS");
311}
312
313
6fc6879b
JM
314static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
315{
4c03a2b3
JM
316 if (argc > 0) {
317 char buf[100];
318 os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]);
319 return wpa_ctrl_command(ctrl, buf);
320 }
6fc6879b
JM
321 return wpa_ctrl_command(ctrl, "MIB");
322}
323
324
bae92174
GD
325static int hostapd_cli_exec(const char *program, const char *arg1,
326 const char *arg2)
327{
5d4fa2a2 328 char *arg;
bae92174
GD
329 size_t len;
330 int res;
bae92174 331
5d4fa2a2
JM
332 len = os_strlen(arg1) + os_strlen(arg2) + 2;
333 arg = os_malloc(len);
334 if (arg == NULL)
bae92174 335 return -1;
5d4fa2a2
JM
336 os_snprintf(arg, len, "%s %s", arg1, arg2);
337 res = os_exec(program, arg, 1);
338 os_free(arg);
339
340 return res;
bae92174
GD
341}
342
343
344static void hostapd_cli_action_process(char *msg, size_t len)
345{
346 const char *pos;
347
348 pos = msg;
349 if (*pos == '<') {
350 pos = os_strchr(pos, '>');
351 if (pos)
352 pos++;
353 else
354 pos = msg;
355 }
356
357 hostapd_cli_exec(action_file, ctrl_ifname, pos);
358}
359
360
6fc6879b
JM
361static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
362{
363 char buf[64];
ea23df65
JM
364 if (argc < 1) {
365 printf("Invalid 'sta' command - at least one argument, STA "
6fc6879b
JM
366 "address, is required.\n");
367 return -1;
368 }
ea23df65
JM
369 if (argc > 1)
370 snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]);
371 else
372 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
6fc6879b
JM
373 return wpa_ctrl_command(ctrl, buf);
374}
375
376
377static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
378 char *argv[])
379{
380 char buf[64];
381 if (argc != 1) {
382 printf("Invalid 'new_sta' command - exactly one argument, STA "
383 "address, is required.\n");
384 return -1;
385 }
386 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
387 return wpa_ctrl_command(ctrl, buf);
388}
389
390
90a3206a
JM
391static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
392 char *argv[])
393{
394 char buf[64];
b91ab76e 395 if (argc < 1) {
90a3206a
JM
396 printf("Invalid 'deauthenticate' command - exactly one "
397 "argument, STA address, is required.\n");
398 return -1;
399 }
b91ab76e
JM
400 if (argc > 1)
401 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
402 argv[0], argv[1]);
403 else
404 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
90a3206a
JM
405 return wpa_ctrl_command(ctrl, buf);
406}
407
408
409static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
410 char *argv[])
411{
412 char buf[64];
b91ab76e 413 if (argc < 1) {
90a3206a
JM
414 printf("Invalid 'disassociate' command - exactly one "
415 "argument, STA address, is required.\n");
416 return -1;
417 }
b91ab76e
JM
418 if (argc > 1)
419 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
420 argv[0], argv[1]);
421 else
422 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
90a3206a
JM
423 return wpa_ctrl_command(ctrl, buf);
424}
425
426
88b4b424
JM
427#ifdef CONFIG_IEEE80211W
428static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
429 char *argv[])
430{
431 char buf[64];
432 if (argc != 1) {
433 printf("Invalid 'sa_query' command - exactly one argument, "
434 "STA address, is required.\n");
435 return -1;
436 }
437 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
438 return wpa_ctrl_command(ctrl, buf);
439}
440#endif /* CONFIG_IEEE80211W */
441
442
ad08c363
JM
443#ifdef CONFIG_WPS
444static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
445 char *argv[])
446{
31fcea93 447 char buf[256];
077a781f
JM
448 if (argc < 2) {
449 printf("Invalid 'wps_pin' command - at least two arguments, "
ad08c363
JM
450 "UUID and PIN, are required.\n");
451 return -1;
452 }
31fcea93
JM
453 if (argc > 3)
454 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
455 argv[0], argv[1], argv[2], argv[3]);
456 else if (argc > 2)
077a781f
JM
457 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
458 argv[0], argv[1], argv[2]);
459 else
460 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
ad08c363
JM
461 return wpa_ctrl_command(ctrl, buf);
462}
463
464
3981cb3c
JM
465static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
466 char *argv[])
467{
468 char cmd[256];
469 int res;
470
471 if (argc != 1 && argc != 2) {
472 printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
473 "- PIN to be verified\n");
474 return -1;
475 }
476
477 if (argc == 2)
478 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
479 argv[0], argv[1]);
480 else
481 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
482 argv[0]);
eeab4f2f 483 if (os_snprintf_error(sizeof(cmd), res)) {
3981cb3c
JM
484 printf("Too long WPS_CHECK_PIN command.\n");
485 return -1;
486 }
487 return wpa_ctrl_command(ctrl, cmd);
488}
489
490
ad08c363
JM
491static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
492 char *argv[])
493{
494 return wpa_ctrl_command(ctrl, "WPS_PBC");
495}
46bdb83a
MH
496
497
4c374cde
AS
498static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
499 char *argv[])
500{
501 return wpa_ctrl_command(ctrl, "WPS_CANCEL");
502}
503
504
bb45b6d7
JM
505#ifdef CONFIG_WPS_NFC
506static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
507 char *argv[])
508{
509 int ret;
510 char *buf;
511 size_t buflen;
512
513 if (argc != 1) {
514 printf("Invalid 'wps_nfc_tag_read' command - one argument "
515 "is required.\n");
516 return -1;
517 }
518
519 buflen = 18 + os_strlen(argv[0]);
520 buf = os_malloc(buflen);
521 if (buf == NULL)
522 return -1;
523 os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
524
525 ret = wpa_ctrl_command(ctrl, buf);
526 os_free(buf);
527
528 return ret;
529}
3cf7a59d
JM
530
531
532static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
533 int argc, char *argv[])
534{
535 char cmd[64];
536 int res;
537
538 if (argc != 1) {
539 printf("Invalid 'wps_nfc_config_token' command - one argument "
540 "is required.\n");
541 return -1;
542 }
543
544 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
545 argv[0]);
eeab4f2f 546 if (os_snprintf_error(sizeof(cmd), res)) {
3cf7a59d
JM
547 printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
548 return -1;
549 }
550 return wpa_ctrl_command(ctrl, cmd);
551}
ffdaa05a
JM
552
553
554static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
555 int argc, char *argv[])
556{
557 char cmd[64];
558 int res;
559
560 if (argc != 1) {
561 printf("Invalid 'wps_nfc_token' command - one argument is "
562 "required.\n");
563 return -1;
564 }
565
566 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
eeab4f2f 567 if (os_snprintf_error(sizeof(cmd), res)) {
ffdaa05a
JM
568 printf("Too long WPS_NFC_TOKEN command.\n");
569 return -1;
570 }
571 return wpa_ctrl_command(ctrl, cmd);
572}
6772a90a
JM
573
574
575static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
576 int argc, char *argv[])
577{
578 char cmd[64];
579 int res;
580
581 if (argc != 2) {
582 printf("Invalid 'nfc_get_handover_sel' command - two arguments "
583 "are required.\n");
584 return -1;
585 }
586
587 res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
588 argv[0], argv[1]);
eeab4f2f 589 if (os_snprintf_error(sizeof(cmd), res)) {
6772a90a
JM
590 printf("Too long NFC_GET_HANDOVER_SEL command.\n");
591 return -1;
592 }
593 return wpa_ctrl_command(ctrl, cmd);
594}
595
bb45b6d7
JM
596#endif /* CONFIG_WPS_NFC */
597
598
5a1cc30f
JM
599static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
600 char *argv[])
601{
602 char buf[64];
603 if (argc < 1) {
604 printf("Invalid 'wps_ap_pin' command - at least one argument "
605 "is required.\n");
606 return -1;
607 }
608 if (argc > 2)
609 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
610 argv[0], argv[1], argv[2]);
611 else if (argc > 1)
612 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
613 argv[0], argv[1]);
614 else
615 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
616 return wpa_ctrl_command(ctrl, buf);
617}
450eddcf
JM
618
619
3351a384
JM
620static int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc,
621 char *argv[])
622{
623 return wpa_ctrl_command(ctrl, "WPS_GET_STATUS");
624}
625
626
450eddcf
JM
627static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
628 char *argv[])
629{
630 char buf[256];
d9d1b952 631 char ssid_hex[2 * SSID_MAX_LEN + 1];
450eddcf
JM
632 char key_hex[2 * 64 + 1];
633 int i;
634
635 if (argc < 1) {
636 printf("Invalid 'wps_config' command - at least two arguments "
637 "are required.\n");
638 return -1;
639 }
640
641 ssid_hex[0] = '\0';
d9d1b952 642 for (i = 0; i < SSID_MAX_LEN; i++) {
450eddcf
JM
643 if (argv[0][i] == '\0')
644 break;
645 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
646 }
647
648 key_hex[0] = '\0';
649 if (argc > 3) {
650 for (i = 0; i < 64; i++) {
651 if (argv[3][i] == '\0')
652 break;
653 os_snprintf(&key_hex[i * 2], 3, "%02x",
654 argv[3][i]);
655 }
656 }
657
658 if (argc > 3)
659 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
660 ssid_hex, argv[1], argv[2], key_hex);
661 else if (argc > 2)
662 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
663 ssid_hex, argv[1], argv[2]);
664 else
665 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
666 ssid_hex, argv[1]);
667 return wpa_ctrl_command(ctrl, buf);
668}
ad08c363
JM
669#endif /* CONFIG_WPS */
670
671
2049a875
JM
672static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
673 char *argv[])
674{
675 char buf[300];
676 int res;
677
678 if (argc < 2) {
679 printf("Invalid 'disassoc_imminent' command - two arguments "
680 "(STA addr and Disassociation Timer) are needed\n");
681 return -1;
682 }
683
684 res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
685 argv[0], argv[1]);
d85e1fc8 686 if (os_snprintf_error(sizeof(buf), res))
2049a875
JM
687 return -1;
688 return wpa_ctrl_command(ctrl, buf);
689}
690
691
71269b37
JM
692static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
693 char *argv[])
694{
695 char buf[300];
696 int res;
697
d5b559b6
KP
698 if (argc < 3) {
699 printf("Invalid 'ess_disassoc' command - three arguments (STA "
700 "addr, disassoc timer, and URL) are needed\n");
71269b37
JM
701 return -1;
702 }
703
d5b559b6
KP
704 res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
705 argv[0], argv[1], argv[2]);
d85e1fc8 706 if (os_snprintf_error(sizeof(buf), res))
71269b37
JM
707 return -1;
708 return wpa_ctrl_command(ctrl, buf);
709}
710
711
a30dff07
JM
712static int hostapd_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc,
713 char *argv[])
714{
715 char buf[2000], *tmp;
716 int res, i, total;
717
718 if (argc < 1) {
719 printf("Invalid 'bss_tm_req' command - at least one argument (STA addr) is needed\n");
720 return -1;
721 }
722
723 res = os_snprintf(buf, sizeof(buf), "BSS_TM_REQ %s", argv[0]);
d85e1fc8 724 if (os_snprintf_error(sizeof(buf), res))
a30dff07
JM
725 return -1;
726
727 total = res;
728 for (i = 1; i < argc; i++) {
729 tmp = &buf[total];
730 res = os_snprintf(tmp, sizeof(buf) - total, " %s", argv[i]);
eeab4f2f 731 if (os_snprintf_error(sizeof(buf) - total, res))
a30dff07
JM
732 return -1;
733 total += res;
734 }
735 return wpa_ctrl_command(ctrl, buf);
736}
737
738
403b96fe
JM
739static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
740 char *argv[])
741{
742 return wpa_ctrl_command(ctrl, "GET_CONFIG");
743}
744
745
6fc6879b
JM
746static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
747 char *addr, size_t addr_len)
748{
749 char buf[4096], *pos;
750 size_t len;
751 int ret;
752
753 if (ctrl_conn == NULL) {
754 printf("Not connected to hostapd - command dropped.\n");
755 return -1;
756 }
757 len = sizeof(buf) - 1;
758 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
759 hostapd_cli_msg_cb);
760 if (ret == -2) {
761 printf("'%s' command timed out.\n", cmd);
762 return -2;
763 } else if (ret < 0) {
764 printf("'%s' command failed.\n", cmd);
765 return -1;
766 }
767
768 buf[len] = '\0';
769 if (memcmp(buf, "FAIL", 4) == 0)
770 return -1;
771 printf("%s", buf);
772
773 pos = buf;
774 while (*pos != '\0' && *pos != '\n')
775 pos++;
776 *pos = '\0';
777 os_strlcpy(addr, buf, addr_len);
778 return 0;
779}
780
781
782static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
783 char *argv[])
784{
785 char addr[32], cmd[64];
786
787 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
788 return 0;
789 do {
790 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
791 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
792
793 return -1;
794}
795
796
797static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
798{
01938838 799 print_help(stdout, argc > 0 ? argv[0] : NULL);
6fc6879b
JM
800 return 0;
801}
802
803
6cad0bff
MK
804static char ** hostapd_cli_complete_help(const char *str, int pos)
805{
806 int arg = get_cmd_arg_num(str, pos);
807 char **res = NULL;
808
809 switch (arg) {
810 case 1:
811 res = list_cmd_list();
812 break;
813 }
814
815 return res;
816}
817
818
6fc6879b
JM
819static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
820 char *argv[])
821{
822 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
823 return 0;
824}
825
826
c551700f
KP
827static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl,
828 int argc, char *argv[])
829{
830 char buf[200];
831 int res;
832
833 if (argc != 1) {
834 printf("Invalid 'set_qos_map_set' command - "
835 "one argument (comma delimited QoS map set) "
836 "is needed\n");
837 return -1;
838 }
839
840 res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
d85e1fc8 841 if (os_snprintf_error(sizeof(buf), res))
c551700f
KP
842 return -1;
843 return wpa_ctrl_command(ctrl, buf);
844}
845
846
847static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
848 int argc, char *argv[])
849{
850 char buf[50];
851 int res;
852
853 if (argc != 1) {
854 printf("Invalid 'send_qos_map_conf' command - "
855 "one argument (STA addr) is needed\n");
856 return -1;
857 }
858
859 res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
d85e1fc8 860 if (os_snprintf_error(sizeof(buf), res))
c551700f
KP
861 return -1;
862 return wpa_ctrl_command(ctrl, buf);
863}
864
865
3fb17a95
JM
866static int hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc,
867 char *argv[])
868{
869 char buf[300];
870 int res;
871
872 if (argc < 2) {
873 printf("Invalid 'hs20_wnm_notif' command - two arguments (STA "
874 "addr and URL) are needed\n");
875 return -1;
876 }
877
878 res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s",
879 argv[0], argv[1]);
d85e1fc8 880 if (os_snprintf_error(sizeof(buf), res))
3fb17a95
JM
881 return -1;
882 return wpa_ctrl_command(ctrl, buf);
883}
884
885
8e1146d9
JM
886static int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc,
887 char *argv[])
888{
889 char buf[300];
890 int res;
891
892 if (argc < 3) {
893 printf("Invalid 'hs20_deauth_req' command - at least three arguments (STA addr, Code, Re-auth Delay) are needed\n");
894 return -1;
895 }
896
897 if (argc > 3)
898 res = os_snprintf(buf, sizeof(buf),
899 "HS20_DEAUTH_REQ %s %s %s %s",
900 argv[0], argv[1], argv[2], argv[3]);
901 else
902 res = os_snprintf(buf, sizeof(buf),
903 "HS20_DEAUTH_REQ %s %s %s",
904 argv[0], argv[1], argv[2]);
d85e1fc8 905 if (os_snprintf_error(sizeof(buf), res))
8e1146d9
JM
906 return -1;
907 return wpa_ctrl_command(ctrl, buf);
908}
909
910
6fc6879b
JM
911static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
912{
913 hostapd_cli_quit = 1;
42838059
JM
914 if (interactive)
915 eloop_terminate();
6fc6879b
JM
916 return 0;
917}
918
919
920static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
921{
922 char cmd[256];
923 if (argc != 1) {
924 printf("Invalid LEVEL command: needs one argument (debug "
925 "level)\n");
926 return 0;
927 }
928 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
929 return wpa_ctrl_command(ctrl, cmd);
930}
931
932
933static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
934{
935 struct dirent *dent;
936 DIR *dir;
937
938 dir = opendir(ctrl_iface_dir);
939 if (dir == NULL) {
940 printf("Control interface directory '%s' could not be "
941 "openned.\n", ctrl_iface_dir);
942 return;
943 }
944
945 printf("Available interfaces:\n");
946 while ((dent = readdir(dir))) {
947 if (strcmp(dent->d_name, ".") == 0 ||
948 strcmp(dent->d_name, "..") == 0)
949 continue;
950 printf("%s\n", dent->d_name);
951 }
952 closedir(dir);
953}
954
955
956static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
957 char *argv[])
958{
959 if (argc < 1) {
960 hostapd_cli_list_interfaces(ctrl);
961 return 0;
962 }
963
964 hostapd_cli_close_connection();
cc0b7cb1
EA
965 os_free(ctrl_ifname);
966 ctrl_ifname = os_strdup(argv[0]);
db9418bb
SG
967 if (ctrl_ifname == NULL)
968 return -1;
6fc6879b
JM
969
970 if (hostapd_cli_open_connection(ctrl_ifname)) {
971 printf("Connected to interface '%s.\n", ctrl_ifname);
972 if (wpa_ctrl_attach(ctrl_conn) == 0) {
973 hostapd_cli_attached = 1;
1cef253a 974 register_event_handler(ctrl_conn);
6fc6879b
JM
975 } else {
976 printf("Warning: Failed to attach to "
977 "hostapd.\n");
978 }
979 } else {
980 printf("Could not connect to interface '%s' - re-trying\n",
981 ctrl_ifname);
982 }
983 return 0;
984}
985
986
b4e34f2f
JM
987static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
988{
989 char cmd[256];
990 int res;
991
992 if (argc != 2) {
993 printf("Invalid SET command: needs two arguments (variable "
994 "name and value)\n");
995 return -1;
996 }
997
998 res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
eeab4f2f 999 if (os_snprintf_error(sizeof(cmd), res)) {
b4e34f2f
JM
1000 printf("Too long SET command.\n");
1001 return -1;
1002 }
1003 return wpa_ctrl_command(ctrl, cmd);
1004}
1005
1006
acec8d32
JM
1007static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
1008{
1009 char cmd[256];
1010 int res;
1011
1012 if (argc != 1) {
1013 printf("Invalid GET command: needs one argument (variable "
1014 "name)\n");
1015 return -1;
1016 }
1017
1018 res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
eeab4f2f 1019 if (os_snprintf_error(sizeof(cmd), res)) {
acec8d32
JM
1020 printf("Too long GET command.\n");
1021 return -1;
1022 }
1023 return wpa_ctrl_command(ctrl, cmd);
1024}
1025
1026
ee039107
AN
1027#ifdef CONFIG_FST
1028static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[])
1029{
1030 char cmd[256];
1031 int res;
1032 int i;
1033 int total;
1034
1035 if (argc <= 0) {
1036 printf("FST command: parameters are required.\n");
1037 return -1;
1038 }
1039
1040 total = os_snprintf(cmd, sizeof(cmd), "FST-MANAGER");
1041
1042 for (i = 0; i < argc; i++) {
1043 res = os_snprintf(cmd + total, sizeof(cmd) - total, " %s",
1044 argv[i]);
1045 if (os_snprintf_error(sizeof(cmd) - total, res)) {
1046 printf("Too long fst command.\n");
1047 return -1;
1048 }
1049 total += res;
1050 }
1051 return wpa_ctrl_command(ctrl, cmd);
1052}
1053#endif /* CONFIG_FST */
1054
1055
334bf36a
AO
1056static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
1057 int argc, char *argv[])
1058{
1059 char cmd[256];
1060 int res;
1061 int i;
1062 char *tmp;
1063 int total;
1064
1065 if (argc < 2) {
1066 printf("Invalid chan_switch command: needs at least two "
1067 "arguments (count and freq)\n"
1068 "usage: <cs_count> <freq> [sec_channel_offset=] "
1069 "[center_freq1=] [center_freq2=] [bandwidth=] "
1070 "[blocktx] [ht|vht]\n");
1071 return -1;
1072 }
1073
1074 res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
1075 argv[0], argv[1]);
eeab4f2f 1076 if (os_snprintf_error(sizeof(cmd), res)) {
334bf36a
AO
1077 printf("Too long CHAN_SWITCH command.\n");
1078 return -1;
1079 }
1080
1081 total = res;
1082 for (i = 2; i < argc; i++) {
1083 tmp = cmd + total;
1084 res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
eeab4f2f 1085 if (os_snprintf_error(sizeof(cmd) - total, res)) {
334bf36a
AO
1086 printf("Too long CHAN_SWITCH command.\n");
1087 return -1;
1088 }
1089 total += res;
1090 }
1091 return wpa_ctrl_command(ctrl, cmd);
1092}
1093
1094
a6938b79
CB
1095static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc,
1096 char *argv[])
1097{
1098 return wpa_ctrl_command(ctrl, "ENABLE");
1099}
1100
1101
1102static int hostapd_cli_cmd_reload(struct wpa_ctrl *ctrl, int argc,
1103 char *argv[])
1104{
1105 return wpa_ctrl_command(ctrl, "RELOAD");
1106}
1107
1108
1109static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc,
1110 char *argv[])
1111{
1112 return wpa_ctrl_command(ctrl, "DISABLE");
1113}
1114
1115
3ae8b7b7
AS
1116static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
1117{
1118 char cmd[256];
1119 int res;
1120
1121 if (argc < 2 || argc > 3) {
1122 printf("Invalid vendor command\n"
1123 "usage: <vendor id> <command id> [<hex formatted command argument>]\n");
1124 return -1;
1125 }
1126
1127 res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
1128 argc == 3 ? argv[2] : "");
eeab4f2f 1129 if (os_snprintf_error(sizeof(cmd), res)) {
3ae8b7b7
AS
1130 printf("Too long VENDOR command.\n");
1131 return -1;
1132 }
1133 return wpa_ctrl_command(ctrl, cmd);
1134}
1135
1136
2c6411ed
JM
1137static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc,
1138 char *argv[])
1139{
1140 return wpa_ctrl_command(ctrl, "ERP_FLUSH");
1141}
1142
1143
5c4f0511
SD
1144static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc,
1145 char *argv[])
1146{
1147 char cmd[256];
1148 int res;
1149
1150 res = os_snprintf(cmd, sizeof(cmd), "LOG_LEVEL%s%s%s%s",
1151 argc >= 1 ? " " : "",
1152 argc >= 1 ? argv[0] : "",
1153 argc == 2 ? " " : "",
1154 argc == 2 ? argv[1] : "");
1155 if (os_snprintf_error(sizeof(cmd), res)) {
1156 printf("Too long option\n");
1157 return -1;
1158 }
1159 return wpa_ctrl_command(ctrl, cmd);
1160}
1161
1162
12605642
DL
1163static int hostapd_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
1164{
1165 if (argc == 0)
1166 return -1;
1167 return hostapd_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]);
1168}
1169
1170
b8daac18
MH
1171static int hostapd_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
1172{
1173 return wpa_ctrl_command(ctrl, "PMKSA");
1174}
1175
1176
4c522c77
MH
1177static int hostapd_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc,
1178 char *argv[])
1179{
1180 return wpa_ctrl_command(ctrl, "PMKSA_FLUSH");
1181}
1182
1183
9b4b2264
DS
1184static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc,
1185 char *argv[])
1186{
1187 char cmd[2048];
1188 int res;
1189
1190 if (argc < 3 || argc > 5) {
1191 printf("Invalid set_neighbor command: needs 3-5 arguments\n");
1192 return -1;
1193 }
1194
1195 res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s",
1196 argv[0], argv[1], argv[2], argc >= 4 ? argv[3] : "",
1197 argc == 5 ? argv[4] : "");
1198 if (os_snprintf_error(sizeof(cmd), res)) {
1199 printf("Too long SET_NEIGHBOR command.\n");
1200 return -1;
1201 }
1202 return wpa_ctrl_command(ctrl, cmd);
1203}
1204
1205
1206static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc,
1207 char *argv[])
1208{
1209 char cmd[400];
1210 int res;
1211
1212 if (argc != 2) {
1213 printf("Invalid remove_neighbor command: needs 2 arguments\n");
1214 return -1;
1215 }
1216
1217 res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NEIGHBOR %s %s",
1218 argv[0], argv[1]);
1219 if (os_snprintf_error(sizeof(cmd), res)) {
1220 printf("Too long REMOVE_NEIGHBOR command.\n");
1221 return -1;
1222 }
1223 return wpa_ctrl_command(ctrl, cmd);
1224}
1225
1226
f4f185a2
DS
1227static int hostapd_cli_cmd_req_lci(struct wpa_ctrl *ctrl, int argc,
1228 char *argv[])
1229{
1230 char cmd[256];
1231 int res;
1232
1233 if (argc != 1) {
1234 printf("Invalid req_lci command - requires destination address\n");
1235 return -1;
1236 }
1237
1238 res = os_snprintf(cmd, sizeof(cmd), "REQ_LCI %s", argv[0]);
1239 if (os_snprintf_error(sizeof(cmd), res)) {
1240 printf("Too long REQ_LCI command.\n");
1241 return -1;
1242 }
1243 return wpa_ctrl_command(ctrl, cmd);
1244}
1245
1246
220754c5
DS
1247static int hostapd_cli_cmd_req_range(struct wpa_ctrl *ctrl, int argc,
1248 char *argv[])
1249{
1250 if (argc < 4) {
1251 printf("Invalid req_range command: needs at least 4 arguments - dest address, randomization interval, min AP count, and 1 to 16 AP addresses\n");
1252 return -1;
1253 }
1254
1255 return hostapd_cli_cmd(ctrl, "REQ_RANGE", 4, argc, argv);
1256}
1257
1258
4d7aab78
EL
1259static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
1260 char *argv[])
1261{
1262 return wpa_ctrl_command(ctrl, "DRIVER_FLAGS");
1263}
1264
1265
6fc6879b
JM
1266struct hostapd_cli_cmd {
1267 const char *cmd;
1268 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
1f927cd4
MK
1269 char ** (*completion)(const char *str, int pos);
1270 const char *usage;
6fc6879b
JM
1271};
1272
8b423edb 1273static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
1f927cd4
MK
1274 { "ping", hostapd_cli_cmd_ping, NULL,
1275 "= pings hostapd" },
1276 { "mib", hostapd_cli_cmd_mib, NULL,
1277 "= get MIB variables (dot1x, dot11, radius)" },
1278 { "relog", hostapd_cli_cmd_relog, NULL, NULL },
1279 { "status", hostapd_cli_cmd_status, NULL, NULL },
1280 { "sta", hostapd_cli_cmd_sta, NULL,
1281 "<addr> = get MIB variables for one station" },
1282 { "all_sta", hostapd_cli_cmd_all_sta, NULL,
1283 "= get MIB variables for all stations" },
1284 { "new_sta", hostapd_cli_cmd_new_sta, NULL,
1285 "<addr> = add a new station" },
1286 { "deauthenticate", hostapd_cli_cmd_deauthenticate, NULL,
1287 "<addr> = deauthenticate a station" },
1288 { "disassociate", hostapd_cli_cmd_disassociate, NULL,
1289 "<addr> = disassociate a station" },
88b4b424 1290#ifdef CONFIG_IEEE80211W
1f927cd4
MK
1291 { "sa_query", hostapd_cli_cmd_sa_query, NULL,
1292 "<addr> = send SA Query to a station" },
88b4b424 1293#endif /* CONFIG_IEEE80211W */
ad08c363 1294#ifdef CONFIG_WPS
1f927cd4
MK
1295 { "wps_pin", hostapd_cli_cmd_wps_pin, NULL,
1296 "<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" },
1297 { "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL,
1298 "<PIN> = verify PIN checksum" },
1299 { "wps_pbc", hostapd_cli_cmd_wps_pbc, NULL,
1300 "= indicate button pushed to initiate PBC" },
1301 { "wps_cancel", hostapd_cli_cmd_wps_cancel, NULL,
1302 "= cancel the pending WPS operation" },
bb45b6d7 1303#ifdef CONFIG_WPS_NFC
1f927cd4
MK
1304 { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read, NULL,
1305 "<hexdump> = report read NFC tag with WPS data" },
1306 { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token, NULL,
1307 "<WPS/NDEF> = build NFC configuration token" },
1308 { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token, NULL,
1309 "<WPS/NDEF/enable/disable> = manager NFC password token" },
1310 { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel, NULL,
1311 NULL },
bb45b6d7 1312#endif /* CONFIG_WPS_NFC */
1f927cd4
MK
1313 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin, NULL,
1314 "<cmd> [params..] = enable/disable AP PIN" },
1315 { "wps_config", hostapd_cli_cmd_wps_config, NULL,
1316 "<SSID> <auth> <encr> <key> = configure AP" },
1317 { "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL,
1318 "= show current WPS status" },
ad08c363 1319#endif /* CONFIG_WPS */
1f927cd4
MK
1320 { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL, NULL },
1321 { "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL, NULL },
1322 { "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL, NULL },
1323 { "get_config", hostapd_cli_cmd_get_config, NULL,
1324 "= show current configuration" },
6cad0bff 1325 { "help", hostapd_cli_cmd_help, hostapd_cli_complete_help,
1f927cd4
MK
1326 "= show this usage help" },
1327 { "interface", hostapd_cli_cmd_interface, NULL,
1328 "[ifname] = show interfaces/select interface" },
ee039107 1329#ifdef CONFIG_FST
1f927cd4 1330 { "fst", hostapd_cli_cmd_fst, NULL, NULL },
ee039107 1331#endif /* CONFIG_FST */
1f927cd4
MK
1332 { "raw", hostapd_cli_cmd_raw, NULL, NULL },
1333 { "level", hostapd_cli_cmd_level, NULL,
1334 "<debug level> = change debug level" },
1335 { "license", hostapd_cli_cmd_license, NULL,
1336 "= show full hostapd_cli license" },
1337 { "quit", hostapd_cli_cmd_quit, NULL,
1338 "= exit hostapd_cli" },
1339 { "set", hostapd_cli_cmd_set, NULL, NULL },
1340 { "get", hostapd_cli_cmd_get, NULL, NULL },
1341 { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL, NULL },
1342 { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf, NULL, NULL },
1343 { "chan_switch", hostapd_cli_cmd_chan_switch, NULL, NULL },
1344 { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL, NULL },
1345 { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL, NULL },
1346 { "vendor", hostapd_cli_cmd_vendor, NULL, NULL },
1347 { "enable", hostapd_cli_cmd_enable, NULL, NULL },
1348 { "reload", hostapd_cli_cmd_reload, NULL, NULL },
1349 { "disable", hostapd_cli_cmd_disable, NULL, NULL },
1350 { "erp_flush", hostapd_cli_cmd_erp_flush, NULL, NULL },
1351 { "log_level", hostapd_cli_cmd_log_level, NULL, NULL },
1352 { "pmksa", hostapd_cli_cmd_pmksa, NULL, NULL },
1353 { "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL, NULL },
1354 { "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL, NULL },
1355 { "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL, NULL },
1356 { "req_lci", hostapd_cli_cmd_req_lci, NULL, NULL },
1357 { "req_range", hostapd_cli_cmd_req_range, NULL, NULL },
1358 { "driver_flags", hostapd_cli_cmd_driver_flags, NULL, NULL },
1359 { NULL, NULL, NULL, NULL }
6fc6879b
JM
1360};
1361
1362
01938838
MK
1363/*
1364 * Prints command usage, lines are padded with the specified string.
1365 */
1366static void print_cmd_help(FILE *stream, const struct hostapd_cli_cmd *cmd,
1367 const char *pad)
1368{
1369 char c;
1370 size_t n;
1371
1372 if (cmd->usage == NULL)
1373 return;
1374 fprintf(stream, "%s%s ", pad, cmd->cmd);
1375 for (n = 0; (c = cmd->usage[n]); n++) {
1376 fprintf(stream, "%c", c);
1377 if (c == '\n')
1378 fprintf(stream, "%s", pad);
1379 }
1380 fprintf(stream, "\n");
1381}
1382
1383
1384static void print_help(FILE *stream, const char *cmd)
1385{
1386 int n;
1387
1388 fprintf(stream, "commands:\n");
1389 for (n = 0; hostapd_cli_commands[n].cmd; n++) {
1390 if (cmd == NULL || str_starts(hostapd_cli_commands[n].cmd, cmd))
1391 print_cmd_help(stream, &hostapd_cli_commands[n], " ");
1392 }
1393}
1394
1395
6fc6879b
JM
1396static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
1397{
8b423edb 1398 const struct hostapd_cli_cmd *cmd, *match = NULL;
6fc6879b
JM
1399 int count;
1400
1401 count = 0;
1402 cmd = hostapd_cli_commands;
1403 while (cmd->cmd) {
1404 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
1405 match = cmd;
acec8d32
JM
1406 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1407 /* we have an exact match */
1408 count = 1;
1409 break;
1410 }
6fc6879b
JM
1411 count++;
1412 }
1413 cmd++;
1414 }
1415
1416 if (count > 1) {
1417 printf("Ambiguous command '%s'; possible commands:", argv[0]);
1418 cmd = hostapd_cli_commands;
1419 while (cmd->cmd) {
1420 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
1421 0) {
1422 printf(" %s", cmd->cmd);
1423 }
1424 cmd++;
1425 }
1426 printf("\n");
1427 } else if (count == 0) {
1428 printf("Unknown command '%s'\n", argv[0]);
1429 } else {
1430 match->handler(ctrl, argc - 1, &argv[1]);
1431 }
1432}
1433
1434
1cef253a
MK
1435static void cli_event(const char *str)
1436{
1437}
1438
1439
bae92174
GD
1440static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
1441 int action_monitor)
6fc6879b
JM
1442{
1443 int first = 1;
1444 if (ctrl_conn == NULL)
1445 return;
1446 while (wpa_ctrl_pending(ctrl)) {
1447 char buf[256];
1448 size_t len = sizeof(buf) - 1;
1449 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
1450 buf[len] = '\0';
bae92174
GD
1451 if (action_monitor)
1452 hostapd_cli_action_process(buf, len);
1453 else {
1cef253a 1454 cli_event(buf);
bae92174
GD
1455 if (in_read && first)
1456 printf("\n");
1457 first = 0;
1458 printf("%s\n", buf);
1459 }
6fc6879b
JM
1460 } else {
1461 printf("Could not read pending message.\n");
1462 break;
1463 }
1464 }
1465}
1466
1467
1cef253a
MK
1468static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx)
1469{
1470 hostapd_cli_recv_pending(ctrl_conn, 0, 0);
1471}
1472
1473
42838059 1474#define max_args 10
6fc6879b 1475
42838059
JM
1476static int tokenize_cmd(char *cmd, char *argv[])
1477{
1478 char *pos;
1479 int argc = 0;
6fc6879b 1480
42838059
JM
1481 pos = cmd;
1482 for (;;) {
1483 while (*pos == ' ')
6fc6879b 1484 pos++;
42838059
JM
1485 if (*pos == '\0')
1486 break;
1487 argv[argc] = pos;
1488 argc++;
1489 if (argc == max_args)
1490 break;
1491 if (*pos == '"') {
1492 char *pos2 = os_strrchr(pos, '"');
1493 if (pos2)
1494 pos = pos2 + 1;
6fc6879b 1495 }
42838059
JM
1496 while (*pos != '\0' && *pos != ' ')
1497 pos++;
1498 if (*pos == ' ')
1499 *pos++ = '\0';
1500 }
bae92174 1501
42838059 1502 return argc;
6fc6879b
JM
1503}
1504
1505
42838059 1506static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
6fc6879b
JM
1507{
1508 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
1509 printf("Connection to hostapd lost - trying to reconnect\n");
1510 hostapd_cli_close_connection();
1511 }
1512 if (!ctrl_conn) {
1513 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1514 if (ctrl_conn) {
1515 printf("Connection to hostapd re-established\n");
1516 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1517 hostapd_cli_attached = 1;
1cef253a 1518 register_event_handler(ctrl_conn);
6fc6879b
JM
1519 } else {
1520 printf("Warning: Failed to attach to "
1521 "hostapd.\n");
1522 }
1523 }
1524 }
1525 if (ctrl_conn)
bae92174 1526 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
42838059
JM
1527 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1528}
1529
1530
1531static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
1532{
1533 eloop_terminate();
1534}
1535
1536
1537static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
1538{
1539 char *argv[max_args];
1540 int argc;
1541 argc = tokenize_cmd(cmd, argv);
1542 if (argc)
1543 wpa_request(ctrl_conn, argc, argv);
1544}
1545
1546
1547static void hostapd_cli_edit_eof_cb(void *ctx)
1548{
1549 eloop_terminate();
1550}
1551
1552
1f927cd4
MK
1553static char ** list_cmd_list(void)
1554{
1555 char **res;
1556 int i, count;
1557
1558 count = ARRAY_SIZE(hostapd_cli_commands);
1559 res = os_calloc(count + 1, sizeof(char *));
1560 if (res == NULL)
1561 return NULL;
1562
1563 for (i = 0; hostapd_cli_commands[i].cmd; i++) {
1564 res[i] = os_strdup(hostapd_cli_commands[i].cmd);
1565 if (res[i] == NULL)
1566 break;
1567 }
1568
1569 return res;
1570}
1571
1572
1573static char ** hostapd_cli_cmd_completion(const char *cmd, const char *str,
1574 int pos)
1575{
1576 int i;
1577
1578 for (i = 0; hostapd_cli_commands[i].cmd; i++) {
1579 if (os_strcasecmp(hostapd_cli_commands[i].cmd, cmd) != 0)
1580 continue;
1581 if (hostapd_cli_commands[i].completion)
1582 return hostapd_cli_commands[i].completion(str, pos);
1583 if (!hostapd_cli_commands[i].usage)
1584 return NULL;
1585 edit_clear_line();
1586 printf("\r%s\n", hostapd_cli_commands[i].usage);
1587 edit_redraw();
1588 break;
1589 }
1590
1591 return NULL;
1592}
1593
1594
1595static char ** hostapd_cli_edit_completion_cb(void *ctx, const char *str,
1596 int pos)
1597{
1598 char **res;
1599 const char *end;
1600 char *cmd;
1601
1602 end = os_strchr(str, ' ');
1603 if (end == NULL || str + pos < end)
1604 return list_cmd_list();
1605
1606 cmd = os_malloc(pos + 1);
1607 if (cmd == NULL)
1608 return NULL;
1609 os_memcpy(cmd, str, pos);
1610 cmd[end - str] = '\0';
1611 res = hostapd_cli_cmd_completion(cmd, str, pos);
1612 os_free(cmd);
1613 return res;
1614}
1615
1616
42838059
JM
1617static void hostapd_cli_interactive(void)
1618{
1619 printf("\nInteractive mode\n\n");
1620
1621 eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
1622 edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
1f927cd4 1623 hostapd_cli_edit_completion_cb, NULL, NULL, NULL);
42838059
JM
1624 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1625
1626 eloop_run();
1627
1628 edit_deinit(NULL, NULL);
1629 eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
1630}
1631
1632
1633static void hostapd_cli_cleanup(void)
1634{
1635 hostapd_cli_close_connection();
1636 if (pid_file)
1637 os_daemonize_terminate(pid_file);
1638
1639 os_program_deinit();
6fc6879b
JM
1640}
1641
1642
bae92174
GD
1643static void hostapd_cli_action(struct wpa_ctrl *ctrl)
1644{
1645 fd_set rfds;
1646 int fd, res;
1647 struct timeval tv;
1648 char buf[256];
1649 size_t len;
1650
1651 fd = wpa_ctrl_get_fd(ctrl);
1652
1653 while (!hostapd_cli_quit) {
1654 FD_ZERO(&rfds);
1655 FD_SET(fd, &rfds);
1656 tv.tv_sec = ping_interval;
1657 tv.tv_usec = 0;
1658 res = select(fd + 1, &rfds, NULL, NULL, &tv);
1659 if (res < 0 && errno != EINTR) {
1660 perror("select");
1661 break;
1662 }
1663
1664 if (FD_ISSET(fd, &rfds))
1665 hostapd_cli_recv_pending(ctrl, 0, 1);
1666 else {
1667 len = sizeof(buf) - 1;
1668 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1669 hostapd_cli_action_process) < 0 ||
1670 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
1671 printf("hostapd did not reply to PING "
1672 "command - exiting\n");
1673 break;
1674 }
1675 }
1676 }
1677}
1678
1679
6fc6879b
JM
1680int main(int argc, char *argv[])
1681{
6fc6879b
JM
1682 int warning_displayed = 0;
1683 int c;
bae92174 1684 int daemonize = 0;
6fc6879b 1685
3433ed8c
JM
1686 if (os_program_init())
1687 return -1;
1688
6fc6879b 1689 for (;;) {
4ae71209 1690 c = getopt(argc, argv, "a:BhG:i:p:P:s:v");
6fc6879b
JM
1691 if (c < 0)
1692 break;
1693 switch (c) {
bae92174
GD
1694 case 'a':
1695 action_file = optarg;
1696 break;
1697 case 'B':
1698 daemonize = 1;
1699 break;
1cc84c1c
JM
1700 case 'G':
1701 ping_interval = atoi(optarg);
1702 break;
6fc6879b
JM
1703 case 'h':
1704 usage();
1705 return 0;
1706 case 'v':
1707 printf("%s\n", hostapd_cli_version);
1708 return 0;
1709 case 'i':
b242d398
JM
1710 os_free(ctrl_ifname);
1711 ctrl_ifname = os_strdup(optarg);
6fc6879b
JM
1712 break;
1713 case 'p':
1714 ctrl_iface_dir = optarg;
1715 break;
b8e5426d
MSS
1716 case 'P':
1717 pid_file = optarg;
1718 break;
4ae71209
MM
1719 case 's':
1720 client_socket_dir = optarg;
1721 break;
6fc6879b
JM
1722 default:
1723 usage();
1724 return -1;
1725 }
1726 }
1727
bae92174 1728 interactive = (argc == optind) && (action_file == NULL);
6fc6879b
JM
1729
1730 if (interactive) {
1731 printf("%s\n\n%s\n\n", hostapd_cli_version,
1732 hostapd_cli_license);
1733 }
1734
42838059
JM
1735 if (eloop_init())
1736 return -1;
1737
6fc6879b
JM
1738 for (;;) {
1739 if (ctrl_ifname == NULL) {
1740 struct dirent *dent;
1741 DIR *dir = opendir(ctrl_iface_dir);
1742 if (dir) {
1743 while ((dent = readdir(dir))) {
b242d398
JM
1744 if (os_strcmp(dent->d_name, ".") == 0
1745 ||
1746 os_strcmp(dent->d_name, "..") == 0)
6fc6879b
JM
1747 continue;
1748 printf("Selected interface '%s'\n",
1749 dent->d_name);
b242d398 1750 ctrl_ifname = os_strdup(dent->d_name);
6fc6879b
JM
1751 break;
1752 }
1753 closedir(dir);
1754 }
1755 }
1756 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1757 if (ctrl_conn) {
1758 if (warning_displayed)
1759 printf("Connection established.\n");
1760 break;
1761 }
1762
1763 if (!interactive) {
1764 perror("Failed to connect to hostapd - "
1765 "wpa_ctrl_open");
1766 return -1;
1767 }
1768
1769 if (!warning_displayed) {
1770 printf("Could not connect to hostapd - re-trying\n");
1771 warning_displayed = 1;
1772 }
b242d398 1773 os_sleep(1, 0);
6fc6879b
JM
1774 continue;
1775 }
1776
bae92174 1777 if (interactive || action_file) {
6fc6879b
JM
1778 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1779 hostapd_cli_attached = 1;
1cef253a 1780 register_event_handler(ctrl_conn);
6fc6879b
JM
1781 } else {
1782 printf("Warning: Failed to attach to hostapd.\n");
bae92174
GD
1783 if (action_file)
1784 return -1;
6fc6879b 1785 }
bae92174
GD
1786 }
1787
2e69bdd1 1788 if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
bae92174
GD
1789 return -1;
1790
1791 if (interactive)
6fc6879b 1792 hostapd_cli_interactive();
bae92174
GD
1793 else if (action_file)
1794 hostapd_cli_action(ctrl_conn);
1795 else
6fc6879b
JM
1796 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1797
1cef253a 1798 unregister_event_handler(ctrl_conn);
bae92174 1799 os_free(ctrl_ifname);
42838059 1800 eloop_destroy();
bae92174 1801 hostapd_cli_cleanup();
6fc6879b
JM
1802 return 0;
1803}
56885eec
JD
1804
1805#else /* CONFIG_NO_CTRL_IFACE */
1806
1807int main(int argc, char *argv[])
1808{
1809 return -1;
1810}
1811
1812#endif /* CONFIG_NO_CTRL_IFACE */