]> git.ipfire.org Git - thirdparty/hostap.git/blame - wpa_supplicant/wpa_cli.c
P2P: Only schedule a single p2p_go_neg_start timeout at a time
[thirdparty/hostap.git] / wpa_supplicant / wpa_cli.c
CommitLineData
6fc6879b
JM
1/*
2 * WPA Supplicant - command line interface for wpa_supplicant daemon
1cea09a9 3 * Copyright (c) 2004-2012, 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
11#ifdef CONFIG_CTRL_IFACE
12
13#ifdef CONFIG_CTRL_IFACE_UNIX
14#include <dirent.h>
15#endif /* CONFIG_CTRL_IFACE_UNIX */
6fc6879b 16
90973fb2 17#include "common/wpa_ctrl.h"
cd101567
JM
18#include "utils/common.h"
19#include "utils/eloop.h"
82a855bd 20#include "utils/edit.h"
a624f20b 21#include "utils/list.h"
90973fb2 22#include "common/version.h"
a8918e86 23#include "common/ieee802_11_defs.h"
b1001e4c
DS
24#ifdef ANDROID
25#include <cutils/properties.h>
26#endif /* ANDROID */
6fc6879b
JM
27
28
29static const char *wpa_cli_version =
30"wpa_cli v" VERSION_STR "\n"
e056f93e 31"Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> and contributors";
6fc6879b
JM
32
33
34static const char *wpa_cli_license =
331f89ff
JM
35"This software may be distributed under the terms of the BSD license.\n"
36"See README for more details.\n";
6fc6879b
JM
37
38static const char *wpa_cli_full_license =
331f89ff 39"This software may be distributed under the terms of the BSD license.\n"
6fc6879b
JM
40"\n"
41"Redistribution and use in source and binary forms, with or without\n"
42"modification, are permitted provided that the following conditions are\n"
43"met:\n"
44"\n"
45"1. Redistributions of source code must retain the above copyright\n"
46" notice, this list of conditions and the following disclaimer.\n"
47"\n"
48"2. Redistributions in binary form must reproduce the above copyright\n"
49" notice, this list of conditions and the following disclaimer in the\n"
50" documentation and/or other materials provided with the distribution.\n"
51"\n"
52"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
53" names of its contributors may be used to endorse or promote products\n"
54" derived from this software without specific prior written permission.\n"
55"\n"
56"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
57"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
58"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
59"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
60"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
61"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
62"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
63"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
64"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
65"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
66"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
67"\n";
68
6fc6879b 69static struct wpa_ctrl *ctrl_conn;
4a3ade4e 70static struct wpa_ctrl *mon_conn;
6fc6879b
JM
71static int wpa_cli_quit = 0;
72static int wpa_cli_attached = 0;
73static int wpa_cli_connected = 0;
74static int wpa_cli_last_id = 0;
c5c5817c
JM
75#ifndef CONFIG_CTRL_IFACE_DIR
76#define CONFIG_CTRL_IFACE_DIR "/var/run/wpa_supplicant"
77#endif /* CONFIG_CTRL_IFACE_DIR */
78static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
6fc6879b
JM
79static char *ctrl_ifname = NULL;
80static const char *pid_file = NULL;
81static const char *action_file = NULL;
1cc84c1c 82static int ping_interval = 5;
4a3ade4e 83static int interactive = 0;
6fc6879b 84
a624f20b
JM
85struct cli_txt_entry {
86 struct dl_list list;
87 char *txt;
88};
89
90static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */
91static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */
76788542 92static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */
a624f20b 93
6fc6879b 94
2af4d404 95static void print_help(const char *cmd);
cd101567 96static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx);
d62aaa7d 97static void wpa_cli_close_connection(void);
8e897ae3 98static char * wpa_cli_get_default_ifname(void);
2af4d404 99static char ** wpa_list_cmd_list(void);
dfa141b1
ER
100
101
6fc6879b
JM
102static void usage(void)
103{
104 printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] "
105 "[-a<action file>] \\\n"
1cc84c1c
JM
106 " [-P<pid file>] [-g<global ctrl>] [-G<ping interval>] "
107 "[command..]\n"
6fc6879b
JM
108 " -h = help (show this usage text)\n"
109 " -v = shown version information\n"
110 " -a = run in daemon mode executing the action file based on "
111 "events from\n"
112 " wpa_supplicant\n"
113 " -B = run a daemon in the background\n"
c5c5817c 114 " default path: " CONFIG_CTRL_IFACE_DIR "\n"
dfa141b1 115 " default interface: first interface found in socket path\n");
2af4d404 116 print_help(NULL);
6fc6879b
JM
117}
118
119
a624f20b
JM
120static void cli_txt_list_free(struct cli_txt_entry *e)
121{
122 dl_list_del(&e->list);
123 os_free(e->txt);
124 os_free(e);
125}
126
127
128static void cli_txt_list_flush(struct dl_list *list)
129{
130 struct cli_txt_entry *e;
131 while ((e = dl_list_first(list, struct cli_txt_entry, list)))
132 cli_txt_list_free(e);
133}
134
135
136static struct cli_txt_entry * cli_txt_list_get(struct dl_list *txt_list,
137 const char *txt)
138{
139 struct cli_txt_entry *e;
140 dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
141 if (os_strcmp(e->txt, txt) == 0)
142 return e;
143 }
144 return NULL;
145}
146
147
148static void cli_txt_list_del(struct dl_list *txt_list, const char *txt)
149{
150 struct cli_txt_entry *e;
151 e = cli_txt_list_get(txt_list, txt);
152 if (e)
153 cli_txt_list_free(e);
154}
155
156
157static void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt)
158{
159 u8 addr[ETH_ALEN];
160 char buf[18];
161 if (hwaddr_aton(txt, addr) < 0)
162 return;
163 os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
164 cli_txt_list_del(txt_list, buf);
165}
166
167
4877e1fc 168#ifdef CONFIG_P2P
76788542
JM
169static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt)
170{
171 const char *end;
172 char *buf;
173 end = os_strchr(txt, ' ');
174 if (end == NULL)
175 end = txt + os_strlen(txt);
176 buf = os_malloc(end - txt + 1);
177 if (buf == NULL)
178 return;
179 os_memcpy(buf, txt, end - txt);
180 buf[end - txt] = '\0';
181 cli_txt_list_del(txt_list, buf);
182 os_free(buf);
183}
4877e1fc 184#endif /* CONFIG_P2P */
76788542
JM
185
186
a624f20b
JM
187static int cli_txt_list_add(struct dl_list *txt_list, const char *txt)
188{
189 struct cli_txt_entry *e;
190 e = cli_txt_list_get(txt_list, txt);
191 if (e)
192 return 0;
193 e = os_zalloc(sizeof(*e));
194 if (e == NULL)
195 return -1;
196 e->txt = os_strdup(txt);
197 if (e->txt == NULL) {
198 os_free(e);
199 return -1;
200 }
201 dl_list_add(txt_list, &e->list);
202 return 0;
203}
204
205
4877e1fc 206#ifdef CONFIG_P2P
a624f20b
JM
207static int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt)
208{
209 u8 addr[ETH_ALEN];
210 char buf[18];
211 if (hwaddr_aton(txt, addr) < 0)
212 return -1;
213 os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
214 return cli_txt_list_add(txt_list, buf);
215}
216
217
76788542
JM
218static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt)
219{
220 const char *end;
221 char *buf;
222 int ret;
223 end = os_strchr(txt, ' ');
224 if (end == NULL)
225 end = txt + os_strlen(txt);
226 buf = os_malloc(end - txt + 1);
227 if (buf == NULL)
228 return -1;
229 os_memcpy(buf, txt, end - txt);
230 buf[end - txt] = '\0';
231 ret = cli_txt_list_add(txt_list, buf);
232 os_free(buf);
233 return ret;
234}
4877e1fc 235#endif /* CONFIG_P2P */
76788542
JM
236
237
a624f20b
JM
238static char ** cli_txt_list_array(struct dl_list *txt_list)
239{
240 unsigned int i, count = dl_list_len(txt_list);
241 char **res;
242 struct cli_txt_entry *e;
243
f9884c09 244 res = os_calloc(count + 1, sizeof(char *));
a624f20b
JM
245 if (res == NULL)
246 return NULL;
247
248 i = 0;
249 dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
250 res[i] = os_strdup(e->txt);
251 if (res[i] == NULL)
252 break;
253 i++;
254 }
255
256 return res;
257}
258
259
260static int get_cmd_arg_num(const char *str, int pos)
261{
262 int arg = 0, i;
263
264 for (i = 0; i <= pos; i++) {
265 if (str[i] != ' ') {
266 arg++;
267 while (i <= pos && str[i] != ' ')
268 i++;
269 }
270 }
271
272 if (arg > 0)
273 arg--;
274 return arg;
275}
276
277
f3f0f648
JM
278static int str_starts(const char *src, const char *match)
279{
280 return os_strncmp(src, match, os_strlen(match)) == 0;
281}
282
283
284static int wpa_cli_show_event(const char *event)
285{
286 const char *start;
287
288 start = os_strchr(event, '>');
289 if (start == NULL)
290 return 1;
291
292 start++;
293 /*
294 * Skip BSS added/removed events since they can be relatively frequent
295 * and are likely of not much use for an interactive user.
296 */
297 if (str_starts(start, WPA_EVENT_BSS_ADDED) ||
298 str_starts(start, WPA_EVENT_BSS_REMOVED))
299 return 0;
300
301 return 1;
302}
303
304
4a3ade4e 305static int wpa_cli_open_connection(const char *ifname, int attach)
6fc6879b
JM
306{
307#if defined(CONFIG_CTRL_IFACE_UDP) || defined(CONFIG_CTRL_IFACE_NAMED_PIPE)
308 ctrl_conn = wpa_ctrl_open(ifname);
4a3ade4e
JM
309 if (ctrl_conn == NULL)
310 return -1;
311
312 if (attach && interactive)
313 mon_conn = wpa_ctrl_open(ifname);
314 else
315 mon_conn = NULL;
6fc6879b 316#else /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
b1001e4c 317 char *cfile = NULL;
6fc6879b
JM
318 int flen, res;
319
320 if (ifname == NULL)
4a3ade4e 321 return -1;
6fc6879b 322
b1001e4c
DS
323#ifdef ANDROID
324 if (access(ctrl_iface_dir, F_OK) < 0) {
325 cfile = os_strdup(ifname);
326 if (cfile == NULL)
327 return -1;
328 }
329#endif /* ANDROID */
330
331 if (cfile == NULL) {
332 flen = os_strlen(ctrl_iface_dir) + os_strlen(ifname) + 2;
333 cfile = os_malloc(flen);
334 if (cfile == NULL)
335 return -1;
336 res = os_snprintf(cfile, flen, "%s/%s", ctrl_iface_dir,
337 ifname);
338 if (res < 0 || res >= flen) {
339 os_free(cfile);
340 return -1;
341 }
6fc6879b
JM
342 }
343
344 ctrl_conn = wpa_ctrl_open(cfile);
4a3ade4e
JM
345 if (ctrl_conn == NULL) {
346 os_free(cfile);
347 return -1;
348 }
349
350 if (attach && interactive)
351 mon_conn = wpa_ctrl_open(cfile);
352 else
353 mon_conn = NULL;
6fc6879b 354 os_free(cfile);
6fc6879b 355#endif /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
4a3ade4e
JM
356
357 if (mon_conn) {
358 if (wpa_ctrl_attach(mon_conn) == 0) {
359 wpa_cli_attached = 1;
cd101567
JM
360 if (interactive)
361 eloop_register_read_sock(
362 wpa_ctrl_get_fd(mon_conn),
363 wpa_cli_mon_receive, NULL, NULL);
4a3ade4e
JM
364 } else {
365 printf("Warning: Failed to attach to "
366 "wpa_supplicant.\n");
d62aaa7d 367 wpa_cli_close_connection();
4a3ade4e
JM
368 return -1;
369 }
370 }
371
372 return 0;
6fc6879b
JM
373}
374
375
376static void wpa_cli_close_connection(void)
377{
378 if (ctrl_conn == NULL)
379 return;
380
381 if (wpa_cli_attached) {
4a3ade4e 382 wpa_ctrl_detach(interactive ? mon_conn : ctrl_conn);
6fc6879b
JM
383 wpa_cli_attached = 0;
384 }
385 wpa_ctrl_close(ctrl_conn);
386 ctrl_conn = NULL;
4a3ade4e 387 if (mon_conn) {
cd101567 388 eloop_unregister_read_sock(wpa_ctrl_get_fd(mon_conn));
4a3ade4e
JM
389 wpa_ctrl_close(mon_conn);
390 mon_conn = NULL;
391 }
6fc6879b
JM
392}
393
394
395static void wpa_cli_msg_cb(char *msg, size_t len)
396{
397 printf("%s\n", msg);
398}
399
400
401static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
402{
403 char buf[2048];
404 size_t len;
405 int ret;
406
407 if (ctrl_conn == NULL) {
408 printf("Not connected to wpa_supplicant - command dropped.\n");
409 return -1;
410 }
411 len = sizeof(buf) - 1;
412 ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
413 wpa_cli_msg_cb);
414 if (ret == -2) {
415 printf("'%s' command timed out.\n", cmd);
416 return -2;
417 } else if (ret < 0) {
418 printf("'%s' command failed.\n", cmd);
419 return -1;
420 }
421 if (print) {
422 buf[len] = '\0';
423 printf("%s", buf);
a432bafb
JM
424 if (interactive && len > 0 && buf[len - 1] != '\n')
425 printf("\n");
6fc6879b
JM
426 }
427 return 0;
428}
429
430
431static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
432{
433 return _wpa_ctrl_command(ctrl, cmd, 1);
434}
435
436
0076869c
JM
437static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
438 char *argv[])
439{
440 int i, res;
441 char *pos, *end;
442
443 pos = buf;
444 end = buf + buflen;
445
446 res = os_snprintf(pos, end - pos, "%s", cmd);
447 if (res < 0 || res >= end - pos)
448 goto fail;
449 pos += res;
450
451 for (i = 0; i < argc; i++) {
452 res = os_snprintf(pos, end - pos, " %s", argv[i]);
453 if (res < 0 || res >= end - pos)
454 goto fail;
455 pos += res;
456 }
457
458 buf[buflen - 1] = '\0';
459 return 0;
460
461fail:
462 printf("Too long command\n");
463 return -1;
464}
465
466
467static int wpa_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd, int min_args,
468 int argc, char *argv[])
469{
470 char buf[256];
471 if (argc < min_args) {
472 printf("Invalid %s command - at least %d argument%s "
473 "required.\n", cmd, min_args,
474 min_args > 1 ? "s are" : " is");
475 return -1;
476 }
477 if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0)
478 return -1;
479 return wpa_ctrl_command(ctrl, buf);
480}
481
482
0eed2a8d
JD
483static int wpa_cli_cmd_ifname(struct wpa_ctrl *ctrl, int argc, char *argv[])
484{
485 return wpa_ctrl_command(ctrl, "IFNAME");
486}
487
488
6fc6879b
JM
489static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
490{
0bc13468
JM
491 if (argc > 0 && os_strcmp(argv[0], "verbose") == 0)
492 return wpa_ctrl_command(ctrl, "STATUS-VERBOSE");
493 if (argc > 0 && os_strcmp(argv[0], "wps") == 0)
494 return wpa_ctrl_command(ctrl, "STATUS-WPS");
495 return wpa_ctrl_command(ctrl, "STATUS");
6fc6879b
JM
496}
497
498
499static int wpa_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
500{
501 return wpa_ctrl_command(ctrl, "PING");
502}
503
504
ac6912b5
BG
505static int wpa_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
506{
507 return wpa_ctrl_command(ctrl, "RELOG");
508}
509
510
77895cd9
JM
511static int wpa_cli_cmd_note(struct wpa_ctrl *ctrl, int argc, char *argv[])
512{
0076869c 513 return wpa_cli_cmd(ctrl, "NOTE", 1, argc, argv);
77895cd9
JM
514}
515
516
6fc6879b
JM
517static int wpa_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
518{
519 return wpa_ctrl_command(ctrl, "MIB");
520}
521
522
523static int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
524{
525 return wpa_ctrl_command(ctrl, "PMKSA");
526}
527
528
529static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
530{
2af4d404 531 print_help(argc > 0 ? argv[0] : NULL);
6fc6879b
JM
532 return 0;
533}
534
535
2af4d404
JM
536static char ** wpa_cli_complete_help(const char *str, int pos)
537{
538 int arg = get_cmd_arg_num(str, pos);
539 char **res = NULL;
540
541 switch (arg) {
542 case 1:
543 res = wpa_list_cmd_list();
544 break;
545 }
546
547 return res;
548}
549
550
6fc6879b
JM
551static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[])
552{
553 printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license);
554 return 0;
555}
556
557
558static int wpa_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
559{
560 wpa_cli_quit = 1;
cd101567
JM
561 if (interactive)
562 eloop_terminate();
6fc6879b
JM
563 return 0;
564}
565
566
567static void wpa_cli_show_variables(void)
568{
569 printf("set variables:\n"
570 " EAPOL::heldPeriod (EAPOL state machine held period, "
571 "in seconds)\n"
572 " EAPOL::authPeriod (EAPOL state machine authentication "
573 "period, in seconds)\n"
574 " EAPOL::startPeriod (EAPOL state machine start period, in "
575 "seconds)\n"
576 " EAPOL::maxStart (EAPOL state machine maximum start "
577 "attempts)\n");
578 printf(" dot11RSNAConfigPMKLifetime (WPA/WPA2 PMK lifetime in "
579 "seconds)\n"
580 " dot11RSNAConfigPMKReauthThreshold (WPA/WPA2 reauthentication"
581 " threshold\n\tpercentage)\n"
582 " dot11RSNAConfigSATimeout (WPA/WPA2 timeout for completing "
583 "security\n\tassociation in seconds)\n");
584}
585
586
587static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
588{
589 char cmd[256];
590 int res;
591
592 if (argc == 0) {
593 wpa_cli_show_variables();
594 return 0;
595 }
596
40eac890 597 if (argc != 1 && argc != 2) {
6fc6879b
JM
598 printf("Invalid SET command: needs two arguments (variable "
599 "name and value)\n");
600 return -1;
601 }
602
40eac890
JM
603 if (argc == 1)
604 res = os_snprintf(cmd, sizeof(cmd), "SET %s ", argv[0]);
605 else
606 res = os_snprintf(cmd, sizeof(cmd), "SET %s %s",
607 argv[0], argv[1]);
6fc6879b
JM
608 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
609 printf("Too long SET command.\n");
610 return -1;
611 }
612 return wpa_ctrl_command(ctrl, cmd);
613}
614
615
acec8d32
JM
616static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
617{
87c7ba84 618 return wpa_cli_cmd(ctrl, "GET", 1, argc, argv);
acec8d32
JM
619}
620
621
6fc6879b
JM
622static int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[])
623{
624 return wpa_ctrl_command(ctrl, "LOGOFF");
625}
626
627
628static int wpa_cli_cmd_logon(struct wpa_ctrl *ctrl, int argc, char *argv[])
629{
630 return wpa_ctrl_command(ctrl, "LOGON");
631}
632
633
634static int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc,
635 char *argv[])
636{
637 return wpa_ctrl_command(ctrl, "REASSOCIATE");
638}
639
640
641static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc,
642 char *argv[])
643{
87c7ba84 644 return wpa_cli_cmd(ctrl, "PREAUTH", 1, argc, argv);
6fc6879b
JM
645}
646
647
648static int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
649{
87c7ba84 650 return wpa_cli_cmd(ctrl, "AP_SCAN", 1, argc, argv);
6fc6879b
JM
651}
652
653
67b9bd08
DS
654static int wpa_cli_cmd_scan_interval(struct wpa_ctrl *ctrl, int argc,
655 char *argv[])
656{
87c7ba84 657 return wpa_cli_cmd(ctrl, "SCAN_INTERVAL", 1, argc, argv);
67b9bd08
DS
658}
659
660
78633c37
SL
661static int wpa_cli_cmd_bss_expire_age(struct wpa_ctrl *ctrl, int argc,
662 char *argv[])
663{
87c7ba84 664 return wpa_cli_cmd(ctrl, "BSS_EXPIRE_AGE", 1, argc, argv);
78633c37
SL
665}
666
667
668static int wpa_cli_cmd_bss_expire_count(struct wpa_ctrl *ctrl, int argc,
669 char *argv[])
670{
87c7ba84 671 return wpa_cli_cmd(ctrl, "BSS_EXPIRE_COUNT", 1, argc, argv);
78633c37
SL
672}
673
674
39ee845f
DS
675static int wpa_cli_cmd_bss_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
676{
677 char cmd[256];
678 int res;
679
680 if (argc < 1)
681 res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH 0");
682 else
683 res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH %s", argv[0]);
684 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
685 printf("Too long BSS_FLUSH command.\n");
686 return -1;
687 }
688 return wpa_ctrl_command(ctrl, cmd);
689}
690
691
6fc6879b
JM
692static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc,
693 char *argv[])
694{
87c7ba84 695 return wpa_cli_cmd(ctrl, "STKSTART", 1, argc, argv);
6fc6879b
JM
696}
697
698
699static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[])
700{
87c7ba84 701 return wpa_cli_cmd(ctrl, "FT_DS", 1, argc, argv);
6fc6879b
JM
702}
703
704
fcc60db4
JM
705static int wpa_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[])
706{
87c7ba84 707 return wpa_cli_cmd(ctrl, "WPS_PBC", 0, argc, argv);
fcc60db4
JM
708}
709
710
711static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
712{
fcc60db4
JM
713 if (argc == 0) {
714 printf("Invalid WPS_PIN command: need one or two arguments:\n"
715 "- BSSID: use 'any' to select any\n"
716 "- PIN: optional, used only with devices that have no "
717 "display\n");
718 return -1;
719 }
720
87c7ba84 721 return wpa_cli_cmd(ctrl, "WPS_PIN", 1, argc, argv);
fcc60db4
JM
722}
723
724
3981cb3c
JM
725static int wpa_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
726 char *argv[])
727{
87c7ba84 728 return wpa_cli_cmd(ctrl, "WPS_CHECK_PIN", 1, argc, argv);
3981cb3c
JM
729}
730
731
2f9929ff
AC
732static int wpa_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
733 char *argv[])
734{
735 return wpa_ctrl_command(ctrl, "WPS_CANCEL");
736}
737
738
71892384 739#ifdef CONFIG_WPS_NFC
3f2c8ba6
JM
740
741static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[])
742{
87c7ba84 743 return wpa_cli_cmd(ctrl, "WPS_NFC", 0, argc, argv);
3f2c8ba6
JM
744}
745
746
bbf41865
JM
747static int wpa_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl, int argc,
748 char *argv[])
749{
750 return wpa_cli_cmd(ctrl, "WPS_NFC_CONFIG_TOKEN", 1, argc, argv);
751}
752
753
3f2c8ba6
JM
754static int wpa_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, int argc,
755 char *argv[])
756{
87c7ba84 757 return wpa_cli_cmd(ctrl, "WPS_NFC_TOKEN", 1, argc, argv);
3f2c8ba6 758}
d7645d23
JM
759
760
761static int wpa_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
762 char *argv[])
763{
764 int ret;
765 char *buf;
766 size_t buflen;
767
768 if (argc != 1) {
769 printf("Invalid 'wps_nfc_tag_read' command - one argument "
770 "is required.\n");
771 return -1;
772 }
773
774 buflen = 18 + os_strlen(argv[0]);
775 buf = os_malloc(buflen);
776 if (buf == NULL)
777 return -1;
778 os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
779
780 ret = wpa_ctrl_command(ctrl, buf);
781 os_free(buf);
782
783 return ret;
784}
71892384 785
e65552dd
JM
786
787static int wpa_cli_cmd_nfc_get_handover_req(struct wpa_ctrl *ctrl, int argc,
788 char *argv[])
789{
790 return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_REQ", 2, argc, argv);
791}
792
793
794static int wpa_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl, int argc,
795 char *argv[])
796{
797 return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_SEL", 2, argc, argv);
798}
799
800
801static int wpa_cli_cmd_nfc_rx_handover_req(struct wpa_ctrl *ctrl, int argc,
802 char *argv[])
803{
804 int ret;
805 char *buf;
806 size_t buflen;
807
808 if (argc != 1) {
809 printf("Invalid 'nfc_rx_handover_req' command - one argument "
810 "is required.\n");
811 return -1;
812 }
813
814 buflen = 21 + os_strlen(argv[0]);
815 buf = os_malloc(buflen);
816 if (buf == NULL)
817 return -1;
818 os_snprintf(buf, buflen, "NFC_RX_HANDOVER_REQ %s", argv[0]);
819
820 ret = wpa_ctrl_command(ctrl, buf);
821 os_free(buf);
822
823 return ret;
824}
825
826
827static int wpa_cli_cmd_nfc_rx_handover_sel(struct wpa_ctrl *ctrl, int argc,
828 char *argv[])
829{
830 int ret;
831 char *buf;
832 size_t buflen;
833
834 if (argc != 1) {
835 printf("Invalid 'nfc_rx_handover_sel' command - one argument "
836 "is required.\n");
837 return -1;
838 }
839
840 buflen = 21 + os_strlen(argv[0]);
841 buf = os_malloc(buflen);
842 if (buf == NULL)
843 return -1;
844 os_snprintf(buf, buflen, "NFC_RX_HANDOVER_SEL %s", argv[0]);
845
846 ret = wpa_ctrl_command(ctrl, buf);
847 os_free(buf);
848
849 return ret;
850}
851
e4758827
JM
852
853static int wpa_cli_cmd_nfc_report_handover(struct wpa_ctrl *ctrl, int argc,
854 char *argv[])
855{
856 return wpa_cli_cmd(ctrl, "NFC_REPORT_HANDOVER", 4, argc, argv);
857}
858
71892384 859#endif /* CONFIG_WPS_NFC */
46bdb83a
MH
860
861
fcc60db4
JM
862static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
863{
864 char cmd[256];
865 int res;
866
52eb293d
JM
867 if (argc == 2)
868 res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s",
869 argv[0], argv[1]);
7d6640a6 870 else if (argc == 5 || argc == 6) {
52eb293d
JM
871 char ssid_hex[2 * 32 + 1];
872 char key_hex[2 * 64 + 1];
873 int i;
874
875 ssid_hex[0] = '\0';
876 for (i = 0; i < 32; i++) {
877 if (argv[2][i] == '\0')
878 break;
879 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]);
880 }
881
882 key_hex[0] = '\0';
7d6640a6
JM
883 if (argc == 6) {
884 for (i = 0; i < 64; i++) {
885 if (argv[5][i] == '\0')
886 break;
887 os_snprintf(&key_hex[i * 2], 3, "%02x",
888 argv[5][i]);
889 }
52eb293d
JM
890 }
891
892 res = os_snprintf(cmd, sizeof(cmd),
893 "WPS_REG %s %s %s %s %s %s",
894 argv[0], argv[1], ssid_hex, argv[3], argv[4],
895 key_hex);
896 } else {
fcc60db4 897 printf("Invalid WPS_REG command: need two arguments:\n"
129eb428 898 "- BSSID of the target AP\n"
fcc60db4 899 "- AP PIN\n");
52eb293d
JM
900 printf("Alternatively, six arguments can be used to "
901 "reconfigure the AP:\n"
129eb428 902 "- BSSID of the target AP\n"
52eb293d
JM
903 "- AP PIN\n"
904 "- new SSID\n"
905 "- new auth (OPEN, WPAPSK, WPA2PSK)\n"
906 "- new encr (NONE, WEP, TKIP, CCMP)\n"
907 "- new key\n");
fcc60db4
JM
908 return -1;
909 }
910
fcc60db4
JM
911 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
912 printf("Too long WPS_REG command.\n");
913 return -1;
914 }
915 return wpa_ctrl_command(ctrl, cmd);
916}
917
918
70d84f11
JM
919static int wpa_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
920 char *argv[])
921{
87c7ba84 922 return wpa_cli_cmd(ctrl, "WPS_AP_PIN", 1, argc, argv);
70d84f11
JM
923}
924
925
e9bcfebf
JM
926static int wpa_cli_cmd_wps_er_start(struct wpa_ctrl *ctrl, int argc,
927 char *argv[])
928{
87c7ba84 929 return wpa_cli_cmd(ctrl, "WPS_ER_START", 0, argc, argv);
e9bcfebf
JM
930}
931
932
933static int wpa_cli_cmd_wps_er_stop(struct wpa_ctrl *ctrl, int argc,
934 char *argv[])
935{
936 return wpa_ctrl_command(ctrl, "WPS_ER_STOP");
937
938}
939
940
72df2f5f
JM
941static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc,
942 char *argv[])
943{
31fcea93
JM
944 if (argc < 2) {
945 printf("Invalid WPS_ER_PIN command: need at least two "
946 "arguments:\n"
72df2f5f 947 "- UUID: use 'any' to select any\n"
31fcea93
JM
948 "- PIN: Enrollee PIN\n"
949 "optional: - Enrollee MAC address\n");
72df2f5f
JM
950 return -1;
951 }
952
87c7ba84 953 return wpa_cli_cmd(ctrl, "WPS_ER_PIN", 2, argc, argv);
72df2f5f
JM
954}
955
956
564cd7fa
JM
957static int wpa_cli_cmd_wps_er_pbc(struct wpa_ctrl *ctrl, int argc,
958 char *argv[])
959{
87c7ba84 960 return wpa_cli_cmd(ctrl, "WPS_ER_PBC", 1, argc, argv);
564cd7fa
JM
961}
962
963
e64dcfd5
JM
964static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc,
965 char *argv[])
966{
e64dcfd5
JM
967 if (argc != 2) {
968 printf("Invalid WPS_ER_LEARN command: need two arguments:\n"
969 "- UUID: specify which AP to use\n"
970 "- PIN: AP PIN\n");
971 return -1;
972 }
973
87c7ba84 974 return wpa_cli_cmd(ctrl, "WPS_ER_LEARN", 2, argc, argv);
e64dcfd5
JM
975}
976
977
ef10f473
JM
978static int wpa_cli_cmd_wps_er_set_config(struct wpa_ctrl *ctrl, int argc,
979 char *argv[])
980{
ef10f473
JM
981 if (argc != 2) {
982 printf("Invalid WPS_ER_SET_CONFIG command: need two "
983 "arguments:\n"
984 "- UUID: specify which AP to use\n"
985 "- Network configuration id\n");
986 return -1;
987 }
988
87c7ba84 989 return wpa_cli_cmd(ctrl, "WPS_ER_SET_CONFIG", 2, argc, argv);
ef10f473
JM
990}
991
992
7d6640a6
JM
993static int wpa_cli_cmd_wps_er_config(struct wpa_ctrl *ctrl, int argc,
994 char *argv[])
995{
996 char cmd[256];
997 int res;
998
999 if (argc == 5 || argc == 6) {
1000 char ssid_hex[2 * 32 + 1];
1001 char key_hex[2 * 64 + 1];
1002 int i;
1003
1004 ssid_hex[0] = '\0';
1005 for (i = 0; i < 32; i++) {
1006 if (argv[2][i] == '\0')
1007 break;
1008 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]);
1009 }
1010
1011 key_hex[0] = '\0';
1012 if (argc == 6) {
1013 for (i = 0; i < 64; i++) {
1014 if (argv[5][i] == '\0')
1015 break;
1016 os_snprintf(&key_hex[i * 2], 3, "%02x",
1017 argv[5][i]);
1018 }
1019 }
1020
1021 res = os_snprintf(cmd, sizeof(cmd),
1022 "WPS_ER_CONFIG %s %s %s %s %s %s",
1023 argv[0], argv[1], ssid_hex, argv[3], argv[4],
1024 key_hex);
1025 } else {
1026 printf("Invalid WPS_ER_CONFIG command: need six arguments:\n"
1027 "- AP UUID\n"
1028 "- AP PIN\n"
1029 "- new SSID\n"
1030 "- new auth (OPEN, WPAPSK, WPA2PSK)\n"
1031 "- new encr (NONE, WEP, TKIP, CCMP)\n"
1032 "- new key\n");
1033 return -1;
1034 }
1035
1036 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
1037 printf("Too long WPS_ER_CONFIG command.\n");
1038 return -1;
1039 }
1040 return wpa_ctrl_command(ctrl, cmd);
1041}
1042
1043
1cea09a9
JM
1044#ifdef CONFIG_WPS_NFC
1045static int wpa_cli_cmd_wps_er_nfc_config_token(struct wpa_ctrl *ctrl, int argc,
1046 char *argv[])
1047{
1cea09a9
JM
1048 if (argc != 2) {
1049 printf("Invalid WPS_ER_NFC_CONFIG_TOKEN command: need two "
1050 "arguments:\n"
1051 "- WPS/NDEF: token format\n"
1052 "- UUID: specify which AP to use\n");
1053 return -1;
1054 }
1055
87c7ba84 1056 return wpa_cli_cmd(ctrl, "WPS_ER_NFC_CONFIG_TOKEN", 2, argc, argv);
1cea09a9
JM
1057}
1058#endif /* CONFIG_WPS_NFC */
1059
1060
11ef8d35
JM
1061static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[])
1062{
87c7ba84 1063 return wpa_cli_cmd(ctrl, "IBSS_RSN", 1, argc, argv);
11ef8d35
JM
1064}
1065
1066
6fc6879b
JM
1067static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
1068{
87c7ba84 1069 return wpa_cli_cmd(ctrl, "LEVEL", 1, argc, argv);
6fc6879b
JM
1070}
1071
1072
1073static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[])
1074{
1075 char cmd[256], *pos, *end;
1076 int i, ret;
1077
1078 if (argc < 2) {
1079 printf("Invalid IDENTITY command: needs two arguments "
1080 "(network id and identity)\n");
1081 return -1;
1082 }
1083
1084 end = cmd + sizeof(cmd);
1085 pos = cmd;
1086 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s",
1087 argv[0], argv[1]);
1088 if (ret < 0 || ret >= end - pos) {
1089 printf("Too long IDENTITY command.\n");
1090 return -1;
1091 }
1092 pos += ret;
1093 for (i = 2; i < argc; i++) {
1094 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
1095 if (ret < 0 || ret >= end - pos) {
1096 printf("Too long IDENTITY command.\n");
1097 return -1;
1098 }
1099 pos += ret;
1100 }
1101
1102 return wpa_ctrl_command(ctrl, cmd);
1103}
1104
1105
1106static int wpa_cli_cmd_password(struct wpa_ctrl *ctrl, int argc, char *argv[])
1107{
1108 char cmd[256], *pos, *end;
1109 int i, ret;
1110
1111 if (argc < 2) {
1112 printf("Invalid PASSWORD command: needs two arguments "
1113 "(network id and password)\n");
1114 return -1;
1115 }
1116
1117 end = cmd + sizeof(cmd);
1118 pos = cmd;
1119 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s",
1120 argv[0], argv[1]);
1121 if (ret < 0 || ret >= end - pos) {
1122 printf("Too long PASSWORD command.\n");
1123 return -1;
1124 }
1125 pos += ret;
1126 for (i = 2; i < argc; i++) {
1127 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
1128 if (ret < 0 || ret >= end - pos) {
1129 printf("Too long PASSWORD command.\n");
1130 return -1;
1131 }
1132 pos += ret;
1133 }
1134
1135 return wpa_ctrl_command(ctrl, cmd);
1136}
1137
1138
1139static int wpa_cli_cmd_new_password(struct wpa_ctrl *ctrl, int argc,
1140 char *argv[])
1141{
1142 char cmd[256], *pos, *end;
1143 int i, ret;
1144
1145 if (argc < 2) {
1146 printf("Invalid NEW_PASSWORD command: needs two arguments "
1147 "(network id and password)\n");
1148 return -1;
1149 }
1150
1151 end = cmd + sizeof(cmd);
1152 pos = cmd;
1153 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s",
1154 argv[0], argv[1]);
1155 if (ret < 0 || ret >= end - pos) {
1156 printf("Too long NEW_PASSWORD command.\n");
1157 return -1;
1158 }
1159 pos += ret;
1160 for (i = 2; i < argc; i++) {
1161 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
1162 if (ret < 0 || ret >= end - pos) {
1163 printf("Too long NEW_PASSWORD command.\n");
1164 return -1;
1165 }
1166 pos += ret;
1167 }
1168
1169 return wpa_ctrl_command(ctrl, cmd);
1170}
1171
1172
1173static int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
1174{
1175 char cmd[256], *pos, *end;
1176 int i, ret;
1177
1178 if (argc < 2) {
1179 printf("Invalid PIN command: needs two arguments "
1180 "(network id and pin)\n");
1181 return -1;
1182 }
1183
1184 end = cmd + sizeof(cmd);
1185 pos = cmd;
1186 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s",
1187 argv[0], argv[1]);
1188 if (ret < 0 || ret >= end - pos) {
1189 printf("Too long PIN command.\n");
1190 return -1;
1191 }
1192 pos += ret;
1193 for (i = 2; i < argc; i++) {
1194 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
1195 if (ret < 0 || ret >= end - pos) {
1196 printf("Too long PIN command.\n");
1197 return -1;
1198 }
1199 pos += ret;
1200 }
1201 return wpa_ctrl_command(ctrl, cmd);
1202}
1203
1204
1205static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[])
1206{
1207 char cmd[256], *pos, *end;
1208 int i, ret;
1209
1210 if (argc < 2) {
1211 printf("Invalid OTP command: needs two arguments (network "
1212 "id and password)\n");
1213 return -1;
1214 }
1215
1216 end = cmd + sizeof(cmd);
1217 pos = cmd;
1218 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s",
1219 argv[0], argv[1]);
1220 if (ret < 0 || ret >= end - pos) {
1221 printf("Too long OTP command.\n");
1222 return -1;
1223 }
1224 pos += ret;
1225 for (i = 2; i < argc; i++) {
1226 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
1227 if (ret < 0 || ret >= end - pos) {
1228 printf("Too long OTP command.\n");
1229 return -1;
1230 }
1231 pos += ret;
1232 }
1233
1234 return wpa_ctrl_command(ctrl, cmd);
1235}
1236
1237
1238static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
1239 char *argv[])
1240{
1241 char cmd[256], *pos, *end;
1242 int i, ret;
1243
1244 if (argc < 2) {
1245 printf("Invalid PASSPHRASE command: needs two arguments "
1246 "(network id and passphrase)\n");
1247 return -1;
1248 }
1249
1250 end = cmd + sizeof(cmd);
1251 pos = cmd;
1252 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s",
1253 argv[0], argv[1]);
1254 if (ret < 0 || ret >= end - pos) {
1255 printf("Too long PASSPHRASE command.\n");
1256 return -1;
1257 }
1258 pos += ret;
1259 for (i = 2; i < argc; i++) {
1260 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
1261 if (ret < 0 || ret >= end - pos) {
1262 printf("Too long PASSPHRASE command.\n");
1263 return -1;
1264 }
1265 pos += ret;
1266 }
1267
1268 return wpa_ctrl_command(ctrl, cmd);
1269}
1270
1271
1272static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[])
1273{
6fc6879b
JM
1274 if (argc < 2) {
1275 printf("Invalid BSSID command: needs two arguments (network "
1276 "id and BSSID)\n");
1277 return -1;
1278 }
1279
87c7ba84 1280 return wpa_cli_cmd(ctrl, "BSSID", 2, argc, argv);
6fc6879b
JM
1281}
1282
1283
9aa10e2b
DS
1284static int wpa_cli_cmd_blacklist(struct wpa_ctrl *ctrl, int argc, char *argv[])
1285{
87c7ba84
JM
1286 return wpa_cli_cmd(ctrl, "BLACKLIST", 0, argc, argv);
1287}
9aa10e2b
DS
1288
1289
0597a5b5
DS
1290static int wpa_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
1291{
87c7ba84 1292 return wpa_cli_cmd(ctrl, "LOG_LEVEL", 0, argc, argv);
0597a5b5
DS
1293}
1294
1295
6fc6879b
JM
1296static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc,
1297 char *argv[])
1298{
1299 return wpa_ctrl_command(ctrl, "LIST_NETWORKS");
1300}
1301
1302
1303static int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc,
1304 char *argv[])
1305{
87c7ba84 1306 return wpa_cli_cmd(ctrl, "SELECT_NETWORK", 1, argc, argv);
6fc6879b
JM
1307}
1308
1309
1310static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc,
1311 char *argv[])
1312{
87c7ba84 1313 return wpa_cli_cmd(ctrl, "ENABLE_NETWORK", 1, argc, argv);
6fc6879b
JM
1314}
1315
1316
1317static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc,
1318 char *argv[])
1319{
87c7ba84 1320 return wpa_cli_cmd(ctrl, "DISABLE_NETWORK", 1, argc, argv);
6fc6879b
JM
1321}
1322
1323
1324static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc,
1325 char *argv[])
1326{
1327 return wpa_ctrl_command(ctrl, "ADD_NETWORK");
1328}
1329
1330
1331static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc,
1332 char *argv[])
1333{
87c7ba84 1334 return wpa_cli_cmd(ctrl, "REMOVE_NETWORK", 1, argc, argv);
6fc6879b
JM
1335}
1336
1337
1338static void wpa_cli_show_network_variables(void)
1339{
1340 printf("set_network variables:\n"
1341 " ssid (network name, SSID)\n"
1342 " psk (WPA passphrase or pre-shared key)\n"
1343 " key_mgmt (key management protocol)\n"
1344 " identity (EAP identity)\n"
1345 " password (EAP password)\n"
1346 " ...\n"
1347 "\n"
1348 "Note: Values are entered in the same format as the "
1349 "configuration file is using,\n"
1350 "i.e., strings values need to be inside double quotation "
1351 "marks.\n"
1352 "For example: set_network 1 ssid \"network name\"\n"
1353 "\n"
1354 "Please see wpa_supplicant.conf documentation for full list "
1355 "of\navailable variables.\n");
1356}
1357
1358
1359static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc,
1360 char *argv[])
1361{
6fc6879b
JM
1362 if (argc == 0) {
1363 wpa_cli_show_network_variables();
1364 return 0;
1365 }
1366
af1dff8c 1367 if (argc < 3) {
6fc6879b
JM
1368 printf("Invalid SET_NETWORK command: needs three arguments\n"
1369 "(network id, variable name, and value)\n");
1370 return -1;
1371 }
1372
87c7ba84 1373 return wpa_cli_cmd(ctrl, "SET_NETWORK", 3, argc, argv);
6fc6879b
JM
1374}
1375
1376
1377static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
1378 char *argv[])
1379{
6fc6879b
JM
1380 if (argc == 0) {
1381 wpa_cli_show_network_variables();
1382 return 0;
1383 }
1384
1385 if (argc != 2) {
1386 printf("Invalid GET_NETWORK command: needs two arguments\n"
1387 "(network id and variable name)\n");
1388 return -1;
1389 }
1390
87c7ba84 1391 return wpa_cli_cmd(ctrl, "GET_NETWORK", 2, argc, argv);
6fc6879b
JM
1392}
1393
1394
d94c9ee6
JM
1395static int wpa_cli_cmd_list_creds(struct wpa_ctrl *ctrl, int argc,
1396 char *argv[])
1397{
1398 return wpa_ctrl_command(ctrl, "LIST_CREDS");
1399}
1400
1401
1402static int wpa_cli_cmd_add_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
1403{
1404 return wpa_ctrl_command(ctrl, "ADD_CRED");
1405}
1406
1407
1408static int wpa_cli_cmd_remove_cred(struct wpa_ctrl *ctrl, int argc,
1409 char *argv[])
1410{
87c7ba84 1411 return wpa_cli_cmd(ctrl, "REMOVE_CRED", 1, argc, argv);
d94c9ee6
JM
1412}
1413
1414
1415static int wpa_cli_cmd_set_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
1416{
d94c9ee6
JM
1417 if (argc != 3) {
1418 printf("Invalid SET_CRED command: needs three arguments\n"
1419 "(cred id, variable name, and value)\n");
1420 return -1;
1421 }
1422
87c7ba84 1423 return wpa_cli_cmd(ctrl, "SET_CRED", 3, argc, argv);
d94c9ee6
JM
1424}
1425
1426
6fc6879b
JM
1427static int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc,
1428 char *argv[])
1429{
1430 return wpa_ctrl_command(ctrl, "DISCONNECT");
1431}
1432
1433
1434static int wpa_cli_cmd_reconnect(struct wpa_ctrl *ctrl, int argc,
1435 char *argv[])
1436{
1437 return wpa_ctrl_command(ctrl, "RECONNECT");
1438}
1439
1440
1441static int wpa_cli_cmd_save_config(struct wpa_ctrl *ctrl, int argc,
1442 char *argv[])
1443{
1444 return wpa_ctrl_command(ctrl, "SAVE_CONFIG");
1445}
1446
1447
1448static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
1449{
66fe0f70 1450 return wpa_cli_cmd(ctrl, "SCAN", 0, argc, argv);
6fc6879b
JM
1451}
1452
1453
1454static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc,
1455 char *argv[])
1456{
1457 return wpa_ctrl_command(ctrl, "SCAN_RESULTS");
1458}
1459
1460
1461static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
1462{
87c7ba84 1463 return wpa_cli_cmd(ctrl, "BSS", 1, argc, argv);
6fc6879b
JM
1464}
1465
1466
a624f20b
JM
1467static char ** wpa_cli_complete_bss(const char *str, int pos)
1468{
1469 int arg = get_cmd_arg_num(str, pos);
1470 char **res = NULL;
1471
1472 switch (arg) {
1473 case 1:
1474 res = cli_txt_list_array(&bsses);
1475 break;
1476 }
1477
1478 return res;
1479}
1480
1481
6fc6879b
JM
1482static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
1483 char *argv[])
1484{
6fc6879b
JM
1485 if (argc < 1 || argc > 2) {
1486 printf("Invalid GET_CAPABILITY command: need either one or "
1487 "two arguments\n");
1488 return -1;
1489 }
1490
1491 if ((argc == 2) && os_strcmp(argv[1], "strict") != 0) {
1492 printf("Invalid GET_CAPABILITY command: second argument, "
1493 "if any, must be 'strict'\n");
1494 return -1;
1495 }
1496
87c7ba84 1497 return wpa_cli_cmd(ctrl, "GET_CAPABILITY", 1, argc, argv);
6fc6879b
JM
1498}
1499
1500
1501static int wpa_cli_list_interfaces(struct wpa_ctrl *ctrl)
1502{
1503 printf("Available interfaces:\n");
1504 return wpa_ctrl_command(ctrl, "INTERFACES");
1505}
1506
1507
1508static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[])
1509{
1510 if (argc < 1) {
1511 wpa_cli_list_interfaces(ctrl);
1512 return 0;
1513 }
1514
1515 wpa_cli_close_connection();
1516 os_free(ctrl_ifname);
1517 ctrl_ifname = os_strdup(argv[0]);
1518
4a3ade4e 1519 if (wpa_cli_open_connection(ctrl_ifname, 1)) {
6fc6879b 1520 printf("Connected to interface '%s.\n", ctrl_ifname);
6fc6879b
JM
1521 } else {
1522 printf("Could not connect to interface '%s' - re-trying\n",
1523 ctrl_ifname);
1524 }
1525 return 0;
1526}
1527
1528
1529static int wpa_cli_cmd_reconfigure(struct wpa_ctrl *ctrl, int argc,
1530 char *argv[])
1531{
1532 return wpa_ctrl_command(ctrl, "RECONFIGURE");
1533}
1534
1535
1536static int wpa_cli_cmd_terminate(struct wpa_ctrl *ctrl, int argc,
1537 char *argv[])
1538{
1539 return wpa_ctrl_command(ctrl, "TERMINATE");
1540}
1541
1542
1543static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc,
1544 char *argv[])
1545{
1546 char cmd[256];
1547 int res;
1548
1549 if (argc < 1) {
1550 printf("Invalid INTERFACE_ADD command: needs at least one "
1551 "argument (interface name)\n"
1552 "All arguments: ifname confname driver ctrl_interface "
1553 "driver_param bridge_name\n");
1554 return -1;
1555 }
1556
1557 /*
1558 * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
1559 * <driver_param>TAB<bridge_name>
1560 */
1561 res = os_snprintf(cmd, sizeof(cmd),
1562 "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s",
1563 argv[0],
1564 argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "",
1565 argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "",
1566 argc > 5 ? argv[5] : "");
1567 if (res < 0 || (size_t) res >= sizeof(cmd))
1568 return -1;
1569 cmd[sizeof(cmd) - 1] = '\0';
1570 return wpa_ctrl_command(ctrl, cmd);
1571}
1572
1573
1574static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc,
1575 char *argv[])
1576{
87c7ba84 1577 return wpa_cli_cmd(ctrl, "INTERFACE_REMOVE", 1, argc, argv);
6fc6879b
JM
1578}
1579
1580
4b4a8ae5
JM
1581static int wpa_cli_cmd_interface_list(struct wpa_ctrl *ctrl, int argc,
1582 char *argv[])
1583{
1584 return wpa_ctrl_command(ctrl, "INTERFACE_LIST");
1585}
1586
1587
e653b622
JM
1588#ifdef CONFIG_AP
1589static int wpa_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
1590{
87c7ba84 1591 return wpa_cli_cmd(ctrl, "STA", 1, argc, argv);
e653b622
JM
1592}
1593
1594
1595static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
1596 char *addr, size_t addr_len)
1597{
1598 char buf[4096], *pos;
1599 size_t len;
1600 int ret;
1601
1602 if (ctrl_conn == NULL) {
1603 printf("Not connected to hostapd - command dropped.\n");
1604 return -1;
1605 }
1606 len = sizeof(buf) - 1;
024d018b 1607 ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
e653b622
JM
1608 wpa_cli_msg_cb);
1609 if (ret == -2) {
1610 printf("'%s' command timed out.\n", cmd);
1611 return -2;
1612 } else if (ret < 0) {
1613 printf("'%s' command failed.\n", cmd);
1614 return -1;
1615 }
1616
1617 buf[len] = '\0';
024d018b 1618 if (os_memcmp(buf, "FAIL", 4) == 0)
e653b622
JM
1619 return -1;
1620 printf("%s", buf);
1621
1622 pos = buf;
1623 while (*pos != '\0' && *pos != '\n')
1624 pos++;
1625 *pos = '\0';
1626 os_strlcpy(addr, buf, addr_len);
1627 return 0;
1628}
1629
1630
1631static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
1632{
1633 char addr[32], cmd[64];
1634
1635 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
1636 return 0;
1637 do {
e824cc46 1638 os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
e653b622
JM
1639 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
1640
1641 return -1;
1642}
e60b2951
JJ
1643
1644
1645static int wpa_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
1646 char *argv[])
1647{
87c7ba84 1648 return wpa_cli_cmd(ctrl, "DEAUTHENTICATE", 1, argc, argv);
e60b2951
JJ
1649}
1650
1651
1652static int wpa_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
1653 char *argv[])
1654{
87c7ba84 1655 return wpa_cli_cmd(ctrl, "DISASSOCIATE", 1, argc, argv);
e60b2951 1656}
e653b622
JM
1657#endif /* CONFIG_AP */
1658
1659
207ef3fb
JM
1660static int wpa_cli_cmd_suspend(struct wpa_ctrl *ctrl, int argc, char *argv[])
1661{
1662 return wpa_ctrl_command(ctrl, "SUSPEND");
1663}
1664
1665
1666static int wpa_cli_cmd_resume(struct wpa_ctrl *ctrl, int argc, char *argv[])
1667{
1668 return wpa_ctrl_command(ctrl, "RESUME");
1669}
1670
1671
32d5295f
JM
1672static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[])
1673{
1674 return wpa_ctrl_command(ctrl, "DROP_SA");
1675}
1676
1677
86d4f806
JM
1678static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
1679{
87c7ba84 1680 return wpa_cli_cmd(ctrl, "ROAM", 1, argc, argv);
86d4f806
JM
1681}
1682
1683
57faa1ce
JM
1684#ifdef CONFIG_P2P
1685
1686static int wpa_cli_cmd_p2p_find(struct wpa_ctrl *ctrl, int argc, char *argv[])
1687{
87c7ba84 1688 return wpa_cli_cmd(ctrl, "P2P_FIND", 0, argc, argv);
57faa1ce
JM
1689}
1690
1691
01335e2c
JM
1692static char ** wpa_cli_complete_p2p_find(const char *str, int pos)
1693{
1694 char **res = NULL;
1695 int arg = get_cmd_arg_num(str, pos);
1696
1697 res = os_calloc(6, sizeof(char *));
1698 if (res == NULL)
1699 return NULL;
1700 res[0] = os_strdup("type=social");
1701 if (res[0] == NULL) {
1702 os_free(res);
1703 return NULL;
1704 }
1705 res[1] = os_strdup("type=progressive");
1706 if (res[1] == NULL)
1707 return res;
1708 res[2] = os_strdup("delay=");
1709 if (res[2] == NULL)
1710 return res;
1711 res[3] = os_strdup("dev_id=");
1712 if (res[3] == NULL)
1713 return res;
1714 if (arg == 1)
1715 res[4] = os_strdup("[timeout]");
1716
1717 return res;
1718}
1719
1720
57faa1ce
JM
1721static int wpa_cli_cmd_p2p_stop_find(struct wpa_ctrl *ctrl, int argc,
1722 char *argv[])
1723{
1724 return wpa_ctrl_command(ctrl, "P2P_STOP_FIND");
1725}
1726
1727
1728static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc,
1729 char *argv[])
1730{
87c7ba84 1731 return wpa_cli_cmd(ctrl, "P2P_CONNECT", 2, argc, argv);
57faa1ce
JM
1732}
1733
1734
a624f20b
JM
1735static char ** wpa_cli_complete_p2p_connect(const char *str, int pos)
1736{
1737 int arg = get_cmd_arg_num(str, pos);
1738 char **res = NULL;
1739
1740 switch (arg) {
1741 case 1:
1742 res = cli_txt_list_array(&p2p_peers);
1743 break;
1744 }
1745
1746 return res;
1747}
1748
1749
57faa1ce
JM
1750static int wpa_cli_cmd_p2p_listen(struct wpa_ctrl *ctrl, int argc,
1751 char *argv[])
1752{
87c7ba84 1753 return wpa_cli_cmd(ctrl, "P2P_LISTEN", 0, argc, argv);
57faa1ce
JM
1754}
1755
1756
1757static int wpa_cli_cmd_p2p_group_remove(struct wpa_ctrl *ctrl, int argc,
1758 char *argv[])
1759{
87c7ba84 1760 return wpa_cli_cmd(ctrl, "P2P_GROUP_REMOVE", 1, argc, argv);
57faa1ce
JM
1761}
1762
1763
76788542
JM
1764static char ** wpa_cli_complete_p2p_group_remove(const char *str, int pos)
1765{
1766 int arg = get_cmd_arg_num(str, pos);
1767 char **res = NULL;
1768
1769 switch (arg) {
1770 case 1:
1771 res = cli_txt_list_array(&p2p_groups);
1772 break;
1773 }
1774
1775 return res;
1776}
1777
1778
57faa1ce
JM
1779static int wpa_cli_cmd_p2p_group_add(struct wpa_ctrl *ctrl, int argc,
1780 char *argv[])
1781{
87c7ba84 1782 return wpa_cli_cmd(ctrl, "P2P_GROUP_ADD", 0, argc, argv);
57faa1ce
JM
1783}
1784
1785
1786static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc,
1787 char *argv[])
1788{
8c5f7309
JJ
1789 if (argc != 2 && argc != 3) {
1790 printf("Invalid P2P_PROV_DISC command: needs at least "
1791 "two arguments, address and config method\n"
1792 "(display, keypad, or pbc) and an optional join\n");
57faa1ce
JM
1793 return -1;
1794 }
1795
87c7ba84 1796 return wpa_cli_cmd(ctrl, "P2P_PROV_DISC", 2, argc, argv);
57faa1ce
JM
1797}
1798
1799
1800static int wpa_cli_cmd_p2p_get_passphrase(struct wpa_ctrl *ctrl, int argc,
1801 char *argv[])
1802{
1803 return wpa_ctrl_command(ctrl, "P2P_GET_PASSPHRASE");
1804}
1805
1806
1807static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc,
1808 char *argv[])
1809{
1810 char cmd[4096];
57faa1ce
JM
1811
1812 if (argc != 2 && argc != 4) {
1813 printf("Invalid P2P_SERV_DISC_REQ command: needs two "
1814 "arguments (address and TLVs) or four arguments "
1815 "(address, \"upnp\", version, search target "
1816 "(SSDP ST:)\n");
1817 return -1;
1818 }
1819
87c7ba84 1820 if (write_cmd(cmd, sizeof(cmd), "P2P_SERV_DISC_REQ", argc, argv) < 0)
57faa1ce 1821 return -1;
57faa1ce
JM
1822 return wpa_ctrl_command(ctrl, cmd);
1823}
1824
1825
1826static int wpa_cli_cmd_p2p_serv_disc_cancel_req(struct wpa_ctrl *ctrl,
1827 int argc, char *argv[])
1828{
87c7ba84 1829 return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_CANCEL_REQ", 1, argc, argv);
57faa1ce
JM
1830}
1831
1832
1833static int wpa_cli_cmd_p2p_serv_disc_resp(struct wpa_ctrl *ctrl, int argc,
1834 char *argv[])
1835{
1836 char cmd[4096];
1837 int res;
1838
1839 if (argc != 4) {
1840 printf("Invalid P2P_SERV_DISC_RESP command: needs four "
1841 "arguments (freq, address, dialog token, and TLVs)\n");
1842 return -1;
1843 }
1844
1845 res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_RESP %s %s %s %s",
1846 argv[0], argv[1], argv[2], argv[3]);
1847 if (res < 0 || (size_t) res >= sizeof(cmd))
1848 return -1;
1849 cmd[sizeof(cmd) - 1] = '\0';
1850 return wpa_ctrl_command(ctrl, cmd);
1851}
1852
1853
1854static int wpa_cli_cmd_p2p_service_update(struct wpa_ctrl *ctrl, int argc,
1855 char *argv[])
1856{
1857 return wpa_ctrl_command(ctrl, "P2P_SERVICE_UPDATE");
1858}
1859
1860
1861static int wpa_cli_cmd_p2p_serv_disc_external(struct wpa_ctrl *ctrl,
1862 int argc, char *argv[])
1863{
87c7ba84 1864 return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_EXTERNAL", 1, argc, argv);
57faa1ce
JM
1865}
1866
1867
1868static int wpa_cli_cmd_p2p_service_flush(struct wpa_ctrl *ctrl, int argc,
1869 char *argv[])
1870{
1871 return wpa_ctrl_command(ctrl, "P2P_SERVICE_FLUSH");
1872}
1873
1874
1875static int wpa_cli_cmd_p2p_service_add(struct wpa_ctrl *ctrl, int argc,
1876 char *argv[])
1877{
1878 char cmd[4096];
1879 int res;
1880
1881 if (argc != 3 && argc != 4) {
1882 printf("Invalid P2P_SERVICE_ADD command: needs three or four "
1883 "arguments\n");
1884 return -1;
1885 }
1886
1887 if (argc == 4)
1888 res = os_snprintf(cmd, sizeof(cmd),
1889 "P2P_SERVICE_ADD %s %s %s %s",
1890 argv[0], argv[1], argv[2], argv[3]);
1891 else
1892 res = os_snprintf(cmd, sizeof(cmd),
1893 "P2P_SERVICE_ADD %s %s %s",
1894 argv[0], argv[1], argv[2]);
1895 if (res < 0 || (size_t) res >= sizeof(cmd))
1896 return -1;
1897 cmd[sizeof(cmd) - 1] = '\0';
1898 return wpa_ctrl_command(ctrl, cmd);
1899}
1900
1901
1902static int wpa_cli_cmd_p2p_service_del(struct wpa_ctrl *ctrl, int argc,
1903 char *argv[])
1904{
1905 char cmd[4096];
1906 int res;
1907
1908 if (argc != 2 && argc != 3) {
1909 printf("Invalid P2P_SERVICE_DEL command: needs two or three "
1910 "arguments\n");
1911 return -1;
1912 }
1913
1914 if (argc == 3)
1915 res = os_snprintf(cmd, sizeof(cmd),
1916 "P2P_SERVICE_DEL %s %s %s",
1917 argv[0], argv[1], argv[2]);
1918 else
1919 res = os_snprintf(cmd, sizeof(cmd),
1920 "P2P_SERVICE_DEL %s %s",
1921 argv[0], argv[1]);
1922 if (res < 0 || (size_t) res >= sizeof(cmd))
1923 return -1;
1924 cmd[sizeof(cmd) - 1] = '\0';
1925 return wpa_ctrl_command(ctrl, cmd);
1926}
1927
1928
1929static int wpa_cli_cmd_p2p_reject(struct wpa_ctrl *ctrl,
1930 int argc, char *argv[])
1931{
87c7ba84 1932 return wpa_cli_cmd(ctrl, "P2P_REJECT", 1, argc, argv);
57faa1ce
JM
1933}
1934
1935
1936static int wpa_cli_cmd_p2p_invite(struct wpa_ctrl *ctrl,
1937 int argc, char *argv[])
1938{
87c7ba84 1939 return wpa_cli_cmd(ctrl, "P2P_INVITE", 1, argc, argv);
57faa1ce
JM
1940}
1941
1942
1943static int wpa_cli_cmd_p2p_peer(struct wpa_ctrl *ctrl, int argc, char *argv[])
1944{
87c7ba84 1945 return wpa_cli_cmd(ctrl, "P2P_PEER", 1, argc, argv);
57faa1ce
JM
1946}
1947
1948
a624f20b
JM
1949static char ** wpa_cli_complete_p2p_peer(const char *str, int pos)
1950{
1951 int arg = get_cmd_arg_num(str, pos);
1952 char **res = NULL;
1953
1954 switch (arg) {
1955 case 1:
1956 res = cli_txt_list_array(&p2p_peers);
1957 break;
1958 }
1959
1960 return res;
1961}
1962
1963
57faa1ce
JM
1964static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, char *cmd,
1965 char *addr, size_t addr_len,
1966 int discovered)
1967{
1968 char buf[4096], *pos;
1969 size_t len;
1970 int ret;
1971
1972 if (ctrl_conn == NULL)
1973 return -1;
1974 len = sizeof(buf) - 1;
024d018b 1975 ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
57faa1ce
JM
1976 wpa_cli_msg_cb);
1977 if (ret == -2) {
1978 printf("'%s' command timed out.\n", cmd);
1979 return -2;
1980 } else if (ret < 0) {
1981 printf("'%s' command failed.\n", cmd);
1982 return -1;
1983 }
1984
1985 buf[len] = '\0';
024d018b 1986 if (os_memcmp(buf, "FAIL", 4) == 0)
57faa1ce
JM
1987 return -1;
1988
1989 pos = buf;
1990 while (*pos != '\0' && *pos != '\n')
1991 pos++;
1992 *pos++ = '\0';
1993 os_strlcpy(addr, buf, addr_len);
1994 if (!discovered || os_strstr(pos, "[PROBE_REQ_ONLY]") == NULL)
1995 printf("%s\n", addr);
1996 return 0;
1997}
1998
1999
2000static int wpa_cli_cmd_p2p_peers(struct wpa_ctrl *ctrl, int argc, char *argv[])
2001{
2002 char addr[32], cmd[64];
2003 int discovered;
2004
2005 discovered = argc > 0 && os_strcmp(argv[0], "discovered") == 0;
2006
2007 if (wpa_ctrl_command_p2p_peer(ctrl, "P2P_PEER FIRST",
2008 addr, sizeof(addr), discovered))
9a6ade33 2009 return -1;
57faa1ce
JM
2010 do {
2011 os_snprintf(cmd, sizeof(cmd), "P2P_PEER NEXT-%s", addr);
2012 } while (wpa_ctrl_command_p2p_peer(ctrl, cmd, addr, sizeof(addr),
2013 discovered) == 0);
2014
9a6ade33 2015 return 0;
57faa1ce
JM
2016}
2017
2018
2019static int wpa_cli_cmd_p2p_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
2020{
87c7ba84 2021 return wpa_cli_cmd(ctrl, "P2P_SET", 2, argc, argv);
57faa1ce
JM
2022}
2023
2024
2025static int wpa_cli_cmd_p2p_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
2026{
2027 return wpa_ctrl_command(ctrl, "P2P_FLUSH");
2028}
2029
2030
59eba7a2
JM
2031static int wpa_cli_cmd_p2p_cancel(struct wpa_ctrl *ctrl, int argc,
2032 char *argv[])
2033{
2034 return wpa_ctrl_command(ctrl, "P2P_CANCEL");
2035}
2036
2037
9d562b79
SS
2038static int wpa_cli_cmd_p2p_unauthorize(struct wpa_ctrl *ctrl, int argc,
2039 char *argv[])
2040{
87c7ba84 2041 return wpa_cli_cmd(ctrl, "P2P_UNAUTHORIZE", 1, argc, argv);
9d562b79
SS
2042}
2043
2044
57faa1ce
JM
2045static int wpa_cli_cmd_p2p_presence_req(struct wpa_ctrl *ctrl, int argc,
2046 char *argv[])
2047{
57faa1ce
JM
2048 if (argc != 0 && argc != 2 && argc != 4) {
2049 printf("Invalid P2P_PRESENCE_REQ command: needs two arguments "
2050 "(preferred duration, interval; in microsecods).\n"
2051 "Optional second pair can be used to provide "
2052 "acceptable values.\n");
2053 return -1;
2054 }
2055
87c7ba84 2056 return wpa_cli_cmd(ctrl, "P2P_PRESENCE_REQ", 0, argc, argv);
57faa1ce
JM
2057}
2058
2059
2060static int wpa_cli_cmd_p2p_ext_listen(struct wpa_ctrl *ctrl, int argc,
2061 char *argv[])
2062{
57faa1ce
JM
2063 if (argc != 0 && argc != 2) {
2064 printf("Invalid P2P_EXT_LISTEN command: needs two arguments "
2065 "(availability period, availability interval; in "
2066 "millisecods).\n"
2067 "Extended Listen Timing can be cancelled with this "
2068 "command when used without parameters.\n");
2069 return -1;
2070 }
2071
87c7ba84 2072 return wpa_cli_cmd(ctrl, "P2P_EXT_LISTEN", 0, argc, argv);
57faa1ce
JM
2073}
2074
2075#endif /* CONFIG_P2P */
2076
9675ce35
JM
2077#ifdef CONFIG_WIFI_DISPLAY
2078
2079static int wpa_cli_cmd_wfd_subelem_set(struct wpa_ctrl *ctrl, int argc,
2080 char *argv[])
2081{
2082 char cmd[100];
2083 int res;
2084
2085 if (argc != 1 && argc != 2) {
2086 printf("Invalid WFD_SUBELEM_SET command: needs one or two "
2087 "arguments (subelem, hexdump)\n");
2088 return -1;
2089 }
2090
2091 res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_SET %s %s",
2092 argv[0], argc > 1 ? argv[1] : "");
2093 if (res < 0 || (size_t) res >= sizeof(cmd))
2094 return -1;
2095 cmd[sizeof(cmd) - 1] = '\0';
2096 return wpa_ctrl_command(ctrl, cmd);
2097}
2098
2099
2100static int wpa_cli_cmd_wfd_subelem_get(struct wpa_ctrl *ctrl, int argc,
2101 char *argv[])
2102{
2103 char cmd[100];
2104 int res;
2105
2106 if (argc != 1) {
2107 printf("Invalid WFD_SUBELEM_GET command: needs one "
2108 "argument (subelem)\n");
2109 return -1;
2110 }
2111
2112 res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_GET %s",
2113 argv[0]);
2114 if (res < 0 || (size_t) res >= sizeof(cmd))
2115 return -1;
2116 cmd[sizeof(cmd) - 1] = '\0';
2117 return wpa_ctrl_command(ctrl, cmd);
2118}
2119#endif /* CONFIG_WIFI_DISPLAY */
2120
57faa1ce 2121
afc064fe
JM
2122#ifdef CONFIG_INTERWORKING
2123static int wpa_cli_cmd_fetch_anqp(struct wpa_ctrl *ctrl, int argc,
2124 char *argv[])
2125{
2126 return wpa_ctrl_command(ctrl, "FETCH_ANQP");
2127}
2128
2129
2130static int wpa_cli_cmd_stop_fetch_anqp(struct wpa_ctrl *ctrl, int argc,
2131 char *argv[])
2132{
2133 return wpa_ctrl_command(ctrl, "STOP_FETCH_ANQP");
2134}
2135
2136
b02fe7ff
JM
2137static int wpa_cli_cmd_interworking_select(struct wpa_ctrl *ctrl, int argc,
2138 char *argv[])
2139{
87c7ba84 2140 return wpa_cli_cmd(ctrl, "INTERWORKING_SELECT", 0, argc, argv);
b02fe7ff
JM
2141}
2142
2143
2144static int wpa_cli_cmd_interworking_connect(struct wpa_ctrl *ctrl, int argc,
2145 char *argv[])
2146{
87c7ba84 2147 return wpa_cli_cmd(ctrl, "INTERWORKING_CONNECT", 1, argc, argv);
b02fe7ff
JM
2148}
2149
2150
afc064fe
JM
2151static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
2152{
87c7ba84 2153 return wpa_cli_cmd(ctrl, "ANQP_GET", 2, argc, argv);
afc064fe 2154}
b1f12296
JM
2155
2156
2157static int wpa_cli_cmd_gas_request(struct wpa_ctrl *ctrl, int argc,
2158 char *argv[])
2159{
2160 return wpa_cli_cmd(ctrl, "GAS_REQUEST", 2, argc, argv);
2161}
2162
2163
2164static int wpa_cli_cmd_gas_response_get(struct wpa_ctrl *ctrl, int argc,
2165 char *argv[])
2166{
2167 return wpa_cli_cmd(ctrl, "GAS_RESPONSE_GET", 2, argc, argv);
2168}
afc064fe
JM
2169#endif /* CONFIG_INTERWORKING */
2170
2171
a8918e86
JK
2172#ifdef CONFIG_HS20
2173
2174static int wpa_cli_cmd_hs20_anqp_get(struct wpa_ctrl *ctrl, int argc,
2175 char *argv[])
2176{
87c7ba84 2177 return wpa_cli_cmd(ctrl, "HS20_ANQP_GET", 2, argc, argv);
a8918e86
JK
2178}
2179
2180
2181static int wpa_cli_cmd_get_nai_home_realm_list(struct wpa_ctrl *ctrl, int argc,
2182 char *argv[])
2183{
2184 char cmd[512];
a8918e86
JK
2185
2186 if (argc == 0) {
2187 printf("Command needs one or two arguments (dst mac addr and "
2188 "optional home realm)\n");
2189 return -1;
2190 }
2191
87c7ba84
JM
2192 if (write_cmd(cmd, sizeof(cmd), "HS20_GET_NAI_HOME_REALM_LIST",
2193 argc, argv) < 0)
a8918e86 2194 return -1;
a8918e86
JK
2195
2196 return wpa_ctrl_command(ctrl, cmd);
2197}
2198
2199#endif /* CONFIG_HS20 */
2200
2201
0d0a8ca1
AC
2202static int wpa_cli_cmd_sta_autoconnect(struct wpa_ctrl *ctrl, int argc,
2203 char *argv[])
2204{
87c7ba84 2205 return wpa_cli_cmd(ctrl, "STA_AUTOCONNECT", 1, argc, argv);
0d0a8ca1
AC
2206}
2207
2208
281ff0aa
GP
2209static int wpa_cli_cmd_tdls_discover(struct wpa_ctrl *ctrl, int argc,
2210 char *argv[])
2211{
87c7ba84 2212 return wpa_cli_cmd(ctrl, "TDLS_DISCOVER", 1, argc, argv);
281ff0aa
GP
2213}
2214
2215
2216static int wpa_cli_cmd_tdls_setup(struct wpa_ctrl *ctrl, int argc,
2217 char *argv[])
2218{
87c7ba84 2219 return wpa_cli_cmd(ctrl, "TDLS_SETUP", 1, argc, argv);
281ff0aa
GP
2220}
2221
2222
2223static int wpa_cli_cmd_tdls_teardown(struct wpa_ctrl *ctrl, int argc,
2224 char *argv[])
2225{
87c7ba84 2226 return wpa_cli_cmd(ctrl, "TDLS_TEARDOWN", 1, argc, argv);
281ff0aa
GP
2227}
2228
2229
60b24b0d
DS
2230static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc,
2231 char *argv[])
2232{
2233 return wpa_ctrl_command(ctrl, "SIGNAL_POLL");
2234}
2235
2236
dc7785f8
YZ
2237static int wpa_cli_cmd_pktcnt_poll(struct wpa_ctrl *ctrl, int argc,
2238 char *argv[])
2239{
2240 return wpa_ctrl_command(ctrl, "PKTCNT_POLL");
2241}
2242
2243
9482426e
JM
2244static int wpa_cli_cmd_reauthenticate(struct wpa_ctrl *ctrl, int argc,
2245 char *argv[])
2246{
2247 return wpa_ctrl_command(ctrl, "REAUTHENTICATE");
2248}
2249
2250
2bdd8342
TB
2251#ifdef CONFIG_AUTOSCAN
2252
2253static int wpa_cli_cmd_autoscan(struct wpa_ctrl *ctrl, int argc, char *argv[])
2254{
2bdd8342
TB
2255 if (argc == 0)
2256 return wpa_ctrl_command(ctrl, "AUTOSCAN ");
2257
87c7ba84 2258 return wpa_cli_cmd(ctrl, "AUTOSCAN", 0, argc, argv);
2bdd8342
TB
2259}
2260
2261#endif /* CONFIG_AUTOSCAN */
2262
2263
e9199e31
JM
2264#ifdef CONFIG_WNM
2265
2266static int wpa_cli_cmd_wnm_sleep(struct wpa_ctrl *ctrl, int argc, char *argv[])
2267{
2268 return wpa_cli_cmd(ctrl, "WNM_SLEEP", 0, argc, argv);
2269}
2270
2271#endif /* CONFIG_WNM */
2272
2273
27b80b5b
JM
2274static int wpa_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
2275{
2276 if (argc == 0)
2277 return -1;
2278 return wpa_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]);
2279}
2280
2281
40fd868c
ER
2282enum wpa_cli_cmd_flags {
2283 cli_cmd_flag_none = 0x00,
2284 cli_cmd_flag_sensitive = 0x01
2285};
2286
6fc6879b
JM
2287struct wpa_cli_cmd {
2288 const char *cmd;
2289 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
b49039bd 2290 char ** (*completion)(const char *str, int pos);
40fd868c 2291 enum wpa_cli_cmd_flags flags;
dfa141b1 2292 const char *usage;
6fc6879b
JM
2293};
2294
2295static struct wpa_cli_cmd wpa_cli_commands[] = {
b49039bd 2296 { "status", wpa_cli_cmd_status, NULL,
dfa141b1
ER
2297 cli_cmd_flag_none,
2298 "[verbose] = get current WPA/EAPOL/EAP status" },
b49039bd 2299 { "ifname", wpa_cli_cmd_ifname, NULL,
0eed2a8d
JD
2300 cli_cmd_flag_none,
2301 "= get current interface name" },
b49039bd 2302 { "ping", wpa_cli_cmd_ping, NULL,
dfa141b1
ER
2303 cli_cmd_flag_none,
2304 "= pings wpa_supplicant" },
b49039bd 2305 { "relog", wpa_cli_cmd_relog, NULL,
ac6912b5
BG
2306 cli_cmd_flag_none,
2307 "= re-open log-file (allow rolling logs)" },
b49039bd 2308 { "note", wpa_cli_cmd_note, NULL,
77895cd9
JM
2309 cli_cmd_flag_none,
2310 "<text> = add a note to wpa_supplicant debug log" },
b49039bd 2311 { "mib", wpa_cli_cmd_mib, NULL,
dfa141b1
ER
2312 cli_cmd_flag_none,
2313 "= get MIB variables (dot1x, dot11)" },
2af4d404 2314 { "help", wpa_cli_cmd_help, wpa_cli_complete_help,
dfa141b1 2315 cli_cmd_flag_none,
2af4d404 2316 "[command] = show usage help" },
b49039bd 2317 { "interface", wpa_cli_cmd_interface, NULL,
dfa141b1
ER
2318 cli_cmd_flag_none,
2319 "[ifname] = show interfaces/select interface" },
b49039bd 2320 { "level", wpa_cli_cmd_level, NULL,
dfa141b1
ER
2321 cli_cmd_flag_none,
2322 "<debug level> = change debug level" },
b49039bd 2323 { "license", wpa_cli_cmd_license, NULL,
dfa141b1
ER
2324 cli_cmd_flag_none,
2325 "= show full wpa_cli license" },
b49039bd 2326 { "quit", wpa_cli_cmd_quit, NULL,
dfa141b1
ER
2327 cli_cmd_flag_none,
2328 "= exit wpa_cli" },
b49039bd 2329 { "set", wpa_cli_cmd_set, NULL,
dfa141b1
ER
2330 cli_cmd_flag_none,
2331 "= set variables (shows list of variables when run without "
2332 "arguments)" },
b49039bd 2333 { "get", wpa_cli_cmd_get, NULL,
acec8d32
JM
2334 cli_cmd_flag_none,
2335 "<name> = get information" },
b49039bd 2336 { "logon", wpa_cli_cmd_logon, NULL,
dfa141b1
ER
2337 cli_cmd_flag_none,
2338 "= IEEE 802.1X EAPOL state machine logon" },
b49039bd 2339 { "logoff", wpa_cli_cmd_logoff, NULL,
dfa141b1
ER
2340 cli_cmd_flag_none,
2341 "= IEEE 802.1X EAPOL state machine logoff" },
b49039bd 2342 { "pmksa", wpa_cli_cmd_pmksa, NULL,
dfa141b1
ER
2343 cli_cmd_flag_none,
2344 "= show PMKSA cache" },
b49039bd 2345 { "reassociate", wpa_cli_cmd_reassociate, NULL,
dfa141b1
ER
2346 cli_cmd_flag_none,
2347 "= force reassociation" },
b49039bd 2348 { "preauthenticate", wpa_cli_cmd_preauthenticate, wpa_cli_complete_bss,
dfa141b1
ER
2349 cli_cmd_flag_none,
2350 "<BSSID> = force preauthentication" },
b49039bd 2351 { "identity", wpa_cli_cmd_identity, NULL,
dfa141b1
ER
2352 cli_cmd_flag_none,
2353 "<network id> <identity> = configure identity for an SSID" },
b49039bd 2354 { "password", wpa_cli_cmd_password, NULL,
dfa141b1
ER
2355 cli_cmd_flag_sensitive,
2356 "<network id> <password> = configure password for an SSID" },
b49039bd 2357 { "new_password", wpa_cli_cmd_new_password, NULL,
dfa141b1
ER
2358 cli_cmd_flag_sensitive,
2359 "<network id> <password> = change password for an SSID" },
b49039bd 2360 { "pin", wpa_cli_cmd_pin, NULL,
dfa141b1
ER
2361 cli_cmd_flag_sensitive,
2362 "<network id> <pin> = configure pin for an SSID" },
b49039bd 2363 { "otp", wpa_cli_cmd_otp, NULL,
dfa141b1
ER
2364 cli_cmd_flag_sensitive,
2365 "<network id> <password> = configure one-time-password for an SSID"
2366 },
b49039bd 2367 { "passphrase", wpa_cli_cmd_passphrase, NULL,
dfa141b1
ER
2368 cli_cmd_flag_sensitive,
2369 "<network id> <passphrase> = configure private key passphrase\n"
2370 " for an SSID" },
b49039bd 2371 { "bssid", wpa_cli_cmd_bssid, NULL,
dfa141b1
ER
2372 cli_cmd_flag_none,
2373 "<network id> <BSSID> = set preferred BSSID for an SSID" },
b49039bd 2374 { "blacklist", wpa_cli_cmd_blacklist, wpa_cli_complete_bss,
9aa10e2b
DS
2375 cli_cmd_flag_none,
2376 "<BSSID> = add a BSSID to the blacklist\n"
2377 "blacklist clear = clear the blacklist\n"
2378 "blacklist = display the blacklist" },
b49039bd 2379 { "log_level", wpa_cli_cmd_log_level, NULL,
0597a5b5
DS
2380 cli_cmd_flag_none,
2381 "<level> [<timestamp>] = update the log level/timestamp\n"
2382 "log_level = display the current log level and log options" },
b49039bd 2383 { "list_networks", wpa_cli_cmd_list_networks, NULL,
dfa141b1
ER
2384 cli_cmd_flag_none,
2385 "= list configured networks" },
b49039bd 2386 { "select_network", wpa_cli_cmd_select_network, NULL,
dfa141b1
ER
2387 cli_cmd_flag_none,
2388 "<network id> = select a network (disable others)" },
b49039bd 2389 { "enable_network", wpa_cli_cmd_enable_network, NULL,
dfa141b1
ER
2390 cli_cmd_flag_none,
2391 "<network id> = enable a network" },
b49039bd 2392 { "disable_network", wpa_cli_cmd_disable_network, NULL,
dfa141b1
ER
2393 cli_cmd_flag_none,
2394 "<network id> = disable a network" },
b49039bd 2395 { "add_network", wpa_cli_cmd_add_network, NULL,
dfa141b1
ER
2396 cli_cmd_flag_none,
2397 "= add a network" },
b49039bd 2398 { "remove_network", wpa_cli_cmd_remove_network, NULL,
dfa141b1
ER
2399 cli_cmd_flag_none,
2400 "<network id> = remove a network" },
b49039bd 2401 { "set_network", wpa_cli_cmd_set_network, NULL,
dfa141b1
ER
2402 cli_cmd_flag_sensitive,
2403 "<network id> <variable> <value> = set network variables (shows\n"
2404 " list of variables when run without arguments)" },
b49039bd 2405 { "get_network", wpa_cli_cmd_get_network, NULL,
dfa141b1
ER
2406 cli_cmd_flag_none,
2407 "<network id> <variable> = get network variables" },
b49039bd 2408 { "list_creds", wpa_cli_cmd_list_creds, NULL,
d94c9ee6
JM
2409 cli_cmd_flag_none,
2410 "= list configured credentials" },
b49039bd 2411 { "add_cred", wpa_cli_cmd_add_cred, NULL,
d94c9ee6
JM
2412 cli_cmd_flag_none,
2413 "= add a credential" },
b49039bd 2414 { "remove_cred", wpa_cli_cmd_remove_cred, NULL,
d94c9ee6
JM
2415 cli_cmd_flag_none,
2416 "<cred id> = remove a credential" },
b49039bd 2417 { "set_cred", wpa_cli_cmd_set_cred, NULL,
d94c9ee6
JM
2418 cli_cmd_flag_sensitive,
2419 "<cred id> <variable> <value> = set credential variables" },
b49039bd 2420 { "save_config", wpa_cli_cmd_save_config, NULL,
dfa141b1
ER
2421 cli_cmd_flag_none,
2422 "= save the current configuration" },
b49039bd 2423 { "disconnect", wpa_cli_cmd_disconnect, NULL,
dfa141b1
ER
2424 cli_cmd_flag_none,
2425 "= disconnect and wait for reassociate/reconnect command before\n"
2426 " connecting" },
b49039bd 2427 { "reconnect", wpa_cli_cmd_reconnect, NULL,
dfa141b1
ER
2428 cli_cmd_flag_none,
2429 "= like reassociate, but only takes effect if already disconnected"
2430 },
b49039bd 2431 { "scan", wpa_cli_cmd_scan, NULL,
dfa141b1
ER
2432 cli_cmd_flag_none,
2433 "= request new BSS scan" },
b49039bd 2434 { "scan_results", wpa_cli_cmd_scan_results, NULL,
dfa141b1
ER
2435 cli_cmd_flag_none,
2436 "= get latest scan results" },
b49039bd 2437 { "bss", wpa_cli_cmd_bss, wpa_cli_complete_bss,
dfa141b1
ER
2438 cli_cmd_flag_none,
2439 "<<idx> | <bssid>> = get detailed scan result info" },
b49039bd 2440 { "get_capability", wpa_cli_cmd_get_capability, NULL,
dfa141b1 2441 cli_cmd_flag_none,
35aa088a
DS
2442 "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels> "
2443 "= get capabilies" },
b49039bd 2444 { "reconfigure", wpa_cli_cmd_reconfigure, NULL,
dfa141b1
ER
2445 cli_cmd_flag_none,
2446 "= force wpa_supplicant to re-read its configuration file" },
b49039bd 2447 { "terminate", wpa_cli_cmd_terminate, NULL,
dfa141b1
ER
2448 cli_cmd_flag_none,
2449 "= terminate wpa_supplicant" },
b49039bd 2450 { "interface_add", wpa_cli_cmd_interface_add, NULL,
dfa141b1
ER
2451 cli_cmd_flag_none,
2452 "<ifname> <confname> <driver> <ctrl_interface> <driver_param>\n"
2453 " <bridge_name> = adds new interface, all parameters but <ifname>\n"
2454 " are optional" },
b49039bd 2455 { "interface_remove", wpa_cli_cmd_interface_remove, NULL,
dfa141b1
ER
2456 cli_cmd_flag_none,
2457 "<ifname> = removes the interface" },
b49039bd 2458 { "interface_list", wpa_cli_cmd_interface_list, NULL,
dfa141b1
ER
2459 cli_cmd_flag_none,
2460 "= list available interfaces" },
b49039bd 2461 { "ap_scan", wpa_cli_cmd_ap_scan, NULL,
dfa141b1
ER
2462 cli_cmd_flag_none,
2463 "<value> = set ap_scan parameter" },
b49039bd 2464 { "scan_interval", wpa_cli_cmd_scan_interval, NULL,
67b9bd08
DS
2465 cli_cmd_flag_none,
2466 "<value> = set scan_interval parameter (in seconds)" },
b49039bd 2467 { "bss_expire_age", wpa_cli_cmd_bss_expire_age, NULL,
78633c37
SL
2468 cli_cmd_flag_none,
2469 "<value> = set BSS expiration age parameter" },
b49039bd 2470 { "bss_expire_count", wpa_cli_cmd_bss_expire_count, NULL,
78633c37
SL
2471 cli_cmd_flag_none,
2472 "<value> = set BSS expiration scan count parameter" },
b49039bd 2473 { "bss_flush", wpa_cli_cmd_bss_flush, NULL,
39ee845f
DS
2474 cli_cmd_flag_none,
2475 "<value> = set BSS flush age (0 by default)" },
b49039bd 2476 { "stkstart", wpa_cli_cmd_stkstart, NULL,
dfa141b1
ER
2477 cli_cmd_flag_none,
2478 "<addr> = request STK negotiation with <addr>" },
b49039bd 2479 { "ft_ds", wpa_cli_cmd_ft_ds, wpa_cli_complete_bss,
dfa141b1
ER
2480 cli_cmd_flag_none,
2481 "<addr> = request over-the-DS FT with <addr>" },
b49039bd 2482 { "wps_pbc", wpa_cli_cmd_wps_pbc, wpa_cli_complete_bss,
dfa141b1
ER
2483 cli_cmd_flag_none,
2484 "[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" },
b49039bd 2485 { "wps_pin", wpa_cli_cmd_wps_pin, wpa_cli_complete_bss,
dfa141b1
ER
2486 cli_cmd_flag_sensitive,
2487 "<BSSID> [PIN] = start WPS PIN method (returns PIN, if not "
2488 "hardcoded)" },
b49039bd 2489 { "wps_check_pin", wpa_cli_cmd_wps_check_pin, NULL,
3981cb3c
JM
2490 cli_cmd_flag_sensitive,
2491 "<PIN> = verify PIN checksum" },
b49039bd 2492 { "wps_cancel", wpa_cli_cmd_wps_cancel, NULL, cli_cmd_flag_none,
2f9929ff 2493 "Cancels the pending WPS operation" },
71892384 2494#ifdef CONFIG_WPS_NFC
b49039bd 2495 { "wps_nfc", wpa_cli_cmd_wps_nfc, wpa_cli_complete_bss,
3f2c8ba6
JM
2496 cli_cmd_flag_none,
2497 "[BSSID] = start Wi-Fi Protected Setup: NFC" },
bbf41865
JM
2498 { "wps_nfc_config_token", wpa_cli_cmd_wps_nfc_config_token, NULL,
2499 cli_cmd_flag_none,
2500 "<WPS|NDEF> = build configuration token" },
b49039bd 2501 { "wps_nfc_token", wpa_cli_cmd_wps_nfc_token, NULL,
3f2c8ba6
JM
2502 cli_cmd_flag_none,
2503 "<WPS|NDEF> = create password token" },
b49039bd 2504 { "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read, NULL,
d7645d23
JM
2505 cli_cmd_flag_sensitive,
2506 "<hexdump of payload> = report read NFC tag with WPS data" },
e65552dd
JM
2507 { "nfc_get_handover_req", wpa_cli_cmd_nfc_get_handover_req, NULL,
2508 cli_cmd_flag_none,
2509 "<NDEF> <WPS> = create NFC handover request" },
2510 { "nfc_get_handover_sel", wpa_cli_cmd_nfc_get_handover_sel, NULL,
2511 cli_cmd_flag_none,
2512 "<NDEF> <WPS> = create NFC handover select" },
2513 { "nfc_rx_handover_req", wpa_cli_cmd_nfc_rx_handover_req, NULL,
2514 cli_cmd_flag_none,
2515 "<hexdump of payload> = report received NFC handover request" },
2516 { "nfc_rx_handover_sel", wpa_cli_cmd_nfc_rx_handover_sel, NULL,
2517 cli_cmd_flag_none,
2518 "<hexdump of payload> = report received NFC handover select" },
e4758827
JM
2519 { "nfc_report_handover", wpa_cli_cmd_nfc_report_handover, NULL,
2520 cli_cmd_flag_none,
2521 "<role> <type> <hexdump of req> <hexdump of sel> = report completed "
2522 "NFC handover" },
71892384 2523#endif /* CONFIG_WPS_NFC */
b49039bd 2524 { "wps_reg", wpa_cli_cmd_wps_reg, wpa_cli_complete_bss,
dfa141b1
ER
2525 cli_cmd_flag_sensitive,
2526 "<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
b49039bd 2527 { "wps_ap_pin", wpa_cli_cmd_wps_ap_pin, NULL,
70d84f11
JM
2528 cli_cmd_flag_sensitive,
2529 "[params..] = enable/disable AP PIN" },
b49039bd 2530 { "wps_er_start", wpa_cli_cmd_wps_er_start, NULL,
e9bcfebf 2531 cli_cmd_flag_none,
08486685 2532 "[IP address] = start Wi-Fi Protected Setup External Registrar" },
b49039bd 2533 { "wps_er_stop", wpa_cli_cmd_wps_er_stop, NULL,
e9bcfebf
JM
2534 cli_cmd_flag_none,
2535 "= stop Wi-Fi Protected Setup External Registrar" },
b49039bd 2536 { "wps_er_pin", wpa_cli_cmd_wps_er_pin, NULL,
72df2f5f
JM
2537 cli_cmd_flag_sensitive,
2538 "<UUID> <PIN> = add an Enrollee PIN to External Registrar" },
b49039bd 2539 { "wps_er_pbc", wpa_cli_cmd_wps_er_pbc, NULL,
564cd7fa
JM
2540 cli_cmd_flag_none,
2541 "<UUID> = accept an Enrollee PBC using External Registrar" },
b49039bd 2542 { "wps_er_learn", wpa_cli_cmd_wps_er_learn, NULL,
e64dcfd5
JM
2543 cli_cmd_flag_sensitive,
2544 "<UUID> <PIN> = learn AP configuration" },
b49039bd 2545 { "wps_er_set_config", wpa_cli_cmd_wps_er_set_config, NULL,
ef10f473
JM
2546 cli_cmd_flag_none,
2547 "<UUID> <network id> = set AP configuration for enrolling" },
b49039bd 2548 { "wps_er_config", wpa_cli_cmd_wps_er_config, NULL,
7d6640a6
JM
2549 cli_cmd_flag_sensitive,
2550 "<UUID> <PIN> <SSID> <auth> <encr> <key> = configure AP" },
1cea09a9 2551#ifdef CONFIG_WPS_NFC
b49039bd 2552 { "wps_er_nfc_config_token", wpa_cli_cmd_wps_er_nfc_config_token, NULL,
1cea09a9
JM
2553 cli_cmd_flag_none,
2554 "<WPS/NDEF> <UUID> = build NFC configuration token" },
2555#endif /* CONFIG_WPS_NFC */
b49039bd 2556 { "ibss_rsn", wpa_cli_cmd_ibss_rsn, NULL,
11ef8d35
JM
2557 cli_cmd_flag_none,
2558 "<addr> = request RSN authentication with <addr> in IBSS" },
e653b622 2559#ifdef CONFIG_AP
b49039bd 2560 { "sta", wpa_cli_cmd_sta, NULL,
e653b622
JM
2561 cli_cmd_flag_none,
2562 "<addr> = get information about an associated station (AP)" },
b49039bd 2563 { "all_sta", wpa_cli_cmd_all_sta, NULL,
e653b622
JM
2564 cli_cmd_flag_none,
2565 "= get information about all associated stations (AP)" },
b49039bd 2566 { "deauthenticate", wpa_cli_cmd_deauthenticate, NULL,
e60b2951
JJ
2567 cli_cmd_flag_none,
2568 "<addr> = deauthenticate a station" },
b49039bd 2569 { "disassociate", wpa_cli_cmd_disassociate, NULL,
e60b2951
JJ
2570 cli_cmd_flag_none,
2571 "<addr> = disassociate a station" },
e653b622 2572#endif /* CONFIG_AP */
b49039bd 2573 { "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none,
207ef3fb 2574 "= notification of suspend/hibernate" },
b49039bd 2575 { "resume", wpa_cli_cmd_resume, NULL, cli_cmd_flag_none,
207ef3fb 2576 "= notification of resume/thaw" },
b49039bd 2577 { "drop_sa", wpa_cli_cmd_drop_sa, NULL, cli_cmd_flag_none,
32d5295f 2578 "= drop SA without deauth/disassoc (test command)" },
b49039bd 2579 { "roam", wpa_cli_cmd_roam, wpa_cli_complete_bss,
86d4f806
JM
2580 cli_cmd_flag_none,
2581 "<addr> = roam to the specified BSS" },
57faa1ce 2582#ifdef CONFIG_P2P
01335e2c
JM
2583 { "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find,
2584 cli_cmd_flag_none,
57faa1ce 2585 "[timeout] [type=*] = find P2P Devices for up-to timeout seconds" },
b49039bd 2586 { "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, NULL, cli_cmd_flag_none,
57faa1ce 2587 "= stop P2P Devices search" },
b49039bd
JM
2588 { "p2p_connect", wpa_cli_cmd_p2p_connect, wpa_cli_complete_p2p_connect,
2589 cli_cmd_flag_none,
e2308e4b 2590 "<addr> <\"pbc\"|PIN> [ht40] = connect to a P2P Device" },
b49039bd 2591 { "p2p_listen", wpa_cli_cmd_p2p_listen, NULL, cli_cmd_flag_none,
57faa1ce 2592 "[timeout] = listen for P2P Devices for up-to timeout seconds" },
b49039bd
JM
2593 { "p2p_group_remove", wpa_cli_cmd_p2p_group_remove,
2594 wpa_cli_complete_p2p_group_remove, cli_cmd_flag_none,
4d2ea6a6 2595 "<ifname> = remove P2P group interface (terminate group if GO)" },
b49039bd 2596 { "p2p_group_add", wpa_cli_cmd_p2p_group_add, NULL, cli_cmd_flag_none,
7aeac985 2597 "[ht40] = add a new P2P group (local end as GO)" },
b49039bd
JM
2598 { "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc,
2599 wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
57faa1ce 2600 "<addr> <method> = request provisioning discovery" },
b49039bd 2601 { "p2p_get_passphrase", wpa_cli_cmd_p2p_get_passphrase, NULL,
57faa1ce
JM
2602 cli_cmd_flag_none,
2603 "= get the passphrase for a group (GO only)" },
2604 { "p2p_serv_disc_req", wpa_cli_cmd_p2p_serv_disc_req,
b49039bd 2605 wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
57faa1ce
JM
2606 "<addr> <TLVs> = schedule service discovery request" },
2607 { "p2p_serv_disc_cancel_req", wpa_cli_cmd_p2p_serv_disc_cancel_req,
b49039bd 2608 NULL, cli_cmd_flag_none,
57faa1ce 2609 "<id> = cancel pending service discovery request" },
b49039bd 2610 { "p2p_serv_disc_resp", wpa_cli_cmd_p2p_serv_disc_resp, NULL,
57faa1ce
JM
2611 cli_cmd_flag_none,
2612 "<freq> <addr> <dialog token> <TLVs> = service discovery response" },
b49039bd 2613 { "p2p_service_update", wpa_cli_cmd_p2p_service_update, NULL,
57faa1ce
JM
2614 cli_cmd_flag_none,
2615 "= indicate change in local services" },
b49039bd 2616 { "p2p_serv_disc_external", wpa_cli_cmd_p2p_serv_disc_external, NULL,
57faa1ce
JM
2617 cli_cmd_flag_none,
2618 "<external> = set external processing of service discovery" },
b49039bd 2619 { "p2p_service_flush", wpa_cli_cmd_p2p_service_flush, NULL,
57faa1ce
JM
2620 cli_cmd_flag_none,
2621 "= remove all stored service entries" },
b49039bd 2622 { "p2p_service_add", wpa_cli_cmd_p2p_service_add, NULL,
57faa1ce
JM
2623 cli_cmd_flag_none,
2624 "<bonjour|upnp> <query|version> <response|service> = add a local "
2625 "service" },
b49039bd 2626 { "p2p_service_del", wpa_cli_cmd_p2p_service_del, NULL,
57faa1ce
JM
2627 cli_cmd_flag_none,
2628 "<bonjour|upnp> <query|version> [|service] = remove a local "
2629 "service" },
b49039bd 2630 { "p2p_reject", wpa_cli_cmd_p2p_reject, wpa_cli_complete_p2p_peer,
57faa1ce
JM
2631 cli_cmd_flag_none,
2632 "<addr> = reject connection attempts from a specific peer" },
b49039bd 2633 { "p2p_invite", wpa_cli_cmd_p2p_invite, NULL,
57faa1ce
JM
2634 cli_cmd_flag_none,
2635 "<cmd> [peer=addr] = invite peer" },
b49039bd 2636 { "p2p_peers", wpa_cli_cmd_p2p_peers, NULL, cli_cmd_flag_none,
57faa1ce
JM
2637 "[discovered] = list known (optionally, only fully discovered) P2P "
2638 "peers" },
b49039bd
JM
2639 { "p2p_peer", wpa_cli_cmd_p2p_peer, wpa_cli_complete_p2p_peer,
2640 cli_cmd_flag_none,
57faa1ce 2641 "<address> = show information about known P2P peer" },
b49039bd 2642 { "p2p_set", wpa_cli_cmd_p2p_set, NULL, cli_cmd_flag_none,
57faa1ce 2643 "<field> <value> = set a P2P parameter" },
b49039bd 2644 { "p2p_flush", wpa_cli_cmd_p2p_flush, NULL, cli_cmd_flag_none,
57faa1ce 2645 "= flush P2P state" },
b49039bd 2646 { "p2p_cancel", wpa_cli_cmd_p2p_cancel, NULL, cli_cmd_flag_none,
59eba7a2 2647 "= cancel P2P group formation" },
b49039bd
JM
2648 { "p2p_unauthorize", wpa_cli_cmd_p2p_unauthorize,
2649 wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
9d562b79 2650 "<address> = unauthorize a peer" },
b49039bd
JM
2651 { "p2p_presence_req", wpa_cli_cmd_p2p_presence_req, NULL,
2652 cli_cmd_flag_none,
57faa1ce
JM
2653 "[<duration> <interval>] [<duration> <interval>] = request GO "
2654 "presence" },
b49039bd
JM
2655 { "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, NULL,
2656 cli_cmd_flag_none,
57faa1ce
JM
2657 "[<period> <interval>] = set extended listen timing" },
2658#endif /* CONFIG_P2P */
9675ce35
JM
2659#ifdef CONFIG_WIFI_DISPLAY
2660 { "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL,
2661 cli_cmd_flag_none,
2662 "<subelem> [contents] = set Wi-Fi Display subelement" },
2663 { "wfd_subelem_get", wpa_cli_cmd_wfd_subelem_get, NULL,
2664 cli_cmd_flag_none,
2665 "<subelem> = get Wi-Fi Display subelement" },
2666#endif /* CONFIG_WIFI_DISPLAY */
afc064fe 2667#ifdef CONFIG_INTERWORKING
b49039bd 2668 { "fetch_anqp", wpa_cli_cmd_fetch_anqp, NULL, cli_cmd_flag_none,
afc064fe 2669 "= fetch ANQP information for all APs" },
b49039bd
JM
2670 { "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, NULL,
2671 cli_cmd_flag_none,
afc064fe 2672 "= stop fetch_anqp operation" },
b49039bd 2673 { "interworking_select", wpa_cli_cmd_interworking_select, NULL,
b02fe7ff
JM
2674 cli_cmd_flag_none,
2675 "[auto] = perform Interworking network selection" },
2676 { "interworking_connect", wpa_cli_cmd_interworking_connect,
b49039bd 2677 wpa_cli_complete_bss, cli_cmd_flag_none,
b02fe7ff 2678 "<BSSID> = connect using Interworking credentials" },
b49039bd
JM
2679 { "anqp_get", wpa_cli_cmd_anqp_get, wpa_cli_complete_bss,
2680 cli_cmd_flag_none,
afc064fe 2681 "<addr> <info id>[,<info id>]... = request ANQP information" },
b1f12296
JM
2682 { "gas_request", wpa_cli_cmd_gas_request, wpa_cli_complete_bss,
2683 cli_cmd_flag_none,
2684 "<addr> <AdvProtoID> [QueryReq] = GAS request" },
2685 { "gas_response_get", wpa_cli_cmd_gas_response_get,
2686 wpa_cli_complete_bss, cli_cmd_flag_none,
2687 "<addr> <dialog token> [start,len] = Fetch last GAS response" },
afc064fe 2688#endif /* CONFIG_INTERWORKING */
a8918e86 2689#ifdef CONFIG_HS20
b49039bd
JM
2690 { "hs20_anqp_get", wpa_cli_cmd_hs20_anqp_get, wpa_cli_complete_bss,
2691 cli_cmd_flag_none,
a8918e86
JK
2692 "<addr> <subtype>[,<subtype>]... = request HS 2.0 ANQP information"
2693 },
2694 { "nai_home_realm_list", wpa_cli_cmd_get_nai_home_realm_list,
b49039bd 2695 wpa_cli_complete_bss, cli_cmd_flag_none,
a8918e86
JK
2696 "<addr> <home realm> = get HS20 nai home realm list" },
2697#endif /* CONFIG_HS20 */
b49039bd
JM
2698 { "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, NULL,
2699 cli_cmd_flag_none,
0d0a8ca1 2700 "<0/1> = disable/enable automatic reconnection" },
b49039bd 2701 { "tdls_discover", wpa_cli_cmd_tdls_discover, NULL,
281ff0aa
GP
2702 cli_cmd_flag_none,
2703 "<addr> = request TDLS discovery with <addr>" },
b49039bd 2704 { "tdls_setup", wpa_cli_cmd_tdls_setup, NULL,
281ff0aa
GP
2705 cli_cmd_flag_none,
2706 "<addr> = request TDLS setup with <addr>" },
b49039bd 2707 { "tdls_teardown", wpa_cli_cmd_tdls_teardown, NULL,
281ff0aa
GP
2708 cli_cmd_flag_none,
2709 "<addr> = tear down TDLS with <addr>" },
b49039bd 2710 { "signal_poll", wpa_cli_cmd_signal_poll, NULL,
60b24b0d
DS
2711 cli_cmd_flag_none,
2712 "= get signal parameters" },
dc7785f8
YZ
2713 { "pktcnt_poll", wpa_cli_cmd_pktcnt_poll, NULL,
2714 cli_cmd_flag_none,
2715 "= get TX/RX packet counters" },
b49039bd
JM
2716 { "reauthenticate", wpa_cli_cmd_reauthenticate, NULL,
2717 cli_cmd_flag_none,
9482426e 2718 "= trigger IEEE 802.1X/EAPOL reauthentication" },
2bdd8342 2719#ifdef CONFIG_AUTOSCAN
b49039bd 2720 { "autoscan", wpa_cli_cmd_autoscan, NULL, cli_cmd_flag_none,
2bdd8342
TB
2721 "[params] = Set or unset (if none) autoscan parameters" },
2722#endif /* CONFIG_AUTOSCAN */
e9199e31
JM
2723#ifdef CONFIG_WNM
2724 { "wnm_sleep", wpa_cli_cmd_wnm_sleep, NULL, cli_cmd_flag_none,
2725 "<enter/exit> [interval=#] = enter/exit WNM-Sleep mode" },
2726#endif /* CONFIG_WNM */
b49039bd 2727 { "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive,
27b80b5b 2728 "<params..> = Sent unprocessed command" },
b49039bd 2729 { NULL, NULL, NULL, cli_cmd_flag_none, NULL }
6fc6879b
JM
2730};
2731
2732
dfa141b1
ER
2733/*
2734 * Prints command usage, lines are padded with the specified string.
2735 */
2736static void print_cmd_help(struct wpa_cli_cmd *cmd, const char *pad)
2737{
2738 char c;
2739 size_t n;
2740
2741 printf("%s%s ", pad, cmd->cmd);
2742 for (n = 0; (c = cmd->usage[n]); n++) {
2743 printf("%c", c);
2744 if (c == '\n')
2745 printf("%s", pad);
2746 }
2747 printf("\n");
2748}
2749
2750
2af4d404 2751static void print_help(const char *cmd)
dfa141b1
ER
2752{
2753 int n;
2754 printf("commands:\n");
2af4d404
JM
2755 for (n = 0; wpa_cli_commands[n].cmd; n++) {
2756 if (cmd == NULL || str_starts(wpa_cli_commands[n].cmd, cmd))
2757 print_cmd_help(&wpa_cli_commands[n], " ");
2758 }
dfa141b1
ER
2759}
2760
2761
e8ecb5fb 2762static int wpa_cli_edit_filter_history_cb(void *ctx, const char *cmd)
40fd868c
ER
2763{
2764 const char *c, *delim;
2765 int n;
2766 size_t len;
2767
2768 delim = os_strchr(cmd, ' ');
2769 if (delim)
2770 len = delim - cmd;
2771 else
2772 len = os_strlen(cmd);
2773
2774 for (n = 0; (c = wpa_cli_commands[n].cmd); n++) {
2775 if (os_strncasecmp(cmd, c, len) == 0 && len == os_strlen(c))
2776 return (wpa_cli_commands[n].flags &
2777 cli_cmd_flag_sensitive);
2778 }
2779 return 0;
2780}
e8ecb5fb
JM
2781
2782
2783static char ** wpa_list_cmd_list(void)
2784{
2785 char **res;
2786 int i, count;
2787
2788 count = sizeof(wpa_cli_commands) / sizeof(wpa_cli_commands[0]);
f9884c09 2789 res = os_calloc(count, sizeof(char *));
e8ecb5fb
JM
2790 if (res == NULL)
2791 return NULL;
2792
2793 for (i = 0; wpa_cli_commands[i].cmd; i++) {
2794 res[i] = os_strdup(wpa_cli_commands[i].cmd);
2795 if (res[i] == NULL)
2796 break;
2797 }
2798
2799 return res;
2800}
2801
2802
2803static char ** wpa_cli_cmd_completion(const char *cmd, const char *str,
2804 int pos)
2805{
2806 int i;
2807
2808 for (i = 0; wpa_cli_commands[i].cmd; i++) {
2809 if (os_strcasecmp(wpa_cli_commands[i].cmd, cmd) == 0) {
e4f6873c
JM
2810 if (wpa_cli_commands[i].completion)
2811 return wpa_cli_commands[i].completion(str,
2812 pos);
e8ecb5fb
JM
2813 edit_clear_line();
2814 printf("\r%s\n", wpa_cli_commands[i].usage);
2815 edit_redraw();
2816 break;
2817 }
2818 }
2819
2820 return NULL;
2821}
2822
2823
2824static char ** wpa_cli_edit_completion_cb(void *ctx, const char *str, int pos)
2825{
2826 char **res;
2827 const char *end;
2828 char *cmd;
2829
2830 end = os_strchr(str, ' ');
2831 if (end == NULL || str + pos < end)
2832 return wpa_list_cmd_list();
2833
2834 cmd = os_malloc(pos + 1);
2835 if (cmd == NULL)
2836 return NULL;
2837 os_memcpy(cmd, str, pos);
2838 cmd[end - str] = '\0';
2839 res = wpa_cli_cmd_completion(cmd, str, pos);
2840 os_free(cmd);
2841 return res;
2842}
40fd868c
ER
2843
2844
6fc6879b
JM
2845static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
2846{
2847 struct wpa_cli_cmd *cmd, *match = NULL;
2848 int count;
2849 int ret = 0;
2850
2851 count = 0;
2852 cmd = wpa_cli_commands;
2853 while (cmd->cmd) {
2854 if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0)
2855 {
2856 match = cmd;
2857 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
2858 /* we have an exact match */
2859 count = 1;
2860 break;
2861 }
2862 count++;
2863 }
2864 cmd++;
2865 }
2866
2867 if (count > 1) {
2868 printf("Ambiguous command '%s'; possible commands:", argv[0]);
2869 cmd = wpa_cli_commands;
2870 while (cmd->cmd) {
2871 if (os_strncasecmp(cmd->cmd, argv[0],
2872 os_strlen(argv[0])) == 0) {
2873 printf(" %s", cmd->cmd);
2874 }
2875 cmd++;
2876 }
2877 printf("\n");
2878 ret = 1;
2879 } else if (count == 0) {
2880 printf("Unknown command '%s'\n", argv[0]);
2881 ret = 1;
2882 } else {
2883 ret = match->handler(ctrl, argc - 1, &argv[1]);
2884 }
2885
2886 return ret;
2887}
2888
2889
2890static int str_match(const char *a, const char *b)
2891{
2892 return os_strncmp(a, b, os_strlen(b)) == 0;
2893}
2894
2895
2896static int wpa_cli_exec(const char *program, const char *arg1,
2897 const char *arg2)
2898{
2899 char *cmd;
2900 size_t len;
2901 int res;
308a4ec8 2902 int ret = 0;
6fc6879b
JM
2903
2904 len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
2905 cmd = os_malloc(len);
2906 if (cmd == NULL)
2907 return -1;
2908 res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
2909 if (res < 0 || (size_t) res >= len) {
2910 os_free(cmd);
2911 return -1;
2912 }
2913 cmd[len - 1] = '\0';
2914#ifndef _WIN32_WCE
308a4ec8
JM
2915 if (system(cmd) < 0)
2916 ret = -1;
6fc6879b
JM
2917#endif /* _WIN32_WCE */
2918 os_free(cmd);
2919
308a4ec8 2920 return ret;
6fc6879b
JM
2921}
2922
2923
2924static void wpa_cli_action_process(const char *msg)
2925{
2926 const char *pos;
2927 char *copy = NULL, *id, *pos2;
2928
2929 pos = msg;
2930 if (*pos == '<') {
2931 /* skip priority */
2932 pos = os_strchr(pos, '>');
2933 if (pos)
2934 pos++;
2935 else
2936 pos = msg;
2937 }
2938
2939 if (str_match(pos, WPA_EVENT_CONNECTED)) {
2940 int new_id = -1;
2941 os_unsetenv("WPA_ID");
2942 os_unsetenv("WPA_ID_STR");
2943 os_unsetenv("WPA_CTRL_DIR");
2944
2945 pos = os_strstr(pos, "[id=");
2946 if (pos)
2947 copy = os_strdup(pos + 4);
2948
2949 if (copy) {
2950 pos2 = id = copy;
2951 while (*pos2 && *pos2 != ' ')
2952 pos2++;
2953 *pos2++ = '\0';
2954 new_id = atoi(id);
2955 os_setenv("WPA_ID", id, 1);
2956 while (*pos2 && *pos2 != '=')
2957 pos2++;
2958 if (*pos2 == '=')
2959 pos2++;
2960 id = pos2;
2961 while (*pos2 && *pos2 != ']')
2962 pos2++;
2963 *pos2 = '\0';
2964 os_setenv("WPA_ID_STR", id, 1);
2965 os_free(copy);
2966 }
2967
2968 os_setenv("WPA_CTRL_DIR", ctrl_iface_dir, 1);
2969
2970 if (!wpa_cli_connected || new_id != wpa_cli_last_id) {
2971 wpa_cli_connected = 1;
2972 wpa_cli_last_id = new_id;
2973 wpa_cli_exec(action_file, ctrl_ifname, "CONNECTED");
2974 }
2975 } else if (str_match(pos, WPA_EVENT_DISCONNECTED)) {
2976 if (wpa_cli_connected) {
2977 wpa_cli_connected = 0;
2978 wpa_cli_exec(action_file, ctrl_ifname, "DISCONNECTED");
2979 }
42f0101b
JM
2980 } else if (str_match(pos, P2P_EVENT_GROUP_STARTED)) {
2981 wpa_cli_exec(action_file, ctrl_ifname, pos);
2982 } else if (str_match(pos, P2P_EVENT_GROUP_REMOVED)) {
2983 wpa_cli_exec(action_file, ctrl_ifname, pos);
72044390
JM
2984 } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) {
2985 wpa_cli_exec(action_file, ctrl_ifname, pos);
2986 } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) {
2987 wpa_cli_exec(action_file, ctrl_ifname, pos);
e670738a
DS
2988 } else if (str_match(pos, P2P_EVENT_GO_NEG_FAILURE)) {
2989 wpa_cli_exec(action_file, ctrl_ifname, pos);
876103dc
AC
2990 } else if (str_match(pos, WPS_EVENT_SUCCESS)) {
2991 wpa_cli_exec(action_file, ctrl_ifname, pos);
2992 } else if (str_match(pos, WPS_EVENT_FAIL)) {
2993 wpa_cli_exec(action_file, ctrl_ifname, pos);
653c4893
NKG
2994 } else if (str_match(pos, AP_STA_CONNECTED)) {
2995 wpa_cli_exec(action_file, ctrl_ifname, pos);
2996 } else if (str_match(pos, AP_STA_DISCONNECTED)) {
2997 wpa_cli_exec(action_file, ctrl_ifname, pos);
6fc6879b
JM
2998 } else if (str_match(pos, WPA_EVENT_TERMINATING)) {
2999 printf("wpa_supplicant is terminating - stop monitoring\n");
3000 wpa_cli_quit = 1;
3001 }
3002}
3003
3004
3005#ifndef CONFIG_ANSI_C_EXTRA
3006static void wpa_cli_action_cb(char *msg, size_t len)
3007{
3008 wpa_cli_action_process(msg);
3009}
3010#endif /* CONFIG_ANSI_C_EXTRA */
3011
3012
3013static void wpa_cli_reconnect(void)
3014{
3015 wpa_cli_close_connection();
059d3a90
JM
3016 if (wpa_cli_open_connection(ctrl_ifname, 1) < 0)
3017 return;
3018
3019 if (interactive) {
3020 edit_clear_line();
3021 printf("\rConnection to wpa_supplicant re-established\n");
3022 edit_redraw();
3023 }
6fc6879b
JM
3024}
3025
3026
a624f20b
JM
3027static void cli_event(const char *str)
3028{
3029 const char *start, *s;
3030
3031 start = os_strchr(str, '>');
3032 if (start == NULL)
3033 return;
3034
3035 start++;
3036
3037 if (str_starts(start, WPA_EVENT_BSS_ADDED)) {
3038 s = os_strchr(start, ' ');
3039 if (s == NULL)
3040 return;
3041 s = os_strchr(s + 1, ' ');
3042 if (s == NULL)
3043 return;
3044 cli_txt_list_add(&bsses, s + 1);
3045 return;
3046 }
3047
3048 if (str_starts(start, WPA_EVENT_BSS_REMOVED)) {
3049 s = os_strchr(start, ' ');
3050 if (s == NULL)
3051 return;
3052 s = os_strchr(s + 1, ' ');
3053 if (s == NULL)
3054 return;
3055 cli_txt_list_del_addr(&bsses, s + 1);
3056 return;
3057 }
3058
3059#ifdef CONFIG_P2P
3060 if (str_starts(start, P2P_EVENT_DEVICE_FOUND)) {
3061 s = os_strstr(start, " p2p_dev_addr=");
3062 if (s == NULL)
3063 return;
3064 cli_txt_list_add_addr(&p2p_peers, s + 14);
3065 return;
3066 }
3067
3068 if (str_starts(start, P2P_EVENT_DEVICE_LOST)) {
3069 s = os_strstr(start, " p2p_dev_addr=");
3070 if (s == NULL)
3071 return;
3072 cli_txt_list_del_addr(&p2p_peers, s + 14);
3073 return;
3074 }
76788542
JM
3075
3076 if (str_starts(start, P2P_EVENT_GROUP_STARTED)) {
3077 s = os_strchr(start, ' ');
3078 if (s == NULL)
3079 return;
3080 cli_txt_list_add_word(&p2p_groups, s + 1);
3081 return;
3082 }
3083
3084 if (str_starts(start, P2P_EVENT_GROUP_REMOVED)) {
3085 s = os_strchr(start, ' ');
3086 if (s == NULL)
3087 return;
3088 cli_txt_list_del_word(&p2p_groups, s + 1);
3089 return;
3090 }
a624f20b
JM
3091#endif /* CONFIG_P2P */
3092}
3093
3094
059d3a90
JM
3095static int check_terminating(const char *msg)
3096{
3097 const char *pos = msg;
3098
3099 if (*pos == '<') {
3100 /* skip priority */
3101 pos = os_strchr(pos, '>');
3102 if (pos)
3103 pos++;
3104 else
3105 pos = msg;
3106 }
3107
3108 if (str_match(pos, WPA_EVENT_TERMINATING) && ctrl_conn) {
3109 edit_clear_line();
3110 printf("\rConnection to wpa_supplicant lost - trying to "
3111 "reconnect\n");
3112 edit_redraw();
3113 wpa_cli_attached = 0;
3114 wpa_cli_close_connection();
3115 return 1;
3116 }
3117
3118 return 0;
3119}
3120
3121
cd101567 3122static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor)
6fc6879b 3123{
6fc6879b
JM
3124 if (ctrl_conn == NULL) {
3125 wpa_cli_reconnect();
3126 return;
3127 }
3128 while (wpa_ctrl_pending(ctrl) > 0) {
3129 char buf[256];
3130 size_t len = sizeof(buf) - 1;
3131 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
3132 buf[len] = '\0';
3133 if (action_monitor)
3134 wpa_cli_action_process(buf);
3135 else {
a624f20b 3136 cli_event(buf);
f3f0f648 3137 if (wpa_cli_show_event(buf)) {
82a855bd 3138 edit_clear_line();
cd101567 3139 printf("\r%s\n", buf);
bdc45634 3140 edit_redraw();
f3f0f648 3141 }
059d3a90
JM
3142
3143 if (interactive && check_terminating(buf) > 0)
3144 return;
6fc6879b
JM
3145 }
3146 } else {
3147 printf("Could not read pending message.\n");
3148 break;
3149 }
3150 }
3151
3152 if (wpa_ctrl_pending(ctrl) < 0) {
3153 printf("Connection to wpa_supplicant lost - trying to "
3154 "reconnect\n");
3155 wpa_cli_reconnect();
3156 }
3157}
3158
6f1c6549
JM
3159#define max_args 10
3160
3161static int tokenize_cmd(char *cmd, char *argv[])
3162{
3163 char *pos;
3164 int argc = 0;
3165
3166 pos = cmd;
3167 for (;;) {
3168 while (*pos == ' ')
3169 pos++;
3170 if (*pos == '\0')
3171 break;
3172 argv[argc] = pos;
3173 argc++;
3174 if (argc == max_args)
3175 break;
3176 if (*pos == '"') {
3177 char *pos2 = os_strrchr(pos, '"');
3178 if (pos2)
3179 pos = pos2 + 1;
3180 }
3181 while (*pos != '\0' && *pos != ' ')
3182 pos++;
3183 if (*pos == ' ')
3184 *pos++ = '\0';
3185 }
3186
3187 return argc;
3188}
3189
3190
cd101567
JM
3191static void wpa_cli_ping(void *eloop_ctx, void *timeout_ctx)
3192{
3193 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
3194 printf("Connection to wpa_supplicant lost - trying to "
3195 "reconnect\n");
3196 wpa_cli_close_connection();
3197 }
3198 if (!ctrl_conn)
3199 wpa_cli_reconnect();
3200 eloop_register_timeout(ping_interval, 0, wpa_cli_ping, NULL, NULL);
3201}
3202
3203
cd101567
JM
3204static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx)
3205{
3206 wpa_cli_recv_pending(mon_conn, 0);
3207}
3208
3209
82a855bd 3210static void wpa_cli_edit_cmd_cb(void *ctx, char *cmd)
aee680e8
JM
3211{
3212 char *argv[max_args];
3213 int argc;
82a855bd 3214 argc = tokenize_cmd(cmd, argv);
aee680e8
JM
3215 if (argc)
3216 wpa_request(ctrl_conn, argc, argv);
aee680e8
JM
3217}
3218
3219
82a855bd 3220static void wpa_cli_edit_eof_cb(void *ctx)
6f1c6549 3221{
82a855bd 3222 eloop_terminate();
cd101567
JM
3223}
3224
3225
4be9f275
JM
3226static int warning_displayed = 0;
3227static char *hfile = NULL;
3228static int edit_started = 0;
aee680e8 3229
4be9f275
JM
3230static void start_edit(void)
3231{
3232 char *home;
db3a0322
JM
3233 char *ps = NULL;
3234
3235#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
3236 ps = wpa_ctrl_get_remote_ifname(ctrl_conn);
3237#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
cd101567 3238
8953e968
JM
3239 home = getenv("HOME");
3240 if (home) {
3241 const char *fname = ".wpa_cli_history";
3242 int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
3243 hfile = os_malloc(hfile_len);
3244 if (hfile)
3245 os_snprintf(hfile, hfile_len, "%s/%s", home, fname);
3246 }
3247
4be9f275 3248 if (edit_init(wpa_cli_edit_cmd_cb, wpa_cli_edit_eof_cb,
db3a0322 3249 wpa_cli_edit_completion_cb, NULL, hfile, ps) < 0) {
4be9f275
JM
3250 eloop_terminate();
3251 return;
3252 }
3253
3254 edit_started = 1;
cd101567 3255 eloop_register_timeout(ping_interval, 0, wpa_cli_ping, NULL, NULL);
4be9f275
JM
3256}
3257
3258
3259static void try_connection(void *eloop_ctx, void *timeout_ctx)
3260{
8e897ae3
JM
3261 if (ctrl_ifname == NULL)
3262 ctrl_ifname = wpa_cli_get_default_ifname();
3263
4be9f275
JM
3264 if (!wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
3265 if (!warning_displayed) {
3266 printf("Could not connect to wpa_supplicant: "
3267 "%s - re-trying\n", ctrl_ifname);
3268 warning_displayed = 1;
3269 }
3270 eloop_register_timeout(1, 0, try_connection, NULL, NULL);
3271 return;
3272 }
3273
3274 if (warning_displayed)
3275 printf("Connection established.\n");
3276
3277 start_edit();
3278}
3279
cd101567 3280
4be9f275
JM
3281static void wpa_cli_interactive(void)
3282{
3283 printf("\nInteractive mode\n\n");
3284
3285 eloop_register_timeout(0, 0, try_connection, NULL, NULL);
cd101567 3286 eloop_run();
4be9f275 3287 eloop_cancel_timeout(try_connection, NULL, NULL);
cd101567 3288
a624f20b 3289 cli_txt_list_flush(&p2p_peers);
76788542 3290 cli_txt_list_flush(&p2p_groups);
a624f20b 3291 cli_txt_list_flush(&bsses);
4be9f275
JM
3292 if (edit_started)
3293 edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
8953e968 3294 os_free(hfile);
cd101567
JM
3295 eloop_cancel_timeout(wpa_cli_ping, NULL, NULL);
3296 wpa_cli_close_connection();
6f1c6549
JM
3297}
3298
6fc6879b
JM
3299
3300static void wpa_cli_action(struct wpa_ctrl *ctrl)
3301{
3302#ifdef CONFIG_ANSI_C_EXTRA
3303 /* TODO: ANSI C version(?) */
3304 printf("Action processing not supported in ANSI C build.\n");
3305#else /* CONFIG_ANSI_C_EXTRA */
3306 fd_set rfds;
3307 int fd, res;
3308 struct timeval tv;
3309 char buf[256]; /* note: large enough to fit in unsolicited messages */
3310 size_t len;
3311
3312 fd = wpa_ctrl_get_fd(ctrl);
3313
3314 while (!wpa_cli_quit) {
3315 FD_ZERO(&rfds);
3316 FD_SET(fd, &rfds);
1cc84c1c 3317 tv.tv_sec = ping_interval;
6fc6879b
JM
3318 tv.tv_usec = 0;
3319 res = select(fd + 1, &rfds, NULL, NULL, &tv);
3320 if (res < 0 && errno != EINTR) {
3321 perror("select");
3322 break;
3323 }
3324
3325 if (FD_ISSET(fd, &rfds))
cd101567 3326 wpa_cli_recv_pending(ctrl, 1);
6fc6879b
JM
3327 else {
3328 /* verify that connection is still working */
3329 len = sizeof(buf) - 1;
3330 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
3331 wpa_cli_action_cb) < 0 ||
3332 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
3333 printf("wpa_supplicant did not reply to PING "
3334 "command - exiting\n");
3335 break;
3336 }
3337 }
3338 }
3339#endif /* CONFIG_ANSI_C_EXTRA */
3340}
3341
3342
3343static void wpa_cli_cleanup(void)
3344{
3345 wpa_cli_close_connection();
3346 if (pid_file)
3347 os_daemonize_terminate(pid_file);
3348
3349 os_program_deinit();
3350}
3351
4be9f275
JM
3352
3353static void wpa_cli_terminate(int sig, void *ctx)
6fc6879b 3354{
4be9f275 3355 eloop_terminate();
6fc6879b
JM
3356}
3357
3358
6fc6879b
JM
3359static char * wpa_cli_get_default_ifname(void)
3360{
3361 char *ifname = NULL;
3362
3363#ifdef CONFIG_CTRL_IFACE_UNIX
3364 struct dirent *dent;
3365 DIR *dir = opendir(ctrl_iface_dir);
b1001e4c
DS
3366 if (!dir) {
3367#ifdef ANDROID
3368 char ifprop[PROPERTY_VALUE_MAX];
3369 if (property_get("wifi.interface", ifprop, NULL) != 0) {
3370 ifname = os_strdup(ifprop);
3371 printf("Using interface '%s'\n", ifname);
3372 return ifname;
3373 }
3374#endif /* ANDROID */
6fc6879b 3375 return NULL;
b1001e4c 3376 }
6fc6879b
JM
3377 while ((dent = readdir(dir))) {
3378#ifdef _DIRENT_HAVE_D_TYPE
3379 /*
3380 * Skip the file if it is not a socket. Also accept
3381 * DT_UNKNOWN (0) in case the C library or underlying
3382 * file system does not support d_type.
3383 */
3384 if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
3385 continue;
3386#endif /* _DIRENT_HAVE_D_TYPE */
3387 if (os_strcmp(dent->d_name, ".") == 0 ||
3388 os_strcmp(dent->d_name, "..") == 0)
3389 continue;
3390 printf("Selected interface '%s'\n", dent->d_name);
3391 ifname = os_strdup(dent->d_name);
3392 break;
3393 }
3394 closedir(dir);
3395#endif /* CONFIG_CTRL_IFACE_UNIX */
3396
3397#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
3398 char buf[2048], *pos;
3399 size_t len;
3400 struct wpa_ctrl *ctrl;
3401 int ret;
3402
3403 ctrl = wpa_ctrl_open(NULL);
3404 if (ctrl == NULL)
3405 return NULL;
3406
3407 len = sizeof(buf) - 1;
3408 ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL);
3409 if (ret >= 0) {
3410 buf[len] = '\0';
3411 pos = os_strchr(buf, '\n');
3412 if (pos)
3413 *pos = '\0';
3414 ifname = os_strdup(buf);
3415 }
3416 wpa_ctrl_close(ctrl);
3417#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
3418
3419 return ifname;
3420}
3421
3422
3423int main(int argc, char *argv[])
3424{
6fc6879b
JM
3425 int c;
3426 int daemonize = 0;
3427 int ret = 0;
3428 const char *global = NULL;
3429
3430 if (os_program_init())
3431 return -1;
3432
3433 for (;;) {
1cc84c1c 3434 c = getopt(argc, argv, "a:Bg:G:hi:p:P:v");
6fc6879b
JM
3435 if (c < 0)
3436 break;
3437 switch (c) {
3438 case 'a':
3439 action_file = optarg;
3440 break;
3441 case 'B':
3442 daemonize = 1;
3443 break;
3444 case 'g':
3445 global = optarg;
3446 break;
1cc84c1c
JM
3447 case 'G':
3448 ping_interval = atoi(optarg);
3449 break;
6fc6879b
JM
3450 case 'h':
3451 usage();
3452 return 0;
3453 case 'v':
3454 printf("%s\n", wpa_cli_version);
3455 return 0;
3456 case 'i':
3457 os_free(ctrl_ifname);
3458 ctrl_ifname = os_strdup(optarg);
3459 break;
3460 case 'p':
3461 ctrl_iface_dir = optarg;
3462 break;
3463 case 'P':
3464 pid_file = optarg;
3465 break;
3466 default:
3467 usage();
3468 return -1;
3469 }
3470 }
3471
3472 interactive = (argc == optind) && (action_file == NULL);
3473
3474 if (interactive)
3475 printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license);
3476
cd101567
JM
3477 if (eloop_init())
3478 return -1;
3479
6fc6879b
JM
3480 if (global) {
3481#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
3482 ctrl_conn = wpa_ctrl_open(NULL);
3483#else /* CONFIG_CTRL_IFACE_NAMED_PIPE */
3484 ctrl_conn = wpa_ctrl_open(global);
3485#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
3486 if (ctrl_conn == NULL) {
5a49459e
BG
3487 fprintf(stderr, "Failed to connect to wpa_supplicant "
3488 "global interface: %s error: %s\n",
3489 global, strerror(errno));
6fc6879b
JM
3490 return -1;
3491 }
3492 }
3493
4be9f275 3494 eloop_register_signal_terminate(wpa_cli_terminate, NULL);
6fc6879b 3495
4a3ade4e
JM
3496 if (ctrl_ifname == NULL)
3497 ctrl_ifname = wpa_cli_get_default_ifname();
3498
3499 if (interactive) {
4be9f275 3500 wpa_cli_interactive();
4a3ade4e
JM
3501 } else {
3502 if (!global &&
3503 wpa_cli_open_connection(ctrl_ifname, 0) < 0) {
5a49459e
BG
3504 fprintf(stderr, "Failed to connect to non-global "
3505 "ctrl_ifname: %s error: %s\n",
3506 ctrl_ifname, strerror(errno));
4a3ade4e
JM
3507 return -1;
3508 }
3509
3510 if (action_file) {
3511 if (wpa_ctrl_attach(ctrl_conn) == 0) {
3512 wpa_cli_attached = 1;
3513 } else {
3514 printf("Warning: Failed to attach to "
3515 "wpa_supplicant.\n");
6fc6879b 3516 return -1;
4a3ade4e 3517 }
6fc6879b 3518 }
6fc6879b 3519
4be9f275
JM
3520 if (daemonize && os_daemonize(pid_file))
3521 return -1;
6fc6879b 3522
4be9f275
JM
3523 if (action_file)
3524 wpa_cli_action(ctrl_conn);
3525 else
3526 ret = wpa_request(ctrl_conn, argc - optind,
3527 &argv[optind]);
3528 }
6fc6879b
JM
3529
3530 os_free(ctrl_ifname);
cd101567 3531 eloop_destroy();
6fc6879b
JM
3532 wpa_cli_cleanup();
3533
3534 return ret;
3535}
3536
3537#else /* CONFIG_CTRL_IFACE */
3538int main(int argc, char *argv[])
3539{
3540 printf("CONFIG_CTRL_IFACE not defined - wpa_cli disabled\n");
3541 return -1;
3542}
3543#endif /* CONFIG_CTRL_IFACE */