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