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