]> git.ipfire.org Git - thirdparty/hostap.git/blame - wpa_supplicant/wpa_cli.c
wpa_cli: Use .wpa_cli_history under Android
[thirdparty/hostap.git] / wpa_supplicant / wpa_cli.c
CommitLineData
6fc6879b
JM
1/*
2 * WPA Supplicant - command line interface for wpa_supplicant daemon
937403b5 3 * Copyright (c) 2004-2015, 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"
937403b5 31"Copyright (c) 2004-2015, 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;
02a3e5c0 73static int wpa_cli_connected = -1;
6fc6879b 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;
13b11ba7 84static char *ifname_prefix = NULL;
6fc6879b 85
a624f20b
JM
86struct cli_txt_entry {
87 struct dl_list list;
88 char *txt;
89};
90
91static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */
92static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */
76788542 93static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */
37620493 94static DEFINE_DL_LIST(ifnames); /* struct cli_txt_entry */
a624f20b 95
6fc6879b 96
2af4d404 97static void print_help(const char *cmd);
cd101567 98static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx);
d62aaa7d 99static void wpa_cli_close_connection(void);
8e897ae3 100static char * wpa_cli_get_default_ifname(void);
2af4d404 101static char ** wpa_list_cmd_list(void);
dfa141b1
ER
102
103
6fc6879b
JM
104static void usage(void)
105{
106 printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] "
107 "[-a<action file>] \\\n"
1cc84c1c
JM
108 " [-P<pid file>] [-g<global ctrl>] [-G<ping interval>] "
109 "[command..]\n"
6fc6879b
JM
110 " -h = help (show this usage text)\n"
111 " -v = shown version information\n"
112 " -a = run in daemon mode executing the action file based on "
113 "events from\n"
114 " wpa_supplicant\n"
115 " -B = run a daemon in the background\n"
c5c5817c 116 " default path: " CONFIG_CTRL_IFACE_DIR "\n"
dfa141b1 117 " default interface: first interface found in socket path\n");
2af4d404 118 print_help(NULL);
6fc6879b
JM
119}
120
121
a624f20b
JM
122static void cli_txt_list_free(struct cli_txt_entry *e)
123{
124 dl_list_del(&e->list);
125 os_free(e->txt);
126 os_free(e);
127}
128
129
130static void cli_txt_list_flush(struct dl_list *list)
131{
132 struct cli_txt_entry *e;
133 while ((e = dl_list_first(list, struct cli_txt_entry, list)))
134 cli_txt_list_free(e);
135}
136
137
138static struct cli_txt_entry * cli_txt_list_get(struct dl_list *txt_list,
139 const char *txt)
140{
141 struct cli_txt_entry *e;
142 dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
143 if (os_strcmp(e->txt, txt) == 0)
144 return e;
145 }
146 return NULL;
147}
148
149
150static void cli_txt_list_del(struct dl_list *txt_list, const char *txt)
151{
152 struct cli_txt_entry *e;
153 e = cli_txt_list_get(txt_list, txt);
154 if (e)
155 cli_txt_list_free(e);
156}
157
158
159static void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt)
160{
161 u8 addr[ETH_ALEN];
162 char buf[18];
163 if (hwaddr_aton(txt, addr) < 0)
164 return;
165 os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
166 cli_txt_list_del(txt_list, buf);
167}
168
169
4877e1fc 170#ifdef CONFIG_P2P
76788542
JM
171static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt)
172{
173 const char *end;
174 char *buf;
175 end = os_strchr(txt, ' ');
176 if (end == NULL)
177 end = txt + os_strlen(txt);
5e24dc8a 178 buf = dup_binstr(txt, end - txt);
76788542
JM
179 if (buf == NULL)
180 return;
76788542
JM
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);
5e24dc8a 226 buf = dup_binstr(txt, end - txt);
76788542
JM
227 if (buf == NULL)
228 return -1;
76788542
JM
229 ret = cli_txt_list_add(txt_list, buf);
230 os_free(buf);
231 return ret;
232}
4877e1fc 233#endif /* CONFIG_P2P */
76788542
JM
234
235
a624f20b
JM
236static char ** cli_txt_list_array(struct dl_list *txt_list)
237{
238 unsigned int i, count = dl_list_len(txt_list);
239 char **res;
240 struct cli_txt_entry *e;
241
f9884c09 242 res = os_calloc(count + 1, sizeof(char *));
a624f20b
JM
243 if (res == NULL)
244 return NULL;
245
246 i = 0;
247 dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
248 res[i] = os_strdup(e->txt);
249 if (res[i] == NULL)
250 break;
251 i++;
252 }
253
254 return res;
255}
256
257
258static int get_cmd_arg_num(const char *str, int pos)
259{
260 int arg = 0, i;
261
262 for (i = 0; i <= pos; i++) {
263 if (str[i] != ' ') {
264 arg++;
265 while (i <= pos && str[i] != ' ')
266 i++;
267 }
268 }
269
270 if (arg > 0)
271 arg--;
272 return arg;
273}
274
275
f3f0f648
JM
276static int str_starts(const char *src, const char *match)
277{
278 return os_strncmp(src, match, os_strlen(match)) == 0;
279}
280
281
282static int wpa_cli_show_event(const char *event)
283{
284 const char *start;
285
286 start = os_strchr(event, '>');
287 if (start == NULL)
288 return 1;
289
290 start++;
291 /*
292 * Skip BSS added/removed events since they can be relatively frequent
293 * and are likely of not much use for an interactive user.
294 */
295 if (str_starts(start, WPA_EVENT_BSS_ADDED) ||
296 str_starts(start, WPA_EVENT_BSS_REMOVED))
297 return 0;
298
299 return 1;
300}
301
302
4a3ade4e 303static int wpa_cli_open_connection(const char *ifname, int attach)
6fc6879b
JM
304{
305#if defined(CONFIG_CTRL_IFACE_UDP) || defined(CONFIG_CTRL_IFACE_NAMED_PIPE)
306 ctrl_conn = wpa_ctrl_open(ifname);
4a3ade4e
JM
307 if (ctrl_conn == NULL)
308 return -1;
309
310 if (attach && interactive)
311 mon_conn = wpa_ctrl_open(ifname);
312 else
313 mon_conn = NULL;
6fc6879b 314#else /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
b1001e4c 315 char *cfile = NULL;
6fc6879b
JM
316 int flen, res;
317
318 if (ifname == NULL)
4a3ade4e 319 return -1;
6fc6879b 320
b1001e4c
DS
321#ifdef ANDROID
322 if (access(ctrl_iface_dir, F_OK) < 0) {
323 cfile = os_strdup(ifname);
324 if (cfile == NULL)
325 return -1;
326 }
327#endif /* ANDROID */
328
329 if (cfile == NULL) {
330 flen = os_strlen(ctrl_iface_dir) + os_strlen(ifname) + 2;
331 cfile = os_malloc(flen);
332 if (cfile == NULL)
333 return -1;
334 res = os_snprintf(cfile, flen, "%s/%s", ctrl_iface_dir,
335 ifname);
d85e1fc8 336 if (os_snprintf_error(flen, res)) {
b1001e4c
DS
337 os_free(cfile);
338 return -1;
339 }
6fc6879b
JM
340 }
341
342 ctrl_conn = wpa_ctrl_open(cfile);
4a3ade4e
JM
343 if (ctrl_conn == NULL) {
344 os_free(cfile);
345 return -1;
346 }
347
348 if (attach && interactive)
349 mon_conn = wpa_ctrl_open(cfile);
350 else
351 mon_conn = NULL;
6fc6879b 352 os_free(cfile);
6fc6879b 353#endif /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
4a3ade4e
JM
354
355 if (mon_conn) {
356 if (wpa_ctrl_attach(mon_conn) == 0) {
357 wpa_cli_attached = 1;
cd101567
JM
358 if (interactive)
359 eloop_register_read_sock(
360 wpa_ctrl_get_fd(mon_conn),
361 wpa_cli_mon_receive, NULL, NULL);
4a3ade4e
JM
362 } else {
363 printf("Warning: Failed to attach to "
364 "wpa_supplicant.\n");
d62aaa7d 365 wpa_cli_close_connection();
4a3ade4e
JM
366 return -1;
367 }
368 }
369
370 return 0;
6fc6879b
JM
371}
372
373
374static void wpa_cli_close_connection(void)
375{
376 if (ctrl_conn == NULL)
377 return;
378
379 if (wpa_cli_attached) {
4a3ade4e 380 wpa_ctrl_detach(interactive ? mon_conn : ctrl_conn);
6fc6879b
JM
381 wpa_cli_attached = 0;
382 }
383 wpa_ctrl_close(ctrl_conn);
384 ctrl_conn = NULL;
4a3ade4e 385 if (mon_conn) {
cd101567 386 eloop_unregister_read_sock(wpa_ctrl_get_fd(mon_conn));
4a3ade4e
JM
387 wpa_ctrl_close(mon_conn);
388 mon_conn = NULL;
389 }
6fc6879b
JM
390}
391
392
393static void wpa_cli_msg_cb(char *msg, size_t len)
394{
395 printf("%s\n", msg);
396}
397
398
399static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
400{
aec309c4 401 char buf[4096];
6fc6879b
JM
402 size_t len;
403 int ret;
404
405 if (ctrl_conn == NULL) {
406 printf("Not connected to wpa_supplicant - command dropped.\n");
407 return -1;
408 }
13b11ba7
JM
409 if (ifname_prefix) {
410 os_snprintf(buf, sizeof(buf), "IFNAME=%s %s",
411 ifname_prefix, cmd);
412 buf[sizeof(buf) - 1] = '\0';
413 cmd = buf;
414 }
6fc6879b
JM
415 len = sizeof(buf) - 1;
416 ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
417 wpa_cli_msg_cb);
418 if (ret == -2) {
419 printf("'%s' command timed out.\n", cmd);
420 return -2;
421 } else if (ret < 0) {
422 printf("'%s' command failed.\n", cmd);
423 return -1;
424 }
425 if (print) {
426 buf[len] = '\0';
427 printf("%s", buf);
a432bafb
JM
428 if (interactive && len > 0 && buf[len - 1] != '\n')
429 printf("\n");
6fc6879b
JM
430 }
431 return 0;
432}
433
434
435static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
436{
437 return _wpa_ctrl_command(ctrl, cmd, 1);
438}
439
440
0076869c
JM
441static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
442 char *argv[])
443{
444 int i, res;
445 char *pos, *end;
446
447 pos = buf;
448 end = buf + buflen;
449
450 res = os_snprintf(pos, end - pos, "%s", cmd);
d85e1fc8 451 if (os_snprintf_error(end - pos, res))
0076869c
JM
452 goto fail;
453 pos += res;
454
455 for (i = 0; i < argc; i++) {
456 res = os_snprintf(pos, end - pos, " %s", argv[i]);
d85e1fc8 457 if (os_snprintf_error(end - pos, res))
0076869c
JM
458 goto fail;
459 pos += res;
460 }
461
462 buf[buflen - 1] = '\0';
463 return 0;
464
465fail:
466 printf("Too long command\n");
467 return -1;
468}
469
470
471static int wpa_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd, int min_args,
472 int argc, char *argv[])
473{
28fcfb67 474 char buf[4096];
0076869c
JM
475 if (argc < min_args) {
476 printf("Invalid %s command - at least %d argument%s "
477 "required.\n", cmd, min_args,
478 min_args > 1 ? "s are" : " is");
479 return -1;
480 }
481 if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0)
482 return -1;
483 return wpa_ctrl_command(ctrl, buf);
484}
485
486
0eed2a8d
JD
487static int wpa_cli_cmd_ifname(struct wpa_ctrl *ctrl, int argc, char *argv[])
488{
489 return wpa_ctrl_command(ctrl, "IFNAME");
490}
491
492
6fc6879b
JM
493static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
494{
0bc13468
JM
495 if (argc > 0 && os_strcmp(argv[0], "verbose") == 0)
496 return wpa_ctrl_command(ctrl, "STATUS-VERBOSE");
497 if (argc > 0 && os_strcmp(argv[0], "wps") == 0)
498 return wpa_ctrl_command(ctrl, "STATUS-WPS");
a771c07d
JM
499 if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
500 return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
0bc13468 501 return wpa_ctrl_command(ctrl, "STATUS");
6fc6879b
JM
502}
503
504
505static int wpa_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
506{
507 return wpa_ctrl_command(ctrl, "PING");
508}
509
510
ac6912b5
BG
511static int wpa_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
512{
513 return wpa_ctrl_command(ctrl, "RELOG");
514}
515
516
77895cd9
JM
517static int wpa_cli_cmd_note(struct wpa_ctrl *ctrl, int argc, char *argv[])
518{
0076869c 519 return wpa_cli_cmd(ctrl, "NOTE", 1, argc, argv);
77895cd9
JM
520}
521
522
6fc6879b
JM
523static int wpa_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
524{
525 return wpa_ctrl_command(ctrl, "MIB");
526}
527
528
529static int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
530{
531 return wpa_ctrl_command(ctrl, "PMKSA");
532}
533
534
79e2b1cc
AK
535static int wpa_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc,
536 char *argv[])
537{
538 return wpa_ctrl_command(ctrl, "PMKSA_FLUSH");
539}
540
541
6fc6879b
JM
542static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
543{
2af4d404 544 print_help(argc > 0 ? argv[0] : NULL);
6fc6879b
JM
545 return 0;
546}
547
548
2af4d404
JM
549static char ** wpa_cli_complete_help(const char *str, int pos)
550{
551 int arg = get_cmd_arg_num(str, pos);
552 char **res = NULL;
553
554 switch (arg) {
555 case 1:
556 res = wpa_list_cmd_list();
557 break;
558 }
559
560 return res;
561}
562
563
6fc6879b
JM
564static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[])
565{
566 printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license);
567 return 0;
568}
569
570
571static int wpa_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
572{
573 wpa_cli_quit = 1;
cd101567
JM
574 if (interactive)
575 eloop_terminate();
6fc6879b
JM
576 return 0;
577}
578
579
6fc6879b
JM
580static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
581{
582 char cmd[256];
583 int res;
584
f1fb042c 585 if (argc == 1) {
40eac890 586 res = os_snprintf(cmd, sizeof(cmd), "SET %s ", argv[0]);
eeab4f2f 587 if (os_snprintf_error(sizeof(cmd), res)) {
f1fb042c
JM
588 printf("Too long SET command.\n");
589 return -1;
590 }
591 return wpa_ctrl_command(ctrl, cmd);
6fc6879b 592 }
f1fb042c
JM
593
594 return wpa_cli_cmd(ctrl, "SET", 2, argc, argv);
6fc6879b
JM
595}
596
597
21565872
JM
598static char ** wpa_cli_complete_set(const char *str, int pos)
599{
600 int arg = get_cmd_arg_num(str, pos);
601 const char *fields[] = {
602 /* runtime values */
603 "EAPOL::heldPeriod", "EAPOL::authPeriod", "EAPOL::startPeriod",
604 "EAPOL::maxStart", "dot11RSNAConfigPMKLifetime",
605 "dot11RSNAConfigPMKReauthThreshold", "dot11RSNAConfigSATimeout",
606 "wps_fragment_size", "wps_version_number", "ampdu",
607 "tdls_testing", "tdls_disabled", "pno", "radio_disabled",
608 "uapsd", "ps", "wifi_display", "bssid_filter", "disallow_aps",
609 "no_keep_alive",
610 /* global configuration parameters */
8ffaafae
MK
611#ifdef CONFIG_CTRL_IFACE
612 "ctrl_interface", "no_ctrl_interface", "ctrl_interface_group",
613#endif /* CONFIG_CTRL_IFACE */
614 "eapol_version", "ap_scan", "bgscan",
615#ifdef CONFIG_MESH
616 "user_mpm", "max_peer_links", "mesh_max_inactivity",
617#endif /* CONFIG_MESH */
618 "disable_scan_offload", "fast_reauth", "opensc_engine_path",
619 "pkcs11_engine_path", "pkcs11_module_path", "openssl_ciphers",
620 "pcsc_reader", "pcsc_pin", "external_sim", "driver_param",
621 "dot11RSNAConfigPMKLifetime",
21565872
JM
622 "dot11RSNAConfigPMKReauthThreshold",
623 "dot11RSNAConfigSATimeout",
8ffaafae
MK
624#ifndef CONFIG_NO_CONFIG_WRITE
625 "update_config",
626#endif /* CONFIG_NO_CONFIG_WRITE */
627 "load_dynamic_eap",
628#ifdef CONFIG_WPS
629 "uuid", "device_name", "manufacturer", "model_name",
630 "model_number", "serial_number", "device_type", "os_version",
631 "config_methods", "wps_cred_processing", "wps_vendor_ext_m1",
632#endif /* CONFIG_WPS */
633#ifdef CONFIG_P2P
634 "sec_device_type",
21565872 635 "p2p_listen_reg_class", "p2p_listen_channel",
8ffaafae
MK
636 "p2p_oper_reg_class", "p2p_oper_channel", "p2p_go_intent",
637 "p2p_ssid_postfix", "persistent_reconnect", "p2p_intra_bss",
638 "p2p_group_idle", "p2p_passphrase_len", "p2p_pref_chan",
639 "p2p_no_go_freq", "p2p_add_cli_chan",
640 "p2p_optimize_listen_chan", "p2p_go_ht40", "p2p_go_vht",
641 "p2p_disabled", "p2p_go_ctwindow", "p2p_no_group_iface",
642 "p2p_ignore_shared_freq", "ip_addr_go", "ip_addr_mask",
643 "ip_addr_start", "ip_addr_end",
644#endif /* CONFIG_P2P */
645 "country", "bss_max_count", "bss_expiration_age",
646 "bss_expiration_scan_count", "filter_ssids", "filter_rssi",
647 "max_num_sta", "disassoc_low_ack",
648#ifdef CONFIG_HS20
649 "hs20",
650#endif /* CONFIG_HS20 */
651 "interworking", "hessid", "access_network_type", "pbc_in_m1",
652 "autoscan", "wps_nfc_dev_pw_id", "wps_nfc_dh_pubkey",
653 "wps_nfc_dh_privkey", "wps_nfc_dev_pw", "ext_password_backend",
21565872 654 "p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
8ffaafae
MK
655 "sae_groups", "dtim_period", "beacon_int",
656 "ap_vendor_elements", "ignore_old_scan_res", "freq_list",
657 "scan_cur_freq", "sched_scan_interval",
658 "tdls_external_control", "osu_dir", "wowlan_triggers",
659 "p2p_search_delay", "mac_addr", "rand_addr_lifetime",
660 "preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
661 "reassoc_same_bss_optim"
21565872 662 };
e7ecab4a 663 int i, num_fields = ARRAY_SIZE(fields);
21565872
JM
664
665 if (arg == 1) {
666 char **res = os_calloc(num_fields + 1, sizeof(char *));
667 if (res == NULL)
668 return NULL;
669 for (i = 0; i < num_fields; i++) {
670 res[i] = os_strdup(fields[i]);
671 if (res[i] == NULL)
672 return res;
673 }
674 return res;
675 }
676
69aa3341
JM
677 if (arg > 1 && os_strncasecmp(str, "set bssid_filter ", 17) == 0)
678 return cli_txt_list_array(&bsses);
679
21565872
JM
680 return NULL;
681}
682
10263dc2
OO
683static int wpa_cli_cmd_dump(struct wpa_ctrl *ctrl, int argc, char *argv[])
684{
685 return wpa_ctrl_command(ctrl, "DUMP");
686}
687
21565872 688
acec8d32
JM
689static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
690{
87c7ba84 691 return wpa_cli_cmd(ctrl, "GET", 1, argc, argv);
acec8d32
JM
692}
693
694
0fd9d95f
MK
695static char ** wpa_cli_complete_get(const char *str, int pos)
696{
697 int arg = get_cmd_arg_num(str, pos);
698 const char *fields[] = {
699#ifdef CONFIG_CTRL_IFACE
700 "ctrl_interface", "ctrl_interface_group",
701#endif /* CONFIG_CTRL_IFACE */
702 "eapol_version", "ap_scan",
703#ifdef CONFIG_MESH
704 "user_mpm", "max_peer_links", "mesh_max_inactivity",
705#endif /* CONFIG_MESH */
706 "disable_scan_offload", "fast_reauth", "opensc_engine_path",
707 "pkcs11_engine_path", "pkcs11_module_path", "openssl_ciphers",
708 "pcsc_reader", "pcsc_pin", "external_sim", "driver_param",
709 "dot11RSNAConfigPMKLifetime",
710 "dot11RSNAConfigPMKReauthThreshold",
711 "dot11RSNAConfigSATimeout",
712#ifndef CONFIG_NO_CONFIG_WRITE
713 "update_config",
714#endif /* CONFIG_NO_CONFIG_WRITE */
715#ifdef CONFIG_WPS
716 "device_name", "manufacturer", "model_name", "model_number",
717 "serial_number", "config_methods", "wps_cred_processing",
718#endif /* CONFIG_WPS */
719#ifdef CONFIG_P2P
720 "p2p_listen_reg_class", "p2p_listen_channel",
721 "p2p_oper_reg_class", "p2p_oper_channel", "p2p_go_intent",
722 "p2p_ssid_postfix", "persistent_reconnect", "p2p_intra_bss",
723 "p2p_group_idle", "p2p_passphrase_len", "p2p_add_cli_chan",
724 "p2p_optimize_listen_chan", "p2p_go_ht40", "p2p_go_vht",
725 "p2p_disabled", "p2p_go_ctwindow", "p2p_no_group_iface",
726 "p2p_ignore_shared_freq", "ip_addr_go", "ip_addr_mask",
727 "ip_addr_start", "ip_addr_end",
728#endif /* CONFIG_P2P */
729 "bss_max_count", "bss_expiration_age",
730 "bss_expiration_scan_count", "filter_ssids", "filter_rssi",
731 "max_num_sta", "disassoc_low_ack",
732#ifdef CONFIG_HS20
733 "hs20",
734#endif /* CONFIG_HS20 */
735 "interworking", "access_network_type", "pbc_in_m1", "autoscan",
736 "wps_nfc_dev_pw_id", "ext_password_backend",
737 "p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
738 "dtim_period", "beacon_int", "ignore_old_scan_res",
739 "scan_cur_freq", "sched_scan_interval",
740 "tdls_external_control", "osu_dir", "wowlan_triggers",
741 "p2p_search_delay", "mac_addr", "rand_addr_lifetime",
742 "preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
743 "reassoc_same_bss_optim"
744 };
745 int i, num_fields = ARRAY_SIZE(fields);
746
747 if (arg == 1) {
748 char **res = os_calloc(num_fields + 1, sizeof(char *));
749 if (res == NULL)
750 return NULL;
751 for (i = 0; i < num_fields; i++) {
752 res[i] = os_strdup(fields[i]);
753 if (res[i] == NULL)
754 return res;
755 }
756 return res;
757 }
758
759 return NULL;
760}
761
762
6fc6879b
JM
763static int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[])
764{
765 return wpa_ctrl_command(ctrl, "LOGOFF");
766}
767
768
769static int wpa_cli_cmd_logon(struct wpa_ctrl *ctrl, int argc, char *argv[])
770{
771 return wpa_ctrl_command(ctrl, "LOGON");
772}
773
774
775static int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc,
776 char *argv[])
777{
778 return wpa_ctrl_command(ctrl, "REASSOCIATE");
779}
780
781
0f44ec8e
PQ
782static int wpa_cli_cmd_reattach(struct wpa_ctrl *ctrl, int argc, char *argv[])
783{
784 return wpa_ctrl_command(ctrl, "REATTACH");
785}
786
787
6fc6879b
JM
788static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc,
789 char *argv[])
790{
87c7ba84 791 return wpa_cli_cmd(ctrl, "PREAUTH", 1, argc, argv);
6fc6879b
JM
792}
793
794
795static int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
796{
87c7ba84 797 return wpa_cli_cmd(ctrl, "AP_SCAN", 1, argc, argv);
6fc6879b
JM
798}
799
800
67b9bd08
DS
801static int wpa_cli_cmd_scan_interval(struct wpa_ctrl *ctrl, int argc,
802 char *argv[])
803{
87c7ba84 804 return wpa_cli_cmd(ctrl, "SCAN_INTERVAL", 1, argc, argv);
67b9bd08
DS
805}
806
807
78633c37
SL
808static int wpa_cli_cmd_bss_expire_age(struct wpa_ctrl *ctrl, int argc,
809 char *argv[])
810{
87c7ba84 811 return wpa_cli_cmd(ctrl, "BSS_EXPIRE_AGE", 1, argc, argv);
78633c37
SL
812}
813
814
815static int wpa_cli_cmd_bss_expire_count(struct wpa_ctrl *ctrl, int argc,
816 char *argv[])
817{
87c7ba84 818 return wpa_cli_cmd(ctrl, "BSS_EXPIRE_COUNT", 1, argc, argv);
78633c37
SL
819}
820
821
39ee845f
DS
822static int wpa_cli_cmd_bss_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
823{
824 char cmd[256];
825 int res;
826
827 if (argc < 1)
828 res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH 0");
829 else
830 res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH %s", argv[0]);
eeab4f2f 831 if (os_snprintf_error(sizeof(cmd), res)) {
39ee845f
DS
832 printf("Too long BSS_FLUSH command.\n");
833 return -1;
834 }
835 return wpa_ctrl_command(ctrl, cmd);
836}
837
838
6fc6879b
JM
839static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc,
840 char *argv[])
841{
87c7ba84 842 return wpa_cli_cmd(ctrl, "STKSTART", 1, argc, argv);
6fc6879b
JM
843}
844
845
846static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[])
847{
87c7ba84 848 return wpa_cli_cmd(ctrl, "FT_DS", 1, argc, argv);
6fc6879b
JM
849}
850
851
fcc60db4
JM
852static int wpa_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[])
853{
87c7ba84 854 return wpa_cli_cmd(ctrl, "WPS_PBC", 0, argc, argv);
fcc60db4
JM
855}
856
857
858static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
859{
fcc60db4
JM
860 if (argc == 0) {
861 printf("Invalid WPS_PIN command: need one or two arguments:\n"
862 "- BSSID: use 'any' to select any\n"
863 "- PIN: optional, used only with devices that have no "
864 "display\n");
865 return -1;
866 }
867
87c7ba84 868 return wpa_cli_cmd(ctrl, "WPS_PIN", 1, argc, argv);
fcc60db4
JM
869}
870
871
3981cb3c
JM
872static int wpa_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
873 char *argv[])
874{
87c7ba84 875 return wpa_cli_cmd(ctrl, "WPS_CHECK_PIN", 1, argc, argv);
3981cb3c
JM
876}
877
878
2f9929ff
AC
879static int wpa_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
880 char *argv[])
881{
882 return wpa_ctrl_command(ctrl, "WPS_CANCEL");
883}
884
885
71892384 886#ifdef CONFIG_WPS_NFC
3f2c8ba6
JM
887
888static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[])
889{
87c7ba84 890 return wpa_cli_cmd(ctrl, "WPS_NFC", 0, argc, argv);
3f2c8ba6
JM
891}
892
893
bbf41865
JM
894static int wpa_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl, int argc,
895 char *argv[])
896{
897 return wpa_cli_cmd(ctrl, "WPS_NFC_CONFIG_TOKEN", 1, argc, argv);
898}
899
900
3f2c8ba6
JM
901static int wpa_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, int argc,
902 char *argv[])
903{
87c7ba84 904 return wpa_cli_cmd(ctrl, "WPS_NFC_TOKEN", 1, argc, argv);
3f2c8ba6 905}
d7645d23
JM
906
907
908static int wpa_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
909 char *argv[])
910{
911 int ret;
912 char *buf;
913 size_t buflen;
914
915 if (argc != 1) {
916 printf("Invalid 'wps_nfc_tag_read' command - one argument "
917 "is required.\n");
918 return -1;
919 }
920
921 buflen = 18 + os_strlen(argv[0]);
922 buf = os_malloc(buflen);
923 if (buf == NULL)
924 return -1;
925 os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
926
927 ret = wpa_ctrl_command(ctrl, buf);
928 os_free(buf);
929
930 return ret;
931}
71892384 932
e65552dd
JM
933
934static int wpa_cli_cmd_nfc_get_handover_req(struct wpa_ctrl *ctrl, int argc,
935 char *argv[])
936{
937 return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_REQ", 2, argc, argv);
938}
939
940
941static int wpa_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl, int argc,
942 char *argv[])
943{
944 return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_SEL", 2, argc, argv);
945}
946
947
e4758827
JM
948static int wpa_cli_cmd_nfc_report_handover(struct wpa_ctrl *ctrl, int argc,
949 char *argv[])
950{
951 return wpa_cli_cmd(ctrl, "NFC_REPORT_HANDOVER", 4, argc, argv);
952}
953
71892384 954#endif /* CONFIG_WPS_NFC */
46bdb83a
MH
955
956
fcc60db4
JM
957static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
958{
959 char cmd[256];
960 int res;
961
52eb293d
JM
962 if (argc == 2)
963 res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s",
964 argv[0], argv[1]);
7d6640a6 965 else if (argc == 5 || argc == 6) {
52eb293d
JM
966 char ssid_hex[2 * 32 + 1];
967 char key_hex[2 * 64 + 1];
968 int i;
969
970 ssid_hex[0] = '\0';
971 for (i = 0; i < 32; i++) {
972 if (argv[2][i] == '\0')
973 break;
974 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]);
975 }
976
977 key_hex[0] = '\0';
7d6640a6
JM
978 if (argc == 6) {
979 for (i = 0; i < 64; i++) {
980 if (argv[5][i] == '\0')
981 break;
982 os_snprintf(&key_hex[i * 2], 3, "%02x",
983 argv[5][i]);
984 }
52eb293d
JM
985 }
986
987 res = os_snprintf(cmd, sizeof(cmd),
988 "WPS_REG %s %s %s %s %s %s",
989 argv[0], argv[1], ssid_hex, argv[3], argv[4],
990 key_hex);
991 } else {
fcc60db4 992 printf("Invalid WPS_REG command: need two arguments:\n"
129eb428 993 "- BSSID of the target AP\n"
fcc60db4 994 "- AP PIN\n");
52eb293d
JM
995 printf("Alternatively, six arguments can be used to "
996 "reconfigure the AP:\n"
129eb428 997 "- BSSID of the target AP\n"
52eb293d
JM
998 "- AP PIN\n"
999 "- new SSID\n"
1000 "- new auth (OPEN, WPAPSK, WPA2PSK)\n"
1001 "- new encr (NONE, WEP, TKIP, CCMP)\n"
1002 "- new key\n");
fcc60db4
JM
1003 return -1;
1004 }
1005
eeab4f2f 1006 if (os_snprintf_error(sizeof(cmd), res)) {
fcc60db4
JM
1007 printf("Too long WPS_REG command.\n");
1008 return -1;
1009 }
1010 return wpa_ctrl_command(ctrl, cmd);
1011}
1012
1013
70d84f11
JM
1014static int wpa_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
1015 char *argv[])
1016{
87c7ba84 1017 return wpa_cli_cmd(ctrl, "WPS_AP_PIN", 1, argc, argv);
70d84f11
JM
1018}
1019
1020
e9bcfebf
JM
1021static int wpa_cli_cmd_wps_er_start(struct wpa_ctrl *ctrl, int argc,
1022 char *argv[])
1023{
87c7ba84 1024 return wpa_cli_cmd(ctrl, "WPS_ER_START", 0, argc, argv);
e9bcfebf
JM
1025}
1026
1027
1028static int wpa_cli_cmd_wps_er_stop(struct wpa_ctrl *ctrl, int argc,
1029 char *argv[])
1030{
1031 return wpa_ctrl_command(ctrl, "WPS_ER_STOP");
1032
1033}
1034
1035
72df2f5f
JM
1036static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc,
1037 char *argv[])
1038{
31fcea93
JM
1039 if (argc < 2) {
1040 printf("Invalid WPS_ER_PIN command: need at least two "
1041 "arguments:\n"
72df2f5f 1042 "- UUID: use 'any' to select any\n"
31fcea93
JM
1043 "- PIN: Enrollee PIN\n"
1044 "optional: - Enrollee MAC address\n");
72df2f5f
JM
1045 return -1;
1046 }
1047
87c7ba84 1048 return wpa_cli_cmd(ctrl, "WPS_ER_PIN", 2, argc, argv);
72df2f5f
JM
1049}
1050
1051
564cd7fa
JM
1052static int wpa_cli_cmd_wps_er_pbc(struct wpa_ctrl *ctrl, int argc,
1053 char *argv[])
1054{
87c7ba84 1055 return wpa_cli_cmd(ctrl, "WPS_ER_PBC", 1, argc, argv);
564cd7fa
JM
1056}
1057
1058
e64dcfd5
JM
1059static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc,
1060 char *argv[])
1061{
e64dcfd5
JM
1062 if (argc != 2) {
1063 printf("Invalid WPS_ER_LEARN command: need two arguments:\n"
1064 "- UUID: specify which AP to use\n"
1065 "- PIN: AP PIN\n");
1066 return -1;
1067 }
1068
87c7ba84 1069 return wpa_cli_cmd(ctrl, "WPS_ER_LEARN", 2, argc, argv);
e64dcfd5
JM
1070}
1071
1072
ef10f473
JM
1073static int wpa_cli_cmd_wps_er_set_config(struct wpa_ctrl *ctrl, int argc,
1074 char *argv[])
1075{
ef10f473
JM
1076 if (argc != 2) {
1077 printf("Invalid WPS_ER_SET_CONFIG command: need two "
1078 "arguments:\n"
1079 "- UUID: specify which AP to use\n"
1080 "- Network configuration id\n");
1081 return -1;
1082 }
1083
87c7ba84 1084 return wpa_cli_cmd(ctrl, "WPS_ER_SET_CONFIG", 2, argc, argv);
ef10f473
JM
1085}
1086
1087
7d6640a6
JM
1088static int wpa_cli_cmd_wps_er_config(struct wpa_ctrl *ctrl, int argc,
1089 char *argv[])
1090{
1091 char cmd[256];
1092 int res;
1093
1094 if (argc == 5 || argc == 6) {
1095 char ssid_hex[2 * 32 + 1];
1096 char key_hex[2 * 64 + 1];
1097 int i;
1098
1099 ssid_hex[0] = '\0';
1100 for (i = 0; i < 32; i++) {
1101 if (argv[2][i] == '\0')
1102 break;
1103 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]);
1104 }
1105
1106 key_hex[0] = '\0';
1107 if (argc == 6) {
1108 for (i = 0; i < 64; i++) {
1109 if (argv[5][i] == '\0')
1110 break;
1111 os_snprintf(&key_hex[i * 2], 3, "%02x",
1112 argv[5][i]);
1113 }
1114 }
1115
1116 res = os_snprintf(cmd, sizeof(cmd),
1117 "WPS_ER_CONFIG %s %s %s %s %s %s",
1118 argv[0], argv[1], ssid_hex, argv[3], argv[4],
1119 key_hex);
1120 } else {
1121 printf("Invalid WPS_ER_CONFIG command: need six arguments:\n"
1122 "- AP UUID\n"
1123 "- AP PIN\n"
1124 "- new SSID\n"
1125 "- new auth (OPEN, WPAPSK, WPA2PSK)\n"
1126 "- new encr (NONE, WEP, TKIP, CCMP)\n"
1127 "- new key\n");
1128 return -1;
1129 }
1130
eeab4f2f 1131 if (os_snprintf_error(sizeof(cmd), res)) {
7d6640a6
JM
1132 printf("Too long WPS_ER_CONFIG command.\n");
1133 return -1;
1134 }
1135 return wpa_ctrl_command(ctrl, cmd);
1136}
1137
1138
1cea09a9
JM
1139#ifdef CONFIG_WPS_NFC
1140static int wpa_cli_cmd_wps_er_nfc_config_token(struct wpa_ctrl *ctrl, int argc,
1141 char *argv[])
1142{
1cea09a9
JM
1143 if (argc != 2) {
1144 printf("Invalid WPS_ER_NFC_CONFIG_TOKEN command: need two "
1145 "arguments:\n"
1146 "- WPS/NDEF: token format\n"
1147 "- UUID: specify which AP to use\n");
1148 return -1;
1149 }
1150
87c7ba84 1151 return wpa_cli_cmd(ctrl, "WPS_ER_NFC_CONFIG_TOKEN", 2, argc, argv);
1cea09a9
JM
1152}
1153#endif /* CONFIG_WPS_NFC */
1154
1155
11ef8d35
JM
1156static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[])
1157{
87c7ba84 1158 return wpa_cli_cmd(ctrl, "IBSS_RSN", 1, argc, argv);
11ef8d35
JM
1159}
1160
1161
6fc6879b
JM
1162static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
1163{
87c7ba84 1164 return wpa_cli_cmd(ctrl, "LEVEL", 1, argc, argv);
6fc6879b
JM
1165}
1166
1167
1168static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[])
1169{
1170 char cmd[256], *pos, *end;
1171 int i, ret;
1172
1173 if (argc < 2) {
1174 printf("Invalid IDENTITY command: needs two arguments "
1175 "(network id and identity)\n");
1176 return -1;
1177 }
1178
1179 end = cmd + sizeof(cmd);
1180 pos = cmd;
1181 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s",
1182 argv[0], argv[1]);
d85e1fc8 1183 if (os_snprintf_error(end - pos, ret)) {
6fc6879b
JM
1184 printf("Too long IDENTITY command.\n");
1185 return -1;
1186 }
1187 pos += ret;
1188 for (i = 2; i < argc; i++) {
1189 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
d85e1fc8 1190 if (os_snprintf_error(end - pos, ret)) {
6fc6879b
JM
1191 printf("Too long IDENTITY command.\n");
1192 return -1;
1193 }
1194 pos += ret;
1195 }
1196
1197 return wpa_ctrl_command(ctrl, cmd);
1198}
1199
1200
1201static int wpa_cli_cmd_password(struct wpa_ctrl *ctrl, int argc, char *argv[])
1202{
1203 char cmd[256], *pos, *end;
1204 int i, ret;
1205
1206 if (argc < 2) {
1207 printf("Invalid PASSWORD command: needs two arguments "
1208 "(network id and password)\n");
1209 return -1;
1210 }
1211
1212 end = cmd + sizeof(cmd);
1213 pos = cmd;
1214 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s",
1215 argv[0], argv[1]);
d85e1fc8 1216 if (os_snprintf_error(end - pos, ret)) {
6fc6879b
JM
1217 printf("Too long PASSWORD command.\n");
1218 return -1;
1219 }
1220 pos += ret;
1221 for (i = 2; i < argc; i++) {
1222 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
d85e1fc8 1223 if (os_snprintf_error(end - pos, ret)) {
6fc6879b
JM
1224 printf("Too long PASSWORD command.\n");
1225 return -1;
1226 }
1227 pos += ret;
1228 }
1229
1230 return wpa_ctrl_command(ctrl, cmd);
1231}
1232
1233
1234static int wpa_cli_cmd_new_password(struct wpa_ctrl *ctrl, int argc,
1235 char *argv[])
1236{
1237 char cmd[256], *pos, *end;
1238 int i, ret;
1239
1240 if (argc < 2) {
1241 printf("Invalid NEW_PASSWORD command: needs two arguments "
1242 "(network id and password)\n");
1243 return -1;
1244 }
1245
1246 end = cmd + sizeof(cmd);
1247 pos = cmd;
1248 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s",
1249 argv[0], argv[1]);
d85e1fc8 1250 if (os_snprintf_error(end - pos, ret)) {
6fc6879b
JM
1251 printf("Too long NEW_PASSWORD command.\n");
1252 return -1;
1253 }
1254 pos += ret;
1255 for (i = 2; i < argc; i++) {
1256 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
d85e1fc8 1257 if (os_snprintf_error(end - pos, ret)) {
6fc6879b
JM
1258 printf("Too long NEW_PASSWORD command.\n");
1259 return -1;
1260 }
1261 pos += ret;
1262 }
1263
1264 return wpa_ctrl_command(ctrl, cmd);
1265}
1266
1267
1268static int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
1269{
1270 char cmd[256], *pos, *end;
1271 int i, ret;
1272
1273 if (argc < 2) {
1274 printf("Invalid PIN command: needs two arguments "
1275 "(network id and pin)\n");
1276 return -1;
1277 }
1278
1279 end = cmd + sizeof(cmd);
1280 pos = cmd;
1281 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s",
1282 argv[0], argv[1]);
d85e1fc8 1283 if (os_snprintf_error(end - pos, ret)) {
6fc6879b
JM
1284 printf("Too long PIN command.\n");
1285 return -1;
1286 }
1287 pos += ret;
1288 for (i = 2; i < argc; i++) {
1289 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
d85e1fc8 1290 if (os_snprintf_error(end - pos, ret)) {
6fc6879b
JM
1291 printf("Too long PIN command.\n");
1292 return -1;
1293 }
1294 pos += ret;
1295 }
1296 return wpa_ctrl_command(ctrl, cmd);
1297}
1298
1299
1300static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[])
1301{
1302 char cmd[256], *pos, *end;
1303 int i, ret;
1304
1305 if (argc < 2) {
1306 printf("Invalid OTP command: needs two arguments (network "
1307 "id and password)\n");
1308 return -1;
1309 }
1310
1311 end = cmd + sizeof(cmd);
1312 pos = cmd;
1313 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s",
1314 argv[0], argv[1]);
d85e1fc8 1315 if (os_snprintf_error(end - pos, ret)) {
6fc6879b
JM
1316 printf("Too long OTP command.\n");
1317 return -1;
1318 }
1319 pos += ret;
1320 for (i = 2; i < argc; i++) {
1321 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
d85e1fc8 1322 if (os_snprintf_error(end - pos, ret)) {
6fc6879b
JM
1323 printf("Too long OTP command.\n");
1324 return -1;
1325 }
1326 pos += ret;
1327 }
1328
1329 return wpa_ctrl_command(ctrl, cmd);
1330}
1331
1332
a5d44ac0
JM
1333static int wpa_cli_cmd_sim(struct wpa_ctrl *ctrl, int argc, char *argv[])
1334{
1335 char cmd[256], *pos, *end;
1336 int i, ret;
1337
1338 if (argc < 2) {
1339 printf("Invalid SIM command: needs two arguments "
1340 "(network id and SIM operation response)\n");
1341 return -1;
1342 }
1343
1344 end = cmd + sizeof(cmd);
1345 pos = cmd;
1346 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "SIM-%s:%s",
1347 argv[0], argv[1]);
d85e1fc8 1348 if (os_snprintf_error(end - pos, ret)) {
a5d44ac0
JM
1349 printf("Too long SIM command.\n");
1350 return -1;
1351 }
1352 pos += ret;
1353 for (i = 2; i < argc; i++) {
1354 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
d85e1fc8 1355 if (os_snprintf_error(end - pos, ret)) {
a5d44ac0
JM
1356 printf("Too long SIM command.\n");
1357 return -1;
1358 }
1359 pos += ret;
1360 }
1361 return wpa_ctrl_command(ctrl, cmd);
1362}
1363
1364
6fc6879b
JM
1365static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
1366 char *argv[])
1367{
1368 char cmd[256], *pos, *end;
1369 int i, ret;
1370
1371 if (argc < 2) {
1372 printf("Invalid PASSPHRASE command: needs two arguments "
1373 "(network id and passphrase)\n");
1374 return -1;
1375 }
1376
1377 end = cmd + sizeof(cmd);
1378 pos = cmd;
1379 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s",
1380 argv[0], argv[1]);
d85e1fc8 1381 if (os_snprintf_error(end - pos, ret)) {
6fc6879b
JM
1382 printf("Too long PASSPHRASE command.\n");
1383 return -1;
1384 }
1385 pos += ret;
1386 for (i = 2; i < argc; i++) {
1387 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
d85e1fc8 1388 if (os_snprintf_error(end - pos, ret)) {
6fc6879b
JM
1389 printf("Too long PASSPHRASE command.\n");
1390 return -1;
1391 }
1392 pos += ret;
1393 }
1394
1395 return wpa_ctrl_command(ctrl, cmd);
1396}
1397
1398
1399static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[])
1400{
6fc6879b
JM
1401 if (argc < 2) {
1402 printf("Invalid BSSID command: needs two arguments (network "
1403 "id and BSSID)\n");
1404 return -1;
1405 }
1406
87c7ba84 1407 return wpa_cli_cmd(ctrl, "BSSID", 2, argc, argv);
6fc6879b
JM
1408}
1409
1410
9aa10e2b
DS
1411static int wpa_cli_cmd_blacklist(struct wpa_ctrl *ctrl, int argc, char *argv[])
1412{
87c7ba84
JM
1413 return wpa_cli_cmd(ctrl, "BLACKLIST", 0, argc, argv);
1414}
9aa10e2b
DS
1415
1416
0597a5b5
DS
1417static int wpa_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
1418{
87c7ba84 1419 return wpa_cli_cmd(ctrl, "LOG_LEVEL", 0, argc, argv);
0597a5b5
DS
1420}
1421
1422
6fc6879b
JM
1423static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc,
1424 char *argv[])
1425{
1426 return wpa_ctrl_command(ctrl, "LIST_NETWORKS");
1427}
1428
1429
1430static int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc,
1431 char *argv[])
1432{
87c7ba84 1433 return wpa_cli_cmd(ctrl, "SELECT_NETWORK", 1, argc, argv);
6fc6879b
JM
1434}
1435
1436
1437static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc,
1438 char *argv[])
1439{
87c7ba84 1440 return wpa_cli_cmd(ctrl, "ENABLE_NETWORK", 1, argc, argv);
6fc6879b
JM
1441}
1442
1443
1444static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc,
1445 char *argv[])
1446{
87c7ba84 1447 return wpa_cli_cmd(ctrl, "DISABLE_NETWORK", 1, argc, argv);
6fc6879b
JM
1448}
1449
1450
1451static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc,
1452 char *argv[])
1453{
1454 return wpa_ctrl_command(ctrl, "ADD_NETWORK");
1455}
1456
1457
1458static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc,
1459 char *argv[])
1460{
87c7ba84 1461 return wpa_cli_cmd(ctrl, "REMOVE_NETWORK", 1, argc, argv);
6fc6879b
JM
1462}
1463
1464
1465static void wpa_cli_show_network_variables(void)
1466{
1467 printf("set_network variables:\n"
1468 " ssid (network name, SSID)\n"
1469 " psk (WPA passphrase or pre-shared key)\n"
1470 " key_mgmt (key management protocol)\n"
1471 " identity (EAP identity)\n"
1472 " password (EAP password)\n"
1473 " ...\n"
1474 "\n"
1475 "Note: Values are entered in the same format as the "
1476 "configuration file is using,\n"
1477 "i.e., strings values need to be inside double quotation "
1478 "marks.\n"
1479 "For example: set_network 1 ssid \"network name\"\n"
1480 "\n"
1481 "Please see wpa_supplicant.conf documentation for full list "
1482 "of\navailable variables.\n");
1483}
1484
1485
1486static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc,
1487 char *argv[])
1488{
6fc6879b
JM
1489 if (argc == 0) {
1490 wpa_cli_show_network_variables();
1491 return 0;
1492 }
1493
af1dff8c 1494 if (argc < 3) {
6fc6879b
JM
1495 printf("Invalid SET_NETWORK command: needs three arguments\n"
1496 "(network id, variable name, and value)\n");
1497 return -1;
1498 }
1499
87c7ba84 1500 return wpa_cli_cmd(ctrl, "SET_NETWORK", 3, argc, argv);
6fc6879b
JM
1501}
1502
1503
1504static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
1505 char *argv[])
1506{
6fc6879b
JM
1507 if (argc == 0) {
1508 wpa_cli_show_network_variables();
1509 return 0;
1510 }
1511
1512 if (argc != 2) {
1513 printf("Invalid GET_NETWORK command: needs two arguments\n"
1514 "(network id and variable name)\n");
1515 return -1;
1516 }
1517
87c7ba84 1518 return wpa_cli_cmd(ctrl, "GET_NETWORK", 2, argc, argv);
6fc6879b
JM
1519}
1520
1521
1c330a2f
DS
1522static int wpa_cli_cmd_dup_network(struct wpa_ctrl *ctrl, int argc,
1523 char *argv[])
1524{
1525 if (argc == 0) {
1526 wpa_cli_show_network_variables();
1527 return 0;
1528 }
1529
1530 if (argc < 3) {
1531 printf("Invalid DUP_NETWORK command: needs three arguments\n"
1532 "(src netid, dest netid, and variable name)\n");
1533 return -1;
1534 }
1535
1536 return wpa_cli_cmd(ctrl, "DUP_NETWORK", 3, argc, argv);
1537}
1538
1539
d94c9ee6
JM
1540static int wpa_cli_cmd_list_creds(struct wpa_ctrl *ctrl, int argc,
1541 char *argv[])
1542{
1543 return wpa_ctrl_command(ctrl, "LIST_CREDS");
1544}
1545
1546
1547static int wpa_cli_cmd_add_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
1548{
1549 return wpa_ctrl_command(ctrl, "ADD_CRED");
1550}
1551
1552
1553static int wpa_cli_cmd_remove_cred(struct wpa_ctrl *ctrl, int argc,
1554 char *argv[])
1555{
87c7ba84 1556 return wpa_cli_cmd(ctrl, "REMOVE_CRED", 1, argc, argv);
d94c9ee6
JM
1557}
1558
1559
1560static int wpa_cli_cmd_set_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
1561{
d94c9ee6
JM
1562 if (argc != 3) {
1563 printf("Invalid SET_CRED command: needs three arguments\n"
1564 "(cred id, variable name, and value)\n");
1565 return -1;
1566 }
1567
87c7ba84 1568 return wpa_cli_cmd(ctrl, "SET_CRED", 3, argc, argv);
d94c9ee6
JM
1569}
1570
1571
c880ab87
JM
1572static int wpa_cli_cmd_get_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
1573{
1574 if (argc != 2) {
1575 printf("Invalid GET_CRED command: needs two arguments\n"
1576 "(cred id, variable name)\n");
1577 return -1;
1578 }
1579
1580 return wpa_cli_cmd(ctrl, "GET_CRED", 2, argc, argv);
1581}
1582
1583
6fc6879b
JM
1584static int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc,
1585 char *argv[])
1586{
1587 return wpa_ctrl_command(ctrl, "DISCONNECT");
1588}
1589
1590
1591static int wpa_cli_cmd_reconnect(struct wpa_ctrl *ctrl, int argc,
1592 char *argv[])
1593{
1594 return wpa_ctrl_command(ctrl, "RECONNECT");
1595}
1596
1597
1598static int wpa_cli_cmd_save_config(struct wpa_ctrl *ctrl, int argc,
1599 char *argv[])
1600{
1601 return wpa_ctrl_command(ctrl, "SAVE_CONFIG");
1602}
1603
1604
1605static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
1606{
66fe0f70 1607 return wpa_cli_cmd(ctrl, "SCAN", 0, argc, argv);
6fc6879b
JM
1608}
1609
1610
1611static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc,
1612 char *argv[])
1613{
1614 return wpa_ctrl_command(ctrl, "SCAN_RESULTS");
1615}
1616
1617
1618static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
1619{
87c7ba84 1620 return wpa_cli_cmd(ctrl, "BSS", 1, argc, argv);
6fc6879b
JM
1621}
1622
1623
a624f20b
JM
1624static char ** wpa_cli_complete_bss(const char *str, int pos)
1625{
1626 int arg = get_cmd_arg_num(str, pos);
1627 char **res = NULL;
1628
1629 switch (arg) {
1630 case 1:
1631 res = cli_txt_list_array(&bsses);
1632 break;
1633 }
1634
1635 return res;
1636}
1637
1638
6fc6879b
JM
1639static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
1640 char *argv[])
1641{
6fc6879b
JM
1642 if (argc < 1 || argc > 2) {
1643 printf("Invalid GET_CAPABILITY command: need either one or "
1644 "two arguments\n");
1645 return -1;
1646 }
1647
1648 if ((argc == 2) && os_strcmp(argv[1], "strict") != 0) {
1649 printf("Invalid GET_CAPABILITY command: second argument, "
1650 "if any, must be 'strict'\n");
1651 return -1;
1652 }
1653
87c7ba84 1654 return wpa_cli_cmd(ctrl, "GET_CAPABILITY", 1, argc, argv);
6fc6879b
JM
1655}
1656
1657
1658static int wpa_cli_list_interfaces(struct wpa_ctrl *ctrl)
1659{
1660 printf("Available interfaces:\n");
1661 return wpa_ctrl_command(ctrl, "INTERFACES");
1662}
1663
1664
1665static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[])
1666{
1667 if (argc < 1) {
1668 wpa_cli_list_interfaces(ctrl);
1669 return 0;
1670 }
1671
1672 wpa_cli_close_connection();
1673 os_free(ctrl_ifname);
1674 ctrl_ifname = os_strdup(argv[0]);
30f459c0
EL
1675 if (!ctrl_ifname) {
1676 printf("Failed to allocate memory\n");
1677 return 0;
1678 }
6fc6879b 1679
2150c333 1680 if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
6fc6879b 1681 printf("Connected to interface '%s.\n", ctrl_ifname);
6fc6879b
JM
1682 } else {
1683 printf("Could not connect to interface '%s' - re-trying\n",
1684 ctrl_ifname);
1685 }
1686 return 0;
1687}
1688
1689
1690static int wpa_cli_cmd_reconfigure(struct wpa_ctrl *ctrl, int argc,
1691 char *argv[])
1692{
1693 return wpa_ctrl_command(ctrl, "RECONFIGURE");
1694}
1695
1696
1697static int wpa_cli_cmd_terminate(struct wpa_ctrl *ctrl, int argc,
1698 char *argv[])
1699{
1700 return wpa_ctrl_command(ctrl, "TERMINATE");
1701}
1702
1703
1704static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc,
1705 char *argv[])
1706{
1707 char cmd[256];
1708 int res;
1709
1710 if (argc < 1) {
1711 printf("Invalid INTERFACE_ADD command: needs at least one "
1712 "argument (interface name)\n"
1713 "All arguments: ifname confname driver ctrl_interface "
1714 "driver_param bridge_name\n");
1715 return -1;
1716 }
1717
1718 /*
1719 * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
1720 * <driver_param>TAB<bridge_name>
1721 */
1722 res = os_snprintf(cmd, sizeof(cmd),
1723 "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s",
1724 argv[0],
1725 argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "",
1726 argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "",
1727 argc > 5 ? argv[5] : "");
d85e1fc8 1728 if (os_snprintf_error(sizeof(cmd), res))
6fc6879b
JM
1729 return -1;
1730 cmd[sizeof(cmd) - 1] = '\0';
1731 return wpa_ctrl_command(ctrl, cmd);
1732}
1733
1734
1735static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc,
1736 char *argv[])
1737{
87c7ba84 1738 return wpa_cli_cmd(ctrl, "INTERFACE_REMOVE", 1, argc, argv);
6fc6879b
JM
1739}
1740
1741
4b4a8ae5
JM
1742static int wpa_cli_cmd_interface_list(struct wpa_ctrl *ctrl, int argc,
1743 char *argv[])
1744{
1745 return wpa_ctrl_command(ctrl, "INTERFACE_LIST");
1746}
1747
1748
e653b622
JM
1749#ifdef CONFIG_AP
1750static int wpa_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
1751{
87c7ba84 1752 return wpa_cli_cmd(ctrl, "STA", 1, argc, argv);
e653b622
JM
1753}
1754
1755
1756static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
1757 char *addr, size_t addr_len)
1758{
1759 char buf[4096], *pos;
1760 size_t len;
1761 int ret;
1762
1763 if (ctrl_conn == NULL) {
1764 printf("Not connected to hostapd - command dropped.\n");
1765 return -1;
1766 }
1767 len = sizeof(buf) - 1;
024d018b 1768 ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
e653b622
JM
1769 wpa_cli_msg_cb);
1770 if (ret == -2) {
1771 printf("'%s' command timed out.\n", cmd);
1772 return -2;
1773 } else if (ret < 0) {
1774 printf("'%s' command failed.\n", cmd);
1775 return -1;
1776 }
1777
1778 buf[len] = '\0';
024d018b 1779 if (os_memcmp(buf, "FAIL", 4) == 0)
e653b622
JM
1780 return -1;
1781 printf("%s", buf);
1782
1783 pos = buf;
1784 while (*pos != '\0' && *pos != '\n')
1785 pos++;
1786 *pos = '\0';
1787 os_strlcpy(addr, buf, addr_len);
1788 return 0;
1789}
1790
1791
1792static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
1793{
1794 char addr[32], cmd[64];
1795
1796 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
1797 return 0;
1798 do {
e824cc46 1799 os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
e653b622
JM
1800 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
1801
1802 return -1;
1803}
e60b2951
JJ
1804
1805
1806static int wpa_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
1807 char *argv[])
1808{
87c7ba84 1809 return wpa_cli_cmd(ctrl, "DEAUTHENTICATE", 1, argc, argv);
e60b2951
JJ
1810}
1811
1812
1813static int wpa_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
1814 char *argv[])
1815{
87c7ba84 1816 return wpa_cli_cmd(ctrl, "DISASSOCIATE", 1, argc, argv);
e60b2951 1817}
334bf36a
AO
1818
1819static int wpa_cli_cmd_chanswitch(struct wpa_ctrl *ctrl, int argc,
1820 char *argv[])
1821{
1822 return wpa_cli_cmd(ctrl, "CHAN_SWITCH", 2, argc, argv);
1823}
1824
e653b622
JM
1825#endif /* CONFIG_AP */
1826
1827
207ef3fb
JM
1828static int wpa_cli_cmd_suspend(struct wpa_ctrl *ctrl, int argc, char *argv[])
1829{
1830 return wpa_ctrl_command(ctrl, "SUSPEND");
1831}
1832
1833
1834static int wpa_cli_cmd_resume(struct wpa_ctrl *ctrl, int argc, char *argv[])
1835{
1836 return wpa_ctrl_command(ctrl, "RESUME");
1837}
1838
1839
9ff4de6d 1840#ifdef CONFIG_TESTING_OPTIONS
32d5295f
JM
1841static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[])
1842{
1843 return wpa_ctrl_command(ctrl, "DROP_SA");
1844}
9ff4de6d 1845#endif /* CONFIG_TESTING_OPTIONS */
32d5295f
JM
1846
1847
86d4f806
JM
1848static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
1849{
87c7ba84 1850 return wpa_cli_cmd(ctrl, "ROAM", 1, argc, argv);
86d4f806
JM
1851}
1852
1853
603a3f34
JL
1854#ifdef CONFIG_MESH
1855
5b78493f
MH
1856static int wpa_cli_cmd_mesh_interface_add(struct wpa_ctrl *ctrl, int argc,
1857 char *argv[])
1858{
1859 return wpa_cli_cmd(ctrl, "MESH_INTERFACE_ADD", 0, argc, argv);
1860}
1861
1862
603a3f34
JL
1863static int wpa_cli_cmd_mesh_group_add(struct wpa_ctrl *ctrl, int argc,
1864 char *argv[])
1865{
1866 return wpa_cli_cmd(ctrl, "MESH_GROUP_ADD", 1, argc, argv);
1867}
1868
1869
1870static int wpa_cli_cmd_mesh_group_remove(struct wpa_ctrl *ctrl, int argc,
1871 char *argv[])
1872{
1873 return wpa_cli_cmd(ctrl, "MESH_GROUP_REMOVE", 1, argc, argv);
1874}
1875
1876#endif /* CONFIG_MESH */
1877
1878
57faa1ce
JM
1879#ifdef CONFIG_P2P
1880
1881static int wpa_cli_cmd_p2p_find(struct wpa_ctrl *ctrl, int argc, char *argv[])
1882{
87c7ba84 1883 return wpa_cli_cmd(ctrl, "P2P_FIND", 0, argc, argv);
57faa1ce
JM
1884}
1885
1886
01335e2c
JM
1887static char ** wpa_cli_complete_p2p_find(const char *str, int pos)
1888{
1889 char **res = NULL;
1890 int arg = get_cmd_arg_num(str, pos);
1891
1892 res = os_calloc(6, sizeof(char *));
1893 if (res == NULL)
1894 return NULL;
1895 res[0] = os_strdup("type=social");
1896 if (res[0] == NULL) {
1897 os_free(res);
1898 return NULL;
1899 }
1900 res[1] = os_strdup("type=progressive");
1901 if (res[1] == NULL)
1902 return res;
1903 res[2] = os_strdup("delay=");
1904 if (res[2] == NULL)
1905 return res;
1906 res[3] = os_strdup("dev_id=");
1907 if (res[3] == NULL)
1908 return res;
1909 if (arg == 1)
1910 res[4] = os_strdup("[timeout]");
1911
1912 return res;
1913}
1914
1915
57faa1ce
JM
1916static int wpa_cli_cmd_p2p_stop_find(struct wpa_ctrl *ctrl, int argc,
1917 char *argv[])
1918{
1919 return wpa_ctrl_command(ctrl, "P2P_STOP_FIND");
1920}
1921
1922
f309c18e
KV
1923static int wpa_cli_cmd_p2p_asp_provision(struct wpa_ctrl *ctrl, int argc,
1924 char *argv[])
1925{
1926 return wpa_cli_cmd(ctrl, "P2P_ASP_PROVISION", 3, argc, argv);
1927}
1928
1929
1930static int wpa_cli_cmd_p2p_asp_provision_resp(struct wpa_ctrl *ctrl, int argc,
1931 char *argv[])
1932{
1933 return wpa_cli_cmd(ctrl, "P2P_ASP_PROVISION_RESP", 2, argc, argv);
1934}
1935
1936
57faa1ce
JM
1937static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc,
1938 char *argv[])
1939{
87c7ba84 1940 return wpa_cli_cmd(ctrl, "P2P_CONNECT", 2, argc, argv);
57faa1ce
JM
1941}
1942
1943
a624f20b
JM
1944static char ** wpa_cli_complete_p2p_connect(const char *str, int pos)
1945{
1946 int arg = get_cmd_arg_num(str, pos);
1947 char **res = NULL;
1948
1949 switch (arg) {
1950 case 1:
1951 res = cli_txt_list_array(&p2p_peers);
1952 break;
1953 }
1954
1955 return res;
1956}
1957
1958
57faa1ce
JM
1959static int wpa_cli_cmd_p2p_listen(struct wpa_ctrl *ctrl, int argc,
1960 char *argv[])
1961{
87c7ba84 1962 return wpa_cli_cmd(ctrl, "P2P_LISTEN", 0, argc, argv);
57faa1ce
JM
1963}
1964
1965
1966static int wpa_cli_cmd_p2p_group_remove(struct wpa_ctrl *ctrl, int argc,
1967 char *argv[])
1968{
87c7ba84 1969 return wpa_cli_cmd(ctrl, "P2P_GROUP_REMOVE", 1, argc, argv);
57faa1ce
JM
1970}
1971
1972
76788542
JM
1973static char ** wpa_cli_complete_p2p_group_remove(const char *str, int pos)
1974{
1975 int arg = get_cmd_arg_num(str, pos);
1976 char **res = NULL;
1977
1978 switch (arg) {
1979 case 1:
1980 res = cli_txt_list_array(&p2p_groups);
1981 break;
1982 }
1983
1984 return res;
1985}
1986
1987
57faa1ce
JM
1988static int wpa_cli_cmd_p2p_group_add(struct wpa_ctrl *ctrl, int argc,
1989 char *argv[])
1990{
87c7ba84 1991 return wpa_cli_cmd(ctrl, "P2P_GROUP_ADD", 0, argc, argv);
57faa1ce
JM
1992}
1993
1994
1995static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc,
1996 char *argv[])
1997{
8c5f7309
JJ
1998 if (argc != 2 && argc != 3) {
1999 printf("Invalid P2P_PROV_DISC command: needs at least "
2000 "two arguments, address and config method\n"
2001 "(display, keypad, or pbc) and an optional join\n");
57faa1ce
JM
2002 return -1;
2003 }
2004
87c7ba84 2005 return wpa_cli_cmd(ctrl, "P2P_PROV_DISC", 2, argc, argv);
57faa1ce
JM
2006}
2007
2008
2009static int wpa_cli_cmd_p2p_get_passphrase(struct wpa_ctrl *ctrl, int argc,
2010 char *argv[])
2011{
2012 return wpa_ctrl_command(ctrl, "P2P_GET_PASSPHRASE");
2013}
2014
2015
2016static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc,
2017 char *argv[])
2018{
2019 char cmd[4096];
57faa1ce 2020
5a4102ce 2021 if (argc < 2) {
57faa1ce 2022 printf("Invalid P2P_SERV_DISC_REQ command: needs two "
5a4102ce 2023 "or more arguments (address and TLVs)\n");
57faa1ce
JM
2024 return -1;
2025 }
2026
87c7ba84 2027 if (write_cmd(cmd, sizeof(cmd), "P2P_SERV_DISC_REQ", argc, argv) < 0)
57faa1ce 2028 return -1;
57faa1ce
JM
2029 return wpa_ctrl_command(ctrl, cmd);
2030}
2031
2032
2033static int wpa_cli_cmd_p2p_serv_disc_cancel_req(struct wpa_ctrl *ctrl,
2034 int argc, char *argv[])
2035{
87c7ba84 2036 return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_CANCEL_REQ", 1, argc, argv);
57faa1ce
JM
2037}
2038
2039
2040static int wpa_cli_cmd_p2p_serv_disc_resp(struct wpa_ctrl *ctrl, int argc,
2041 char *argv[])
2042{
2043 char cmd[4096];
2044 int res;
2045
2046 if (argc != 4) {
2047 printf("Invalid P2P_SERV_DISC_RESP command: needs four "
2048 "arguments (freq, address, dialog token, and TLVs)\n");
2049 return -1;
2050 }
2051
2052 res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_RESP %s %s %s %s",
2053 argv[0], argv[1], argv[2], argv[3]);
d85e1fc8 2054 if (os_snprintf_error(sizeof(cmd), res))
57faa1ce
JM
2055 return -1;
2056 cmd[sizeof(cmd) - 1] = '\0';
2057 return wpa_ctrl_command(ctrl, cmd);
2058}
2059
2060
2061static int wpa_cli_cmd_p2p_service_update(struct wpa_ctrl *ctrl, int argc,
2062 char *argv[])
2063{
2064 return wpa_ctrl_command(ctrl, "P2P_SERVICE_UPDATE");
2065}
2066
2067
2068static int wpa_cli_cmd_p2p_serv_disc_external(struct wpa_ctrl *ctrl,
2069 int argc, char *argv[])
2070{
87c7ba84 2071 return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_EXTERNAL", 1, argc, argv);
57faa1ce
JM
2072}
2073
2074
2075static int wpa_cli_cmd_p2p_service_flush(struct wpa_ctrl *ctrl, int argc,
2076 char *argv[])
2077{
2078 return wpa_ctrl_command(ctrl, "P2P_SERVICE_FLUSH");
2079}
2080
2081
2082static int wpa_cli_cmd_p2p_service_add(struct wpa_ctrl *ctrl, int argc,
2083 char *argv[])
2084{
ae9d45f3
KV
2085 if (argc < 3) {
2086 printf("Invalid P2P_SERVICE_ADD command: needs 3-6 arguments\n");
2087 return -1;
2088 }
57faa1ce 2089
ae9d45f3
KV
2090 return wpa_cli_cmd(ctrl, "P2P_SERVICE_ADD", 3, argc, argv);
2091}
2092
2093
2094static int wpa_cli_cmd_p2p_service_rep(struct wpa_ctrl *ctrl, int argc,
2095 char *argv[])
2096{
2097 if (argc < 5 || argc > 6) {
2098 printf("Invalid P2P_SERVICE_REP command: needs 5-6 "
57faa1ce
JM
2099 "arguments\n");
2100 return -1;
2101 }
2102
ae9d45f3 2103 return wpa_cli_cmd(ctrl, "P2P_SERVICE_REP", 5, argc, argv);
57faa1ce
JM
2104}
2105
2106
2107static int wpa_cli_cmd_p2p_service_del(struct wpa_ctrl *ctrl, int argc,
2108 char *argv[])
2109{
2110 char cmd[4096];
2111 int res;
2112
2113 if (argc != 2 && argc != 3) {
2114 printf("Invalid P2P_SERVICE_DEL command: needs two or three "
2115 "arguments\n");
2116 return -1;
2117 }
2118
2119 if (argc == 3)
2120 res = os_snprintf(cmd, sizeof(cmd),
2121 "P2P_SERVICE_DEL %s %s %s",
2122 argv[0], argv[1], argv[2]);
2123 else
2124 res = os_snprintf(cmd, sizeof(cmd),
2125 "P2P_SERVICE_DEL %s %s",
2126 argv[0], argv[1]);
d85e1fc8 2127 if (os_snprintf_error(sizeof(cmd), res))
57faa1ce
JM
2128 return -1;
2129 cmd[sizeof(cmd) - 1] = '\0';
2130 return wpa_ctrl_command(ctrl, cmd);
2131}
2132
2133
2134static int wpa_cli_cmd_p2p_reject(struct wpa_ctrl *ctrl,
2135 int argc, char *argv[])
2136{
87c7ba84 2137 return wpa_cli_cmd(ctrl, "P2P_REJECT", 1, argc, argv);
57faa1ce
JM
2138}
2139
2140
2141static int wpa_cli_cmd_p2p_invite(struct wpa_ctrl *ctrl,
2142 int argc, char *argv[])
2143{
87c7ba84 2144 return wpa_cli_cmd(ctrl, "P2P_INVITE", 1, argc, argv);
57faa1ce
JM
2145}
2146
2147
2148static int wpa_cli_cmd_p2p_peer(struct wpa_ctrl *ctrl, int argc, char *argv[])
2149{
87c7ba84 2150 return wpa_cli_cmd(ctrl, "P2P_PEER", 1, argc, argv);
57faa1ce
JM
2151}
2152
2153
a624f20b
JM
2154static char ** wpa_cli_complete_p2p_peer(const char *str, int pos)
2155{
2156 int arg = get_cmd_arg_num(str, pos);
2157 char **res = NULL;
2158
2159 switch (arg) {
2160 case 1:
2161 res = cli_txt_list_array(&p2p_peers);
2162 break;
2163 }
2164
2165 return res;
2166}
2167
2168
57faa1ce
JM
2169static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, char *cmd,
2170 char *addr, size_t addr_len,
2171 int discovered)
2172{
2173 char buf[4096], *pos;
2174 size_t len;
2175 int ret;
2176
2177 if (ctrl_conn == NULL)
2178 return -1;
2179 len = sizeof(buf) - 1;
024d018b 2180 ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
57faa1ce
JM
2181 wpa_cli_msg_cb);
2182 if (ret == -2) {
2183 printf("'%s' command timed out.\n", cmd);
2184 return -2;
2185 } else if (ret < 0) {
2186 printf("'%s' command failed.\n", cmd);
2187 return -1;
2188 }
2189
2190 buf[len] = '\0';
024d018b 2191 if (os_memcmp(buf, "FAIL", 4) == 0)
57faa1ce
JM
2192 return -1;
2193
2194 pos = buf;
2195 while (*pos != '\0' && *pos != '\n')
2196 pos++;
2197 *pos++ = '\0';
2198 os_strlcpy(addr, buf, addr_len);
2199 if (!discovered || os_strstr(pos, "[PROBE_REQ_ONLY]") == NULL)
2200 printf("%s\n", addr);
2201 return 0;
2202}
2203
2204
2205static int wpa_cli_cmd_p2p_peers(struct wpa_ctrl *ctrl, int argc, char *argv[])
2206{
2207 char addr[32], cmd[64];
2208 int discovered;
2209
2210 discovered = argc > 0 && os_strcmp(argv[0], "discovered") == 0;
2211
2212 if (wpa_ctrl_command_p2p_peer(ctrl, "P2P_PEER FIRST",
2213 addr, sizeof(addr), discovered))
9a6ade33 2214 return -1;
57faa1ce
JM
2215 do {
2216 os_snprintf(cmd, sizeof(cmd), "P2P_PEER NEXT-%s", addr);
2217 } while (wpa_ctrl_command_p2p_peer(ctrl, cmd, addr, sizeof(addr),
2218 discovered) == 0);
2219
9a6ade33 2220 return 0;
57faa1ce
JM
2221}
2222
2223
2224static int wpa_cli_cmd_p2p_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
2225{
87c7ba84 2226 return wpa_cli_cmd(ctrl, "P2P_SET", 2, argc, argv);
57faa1ce
JM
2227}
2228
2229
698e921b
JM
2230static char ** wpa_cli_complete_p2p_set(const char *str, int pos)
2231{
2232 int arg = get_cmd_arg_num(str, pos);
2233 const char *fields[] = {
2234 "discoverability",
2235 "managed",
2236 "listen_channel",
2237 "ssid_postfix",
2238 "noa",
2239 "ps",
2240 "oppps",
2241 "ctwindow",
2242 "disabled",
2243 "conc_pref",
2244 "force_long_sd",
2245 "peer_filter",
2246 "cross_connect",
2247 "go_apsd",
2248 "client_apsd",
2249 "disallow_freq",
2250 "disc_int",
05766ed8 2251 "per_sta_psk",
698e921b 2252 };
e7ecab4a 2253 int i, num_fields = ARRAY_SIZE(fields);
698e921b
JM
2254
2255 if (arg == 1) {
2256 char **res = os_calloc(num_fields + 1, sizeof(char *));
2257 if (res == NULL)
2258 return NULL;
2259 for (i = 0; i < num_fields; i++) {
2260 res[i] = os_strdup(fields[i]);
2261 if (res[i] == NULL)
2262 return res;
2263 }
2264 return res;
2265 }
2266
2267 if (arg == 2 && os_strncasecmp(str, "p2p_set peer_filter ", 20) == 0)
2268 return cli_txt_list_array(&p2p_peers);
2269
2270 return NULL;
2271}
2272
2273
57faa1ce
JM
2274static int wpa_cli_cmd_p2p_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
2275{
2276 return wpa_ctrl_command(ctrl, "P2P_FLUSH");
2277}
2278
2279
59eba7a2
JM
2280static int wpa_cli_cmd_p2p_cancel(struct wpa_ctrl *ctrl, int argc,
2281 char *argv[])
2282{
2283 return wpa_ctrl_command(ctrl, "P2P_CANCEL");
2284}
2285
2286
9d562b79
SS
2287static int wpa_cli_cmd_p2p_unauthorize(struct wpa_ctrl *ctrl, int argc,
2288 char *argv[])
2289{
87c7ba84 2290 return wpa_cli_cmd(ctrl, "P2P_UNAUTHORIZE", 1, argc, argv);
9d562b79
SS
2291}
2292
2293
57faa1ce
JM
2294static int wpa_cli_cmd_p2p_presence_req(struct wpa_ctrl *ctrl, int argc,
2295 char *argv[])
2296{
57faa1ce
JM
2297 if (argc != 0 && argc != 2 && argc != 4) {
2298 printf("Invalid P2P_PRESENCE_REQ command: needs two arguments "
2299 "(preferred duration, interval; in microsecods).\n"
2300 "Optional second pair can be used to provide "
2301 "acceptable values.\n");
2302 return -1;
2303 }
2304
87c7ba84 2305 return wpa_cli_cmd(ctrl, "P2P_PRESENCE_REQ", 0, argc, argv);
57faa1ce
JM
2306}
2307
2308
2309static int wpa_cli_cmd_p2p_ext_listen(struct wpa_ctrl *ctrl, int argc,
2310 char *argv[])
2311{
57faa1ce
JM
2312 if (argc != 0 && argc != 2) {
2313 printf("Invalid P2P_EXT_LISTEN command: needs two arguments "
2314 "(availability period, availability interval; in "
2315 "millisecods).\n"
2316 "Extended Listen Timing can be cancelled with this "
2317 "command when used without parameters.\n");
2318 return -1;
2319 }
2320
87c7ba84 2321 return wpa_cli_cmd(ctrl, "P2P_EXT_LISTEN", 0, argc, argv);
57faa1ce
JM
2322}
2323
f2c56602
JM
2324
2325static int wpa_cli_cmd_p2p_remove_client(struct wpa_ctrl *ctrl, int argc,
2326 char *argv[])
2327{
2328 return wpa_cli_cmd(ctrl, "P2P_REMOVE_CLIENT", 1, argc, argv);
2329}
2330
57faa1ce
JM
2331#endif /* CONFIG_P2P */
2332
9675ce35
JM
2333#ifdef CONFIG_WIFI_DISPLAY
2334
2335static int wpa_cli_cmd_wfd_subelem_set(struct wpa_ctrl *ctrl, int argc,
2336 char *argv[])
2337{
2338 char cmd[100];
2339 int res;
2340
2341 if (argc != 1 && argc != 2) {
2342 printf("Invalid WFD_SUBELEM_SET command: needs one or two "
2343 "arguments (subelem, hexdump)\n");
2344 return -1;
2345 }
2346
2347 res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_SET %s %s",
2348 argv[0], argc > 1 ? argv[1] : "");
d85e1fc8 2349 if (os_snprintf_error(sizeof(cmd), res))
9675ce35
JM
2350 return -1;
2351 cmd[sizeof(cmd) - 1] = '\0';
2352 return wpa_ctrl_command(ctrl, cmd);
2353}
2354
2355
2356static int wpa_cli_cmd_wfd_subelem_get(struct wpa_ctrl *ctrl, int argc,
2357 char *argv[])
2358{
2359 char cmd[100];
2360 int res;
2361
2362 if (argc != 1) {
2363 printf("Invalid WFD_SUBELEM_GET command: needs one "
2364 "argument (subelem)\n");
2365 return -1;
2366 }
2367
2368 res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_GET %s",
2369 argv[0]);
d85e1fc8 2370 if (os_snprintf_error(sizeof(cmd), res))
9675ce35
JM
2371 return -1;
2372 cmd[sizeof(cmd) - 1] = '\0';
2373 return wpa_ctrl_command(ctrl, cmd);
2374}
2375#endif /* CONFIG_WIFI_DISPLAY */
2376
57faa1ce 2377
afc064fe
JM
2378#ifdef CONFIG_INTERWORKING
2379static int wpa_cli_cmd_fetch_anqp(struct wpa_ctrl *ctrl, int argc,
2380 char *argv[])
2381{
2382 return wpa_ctrl_command(ctrl, "FETCH_ANQP");
2383}
2384
2385
2386static int wpa_cli_cmd_stop_fetch_anqp(struct wpa_ctrl *ctrl, int argc,
2387 char *argv[])
2388{
2389 return wpa_ctrl_command(ctrl, "STOP_FETCH_ANQP");
2390}
2391
2392
b02fe7ff
JM
2393static int wpa_cli_cmd_interworking_select(struct wpa_ctrl *ctrl, int argc,
2394 char *argv[])
2395{
87c7ba84 2396 return wpa_cli_cmd(ctrl, "INTERWORKING_SELECT", 0, argc, argv);
b02fe7ff
JM
2397}
2398
2399
2400static int wpa_cli_cmd_interworking_connect(struct wpa_ctrl *ctrl, int argc,
2401 char *argv[])
2402{
87c7ba84 2403 return wpa_cli_cmd(ctrl, "INTERWORKING_CONNECT", 1, argc, argv);
b02fe7ff
JM
2404}
2405
2406
f91a512f
JM
2407static int wpa_cli_cmd_interworking_add_network(struct wpa_ctrl *ctrl, int argc,
2408 char *argv[])
2409{
2410 return wpa_cli_cmd(ctrl, "INTERWORKING_ADD_NETWORK", 1, argc, argv);
2411}
2412
2413
afc064fe
JM
2414static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
2415{
87c7ba84 2416 return wpa_cli_cmd(ctrl, "ANQP_GET", 2, argc, argv);
afc064fe 2417}
b1f12296
JM
2418
2419
2420static int wpa_cli_cmd_gas_request(struct wpa_ctrl *ctrl, int argc,
2421 char *argv[])
2422{
2423 return wpa_cli_cmd(ctrl, "GAS_REQUEST", 2, argc, argv);
2424}
2425
2426
2427static int wpa_cli_cmd_gas_response_get(struct wpa_ctrl *ctrl, int argc,
2428 char *argv[])
2429{
2430 return wpa_cli_cmd(ctrl, "GAS_RESPONSE_GET", 2, argc, argv);
2431}
afc064fe
JM
2432#endif /* CONFIG_INTERWORKING */
2433
2434
a8918e86
JK
2435#ifdef CONFIG_HS20
2436
2437static int wpa_cli_cmd_hs20_anqp_get(struct wpa_ctrl *ctrl, int argc,
2438 char *argv[])
2439{
87c7ba84 2440 return wpa_cli_cmd(ctrl, "HS20_ANQP_GET", 2, argc, argv);
a8918e86
JK
2441}
2442
2443
2444static int wpa_cli_cmd_get_nai_home_realm_list(struct wpa_ctrl *ctrl, int argc,
2445 char *argv[])
2446{
2447 char cmd[512];
a8918e86
JK
2448
2449 if (argc == 0) {
2450 printf("Command needs one or two arguments (dst mac addr and "
2451 "optional home realm)\n");
2452 return -1;
2453 }
2454
87c7ba84
JM
2455 if (write_cmd(cmd, sizeof(cmd), "HS20_GET_NAI_HOME_REALM_LIST",
2456 argc, argv) < 0)
a8918e86 2457 return -1;
a8918e86
JK
2458
2459 return wpa_ctrl_command(ctrl, cmd);
2460}
2461
184e110c
JM
2462
2463static int wpa_cli_cmd_hs20_icon_request(struct wpa_ctrl *ctrl, int argc,
2464 char *argv[])
2465{
2466 char cmd[512];
2467
2468 if (argc < 2) {
2469 printf("Command needs two arguments (dst mac addr and "
2470 "icon name)\n");
2471 return -1;
2472 }
2473
2474 if (write_cmd(cmd, sizeof(cmd), "HS20_ICON_REQUEST", argc, argv) < 0)
2475 return -1;
2476
2477 return wpa_ctrl_command(ctrl, cmd);
2478}
2479
b572df86
JM
2480
2481static int wpa_cli_cmd_fetch_osu(struct wpa_ctrl *ctrl, int argc, char *argv[])
2482{
2483 return wpa_ctrl_command(ctrl, "FETCH_OSU");
2484}
2485
2486
2487static int wpa_cli_cmd_cancel_fetch_osu(struct wpa_ctrl *ctrl, int argc,
2488 char *argv[])
2489{
2490 return wpa_ctrl_command(ctrl, "CANCEL_FETCH_OSU");
2491}
2492
a8918e86
JK
2493#endif /* CONFIG_HS20 */
2494
2495
0d0a8ca1
AC
2496static int wpa_cli_cmd_sta_autoconnect(struct wpa_ctrl *ctrl, int argc,
2497 char *argv[])
2498{
87c7ba84 2499 return wpa_cli_cmd(ctrl, "STA_AUTOCONNECT", 1, argc, argv);
0d0a8ca1
AC
2500}
2501
2502
281ff0aa
GP
2503static int wpa_cli_cmd_tdls_discover(struct wpa_ctrl *ctrl, int argc,
2504 char *argv[])
2505{
87c7ba84 2506 return wpa_cli_cmd(ctrl, "TDLS_DISCOVER", 1, argc, argv);
281ff0aa
GP
2507}
2508
2509
2510static int wpa_cli_cmd_tdls_setup(struct wpa_ctrl *ctrl, int argc,
2511 char *argv[])
2512{
87c7ba84 2513 return wpa_cli_cmd(ctrl, "TDLS_SETUP", 1, argc, argv);
281ff0aa
GP
2514}
2515
2516
2517static int wpa_cli_cmd_tdls_teardown(struct wpa_ctrl *ctrl, int argc,
2518 char *argv[])
2519{
87c7ba84 2520 return wpa_cli_cmd(ctrl, "TDLS_TEARDOWN", 1, argc, argv);
281ff0aa
GP
2521}
2522
2523
df9d340c
MB
2524static int wpa_cli_cmd_wmm_ac_addts(struct wpa_ctrl *ctrl, int argc,
2525 char *argv[])
2526{
2527 return wpa_cli_cmd(ctrl, "WMM_AC_ADDTS", 3, argc, argv);
2528}
2529
2530
2531static int wpa_cli_cmd_wmm_ac_delts(struct wpa_ctrl *ctrl, int argc,
2532 char *argv[])
2533{
2534 return wpa_cli_cmd(ctrl, "WMM_AC_DELTS", 1, argc, argv);
2535}
2536
2537
8506ea6f
MB
2538static int wpa_cli_cmd_wmm_ac_status(struct wpa_ctrl *ctrl, int argc,
2539 char *argv[])
2540{
2541 return wpa_ctrl_command(ctrl, "WMM_AC_STATUS");
2542}
2543
2544
7db53bb8
AN
2545static int wpa_cli_cmd_tdls_chan_switch(struct wpa_ctrl *ctrl, int argc,
2546 char *argv[])
2547{
2548 return wpa_cli_cmd(ctrl, "TDLS_CHAN_SWITCH", 2, argc, argv);
2549}
2550
2551
2552static int wpa_cli_cmd_tdls_cancel_chan_switch(struct wpa_ctrl *ctrl, int argc,
2553 char *argv[])
2554{
2555 return wpa_cli_cmd(ctrl, "TDLS_CANCEL_CHAN_SWITCH", 1, argc, argv);
2556}
2557
2558
60b24b0d
DS
2559static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc,
2560 char *argv[])
2561{
2562 return wpa_ctrl_command(ctrl, "SIGNAL_POLL");
2563}
2564
2565
dc7785f8
YZ
2566static int wpa_cli_cmd_pktcnt_poll(struct wpa_ctrl *ctrl, int argc,
2567 char *argv[])
2568{
2569 return wpa_ctrl_command(ctrl, "PKTCNT_POLL");
2570}
2571
2572
9482426e
JM
2573static int wpa_cli_cmd_reauthenticate(struct wpa_ctrl *ctrl, int argc,
2574 char *argv[])
2575{
2576 return wpa_ctrl_command(ctrl, "REAUTHENTICATE");
2577}
2578
2579
2bdd8342
TB
2580#ifdef CONFIG_AUTOSCAN
2581
2582static int wpa_cli_cmd_autoscan(struct wpa_ctrl *ctrl, int argc, char *argv[])
2583{
2bdd8342
TB
2584 if (argc == 0)
2585 return wpa_ctrl_command(ctrl, "AUTOSCAN ");
2586
87c7ba84 2587 return wpa_cli_cmd(ctrl, "AUTOSCAN", 0, argc, argv);
2bdd8342
TB
2588}
2589
2590#endif /* CONFIG_AUTOSCAN */
2591
2592
e9199e31
JM
2593#ifdef CONFIG_WNM
2594
2595static int wpa_cli_cmd_wnm_sleep(struct wpa_ctrl *ctrl, int argc, char *argv[])
2596{
2597 return wpa_cli_cmd(ctrl, "WNM_SLEEP", 0, argc, argv);
2598}
2599
65bcd0a9
VK
2600
2601static int wpa_cli_cmd_wnm_bss_query(struct wpa_ctrl *ctrl, int argc, char *argv[])
2602{
2603 return wpa_cli_cmd(ctrl, "WNM_BSS_QUERY", 1, argc, argv);
2604}
2605
e9199e31
JM
2606#endif /* CONFIG_WNM */
2607
2608
27b80b5b
JM
2609static int wpa_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
2610{
2611 if (argc == 0)
2612 return -1;
2613 return wpa_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]);
2614}
2615
2616
5e2c3490
JM
2617#ifdef ANDROID
2618static int wpa_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[])
2619{
2620 return wpa_cli_cmd(ctrl, "DRIVER", 1, argc, argv);
2621}
2622#endif /* ANDROID */
2623
2624
adef8948
BL
2625static int wpa_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
2626{
2627 return wpa_cli_cmd(ctrl, "VENDOR", 1, argc, argv);
2628}
2629
2630
acb54643
JM
2631static int wpa_cli_cmd_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
2632{
2633 return wpa_ctrl_command(ctrl, "FLUSH");
2634}
2635
2636
1f965e62
JM
2637static int wpa_cli_cmd_radio_work(struct wpa_ctrl *ctrl, int argc, char *argv[])
2638{
2639 return wpa_cli_cmd(ctrl, "RADIO_WORK", 1, argc, argv);
2640}
2641
2642
fad14af9
AK
2643static int wpa_cli_cmd_neighbor_rep_request(struct wpa_ctrl *ctrl, int argc,
2644 char *argv[])
2645{
2646 return wpa_cli_cmd(ctrl, "NEIGHBOR_REP_REQUEST", 0, argc, argv);
2647}
2648
2649
65d9a5e2
JM
2650static int wpa_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
2651{
2652 return wpa_ctrl_command(ctrl, "ERP_FLUSH");
2653}
2654
2655
8b48e320
IP
2656static int wpa_cli_cmd_mac_rand_scan(struct wpa_ctrl *ctrl, int argc,
2657 char *argv[])
2658{
2659 return wpa_cli_cmd(ctrl, "MAC_RAND_SCAN", 1, argc, argv);
2660}
2661
2662
40fd868c
ER
2663enum wpa_cli_cmd_flags {
2664 cli_cmd_flag_none = 0x00,
2665 cli_cmd_flag_sensitive = 0x01
2666};
2667
6fc6879b
JM
2668struct wpa_cli_cmd {
2669 const char *cmd;
2670 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
b49039bd 2671 char ** (*completion)(const char *str, int pos);
40fd868c 2672 enum wpa_cli_cmd_flags flags;
dfa141b1 2673 const char *usage;
6fc6879b
JM
2674};
2675
2676static struct wpa_cli_cmd wpa_cli_commands[] = {
b49039bd 2677 { "status", wpa_cli_cmd_status, NULL,
dfa141b1
ER
2678 cli_cmd_flag_none,
2679 "[verbose] = get current WPA/EAPOL/EAP status" },
b49039bd 2680 { "ifname", wpa_cli_cmd_ifname, NULL,
0eed2a8d
JD
2681 cli_cmd_flag_none,
2682 "= get current interface name" },
b49039bd 2683 { "ping", wpa_cli_cmd_ping, NULL,
dfa141b1
ER
2684 cli_cmd_flag_none,
2685 "= pings wpa_supplicant" },
b49039bd 2686 { "relog", wpa_cli_cmd_relog, NULL,
ac6912b5
BG
2687 cli_cmd_flag_none,
2688 "= re-open log-file (allow rolling logs)" },
b49039bd 2689 { "note", wpa_cli_cmd_note, NULL,
77895cd9
JM
2690 cli_cmd_flag_none,
2691 "<text> = add a note to wpa_supplicant debug log" },
b49039bd 2692 { "mib", wpa_cli_cmd_mib, NULL,
dfa141b1
ER
2693 cli_cmd_flag_none,
2694 "= get MIB variables (dot1x, dot11)" },
2af4d404 2695 { "help", wpa_cli_cmd_help, wpa_cli_complete_help,
dfa141b1 2696 cli_cmd_flag_none,
2af4d404 2697 "[command] = show usage help" },
b49039bd 2698 { "interface", wpa_cli_cmd_interface, NULL,
dfa141b1
ER
2699 cli_cmd_flag_none,
2700 "[ifname] = show interfaces/select interface" },
b49039bd 2701 { "level", wpa_cli_cmd_level, NULL,
dfa141b1
ER
2702 cli_cmd_flag_none,
2703 "<debug level> = change debug level" },
b49039bd 2704 { "license", wpa_cli_cmd_license, NULL,
dfa141b1
ER
2705 cli_cmd_flag_none,
2706 "= show full wpa_cli license" },
b49039bd 2707 { "quit", wpa_cli_cmd_quit, NULL,
dfa141b1
ER
2708 cli_cmd_flag_none,
2709 "= exit wpa_cli" },
21565872 2710 { "set", wpa_cli_cmd_set, wpa_cli_complete_set,
dfa141b1
ER
2711 cli_cmd_flag_none,
2712 "= set variables (shows list of variables when run without "
2713 "arguments)" },
10263dc2
OO
2714 { "dump", wpa_cli_cmd_dump, NULL,
2715 cli_cmd_flag_none,
2716 "= dump config variables" },
0fd9d95f 2717 { "get", wpa_cli_cmd_get, wpa_cli_complete_get,
acec8d32
JM
2718 cli_cmd_flag_none,
2719 "<name> = get information" },
b49039bd 2720 { "logon", wpa_cli_cmd_logon, NULL,
dfa141b1
ER
2721 cli_cmd_flag_none,
2722 "= IEEE 802.1X EAPOL state machine logon" },
b49039bd 2723 { "logoff", wpa_cli_cmd_logoff, NULL,
dfa141b1
ER
2724 cli_cmd_flag_none,
2725 "= IEEE 802.1X EAPOL state machine logoff" },
b49039bd 2726 { "pmksa", wpa_cli_cmd_pmksa, NULL,
dfa141b1
ER
2727 cli_cmd_flag_none,
2728 "= show PMKSA cache" },
79e2b1cc
AK
2729 { "pmksa_flush", wpa_cli_cmd_pmksa_flush, NULL,
2730 cli_cmd_flag_none,
2731 "= flush PMKSA cache entries" },
b49039bd 2732 { "reassociate", wpa_cli_cmd_reassociate, NULL,
dfa141b1
ER
2733 cli_cmd_flag_none,
2734 "= force reassociation" },
0f44ec8e
PQ
2735 { "reattach", wpa_cli_cmd_reattach, NULL,
2736 cli_cmd_flag_none,
2737 "= force reassociation back to the same BSS" },
b49039bd 2738 { "preauthenticate", wpa_cli_cmd_preauthenticate, wpa_cli_complete_bss,
dfa141b1
ER
2739 cli_cmd_flag_none,
2740 "<BSSID> = force preauthentication" },
b49039bd 2741 { "identity", wpa_cli_cmd_identity, NULL,
dfa141b1
ER
2742 cli_cmd_flag_none,
2743 "<network id> <identity> = configure identity for an SSID" },
b49039bd 2744 { "password", wpa_cli_cmd_password, NULL,
dfa141b1
ER
2745 cli_cmd_flag_sensitive,
2746 "<network id> <password> = configure password for an SSID" },
b49039bd 2747 { "new_password", wpa_cli_cmd_new_password, NULL,
dfa141b1
ER
2748 cli_cmd_flag_sensitive,
2749 "<network id> <password> = change password for an SSID" },
b49039bd 2750 { "pin", wpa_cli_cmd_pin, NULL,
dfa141b1
ER
2751 cli_cmd_flag_sensitive,
2752 "<network id> <pin> = configure pin for an SSID" },
b49039bd 2753 { "otp", wpa_cli_cmd_otp, NULL,
dfa141b1
ER
2754 cli_cmd_flag_sensitive,
2755 "<network id> <password> = configure one-time-password for an SSID"
2756 },
b49039bd 2757 { "passphrase", wpa_cli_cmd_passphrase, NULL,
dfa141b1
ER
2758 cli_cmd_flag_sensitive,
2759 "<network id> <passphrase> = configure private key passphrase\n"
2760 " for an SSID" },
a5d44ac0
JM
2761 { "sim", wpa_cli_cmd_sim, NULL,
2762 cli_cmd_flag_sensitive,
2763 "<network id> <pin> = report SIM operation result" },
b49039bd 2764 { "bssid", wpa_cli_cmd_bssid, NULL,
dfa141b1
ER
2765 cli_cmd_flag_none,
2766 "<network id> <BSSID> = set preferred BSSID for an SSID" },
b49039bd 2767 { "blacklist", wpa_cli_cmd_blacklist, wpa_cli_complete_bss,
9aa10e2b
DS
2768 cli_cmd_flag_none,
2769 "<BSSID> = add a BSSID to the blacklist\n"
2770 "blacklist clear = clear the blacklist\n"
2771 "blacklist = display the blacklist" },
b49039bd 2772 { "log_level", wpa_cli_cmd_log_level, NULL,
0597a5b5
DS
2773 cli_cmd_flag_none,
2774 "<level> [<timestamp>] = update the log level/timestamp\n"
2775 "log_level = display the current log level and log options" },
b49039bd 2776 { "list_networks", wpa_cli_cmd_list_networks, NULL,
dfa141b1
ER
2777 cli_cmd_flag_none,
2778 "= list configured networks" },
b49039bd 2779 { "select_network", wpa_cli_cmd_select_network, NULL,
dfa141b1
ER
2780 cli_cmd_flag_none,
2781 "<network id> = select a network (disable others)" },
b49039bd 2782 { "enable_network", wpa_cli_cmd_enable_network, NULL,
dfa141b1
ER
2783 cli_cmd_flag_none,
2784 "<network id> = enable a network" },
b49039bd 2785 { "disable_network", wpa_cli_cmd_disable_network, NULL,
dfa141b1
ER
2786 cli_cmd_flag_none,
2787 "<network id> = disable a network" },
b49039bd 2788 { "add_network", wpa_cli_cmd_add_network, NULL,
dfa141b1
ER
2789 cli_cmd_flag_none,
2790 "= add a network" },
b49039bd 2791 { "remove_network", wpa_cli_cmd_remove_network, NULL,
dfa141b1
ER
2792 cli_cmd_flag_none,
2793 "<network id> = remove a network" },
b49039bd 2794 { "set_network", wpa_cli_cmd_set_network, NULL,
dfa141b1
ER
2795 cli_cmd_flag_sensitive,
2796 "<network id> <variable> <value> = set network variables (shows\n"
2797 " list of variables when run without arguments)" },
b49039bd 2798 { "get_network", wpa_cli_cmd_get_network, NULL,
dfa141b1
ER
2799 cli_cmd_flag_none,
2800 "<network id> <variable> = get network variables" },
1c330a2f
DS
2801 { "dup_network", wpa_cli_cmd_dup_network, NULL,
2802 cli_cmd_flag_none,
2803 "<src network id> <dst network id> <variable> = duplicate network variables"
2804 },
b49039bd 2805 { "list_creds", wpa_cli_cmd_list_creds, NULL,
d94c9ee6
JM
2806 cli_cmd_flag_none,
2807 "= list configured credentials" },
b49039bd 2808 { "add_cred", wpa_cli_cmd_add_cred, NULL,
d94c9ee6
JM
2809 cli_cmd_flag_none,
2810 "= add a credential" },
b49039bd 2811 { "remove_cred", wpa_cli_cmd_remove_cred, NULL,
d94c9ee6
JM
2812 cli_cmd_flag_none,
2813 "<cred id> = remove a credential" },
b49039bd 2814 { "set_cred", wpa_cli_cmd_set_cred, NULL,
d94c9ee6
JM
2815 cli_cmd_flag_sensitive,
2816 "<cred id> <variable> <value> = set credential variables" },
c880ab87
JM
2817 { "get_cred", wpa_cli_cmd_get_cred, NULL,
2818 cli_cmd_flag_none,
2819 "<cred id> <variable> = get credential variables" },
b49039bd 2820 { "save_config", wpa_cli_cmd_save_config, NULL,
dfa141b1
ER
2821 cli_cmd_flag_none,
2822 "= save the current configuration" },
b49039bd 2823 { "disconnect", wpa_cli_cmd_disconnect, NULL,
dfa141b1
ER
2824 cli_cmd_flag_none,
2825 "= disconnect and wait for reassociate/reconnect command before\n"
2826 " connecting" },
b49039bd 2827 { "reconnect", wpa_cli_cmd_reconnect, NULL,
dfa141b1
ER
2828 cli_cmd_flag_none,
2829 "= like reassociate, but only takes effect if already disconnected"
2830 },
b49039bd 2831 { "scan", wpa_cli_cmd_scan, NULL,
dfa141b1
ER
2832 cli_cmd_flag_none,
2833 "= request new BSS scan" },
b49039bd 2834 { "scan_results", wpa_cli_cmd_scan_results, NULL,
dfa141b1
ER
2835 cli_cmd_flag_none,
2836 "= get latest scan results" },
b49039bd 2837 { "bss", wpa_cli_cmd_bss, wpa_cli_complete_bss,
dfa141b1
ER
2838 cli_cmd_flag_none,
2839 "<<idx> | <bssid>> = get detailed scan result info" },
b49039bd 2840 { "get_capability", wpa_cli_cmd_get_capability, NULL,
dfa141b1 2841 cli_cmd_flag_none,
06060522 2842 "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels/freq/modes> "
35aa088a 2843 "= get capabilies" },
b49039bd 2844 { "reconfigure", wpa_cli_cmd_reconfigure, NULL,
dfa141b1
ER
2845 cli_cmd_flag_none,
2846 "= force wpa_supplicant to re-read its configuration file" },
b49039bd 2847 { "terminate", wpa_cli_cmd_terminate, NULL,
dfa141b1
ER
2848 cli_cmd_flag_none,
2849 "= terminate wpa_supplicant" },
b49039bd 2850 { "interface_add", wpa_cli_cmd_interface_add, NULL,
dfa141b1
ER
2851 cli_cmd_flag_none,
2852 "<ifname> <confname> <driver> <ctrl_interface> <driver_param>\n"
2853 " <bridge_name> = adds new interface, all parameters but <ifname>\n"
2854 " are optional" },
b49039bd 2855 { "interface_remove", wpa_cli_cmd_interface_remove, NULL,
dfa141b1
ER
2856 cli_cmd_flag_none,
2857 "<ifname> = removes the interface" },
b49039bd 2858 { "interface_list", wpa_cli_cmd_interface_list, NULL,
dfa141b1
ER
2859 cli_cmd_flag_none,
2860 "= list available interfaces" },
b49039bd 2861 { "ap_scan", wpa_cli_cmd_ap_scan, NULL,
dfa141b1
ER
2862 cli_cmd_flag_none,
2863 "<value> = set ap_scan parameter" },
b49039bd 2864 { "scan_interval", wpa_cli_cmd_scan_interval, NULL,
67b9bd08
DS
2865 cli_cmd_flag_none,
2866 "<value> = set scan_interval parameter (in seconds)" },
b49039bd 2867 { "bss_expire_age", wpa_cli_cmd_bss_expire_age, NULL,
78633c37
SL
2868 cli_cmd_flag_none,
2869 "<value> = set BSS expiration age parameter" },
b49039bd 2870 { "bss_expire_count", wpa_cli_cmd_bss_expire_count, NULL,
78633c37
SL
2871 cli_cmd_flag_none,
2872 "<value> = set BSS expiration scan count parameter" },
b49039bd 2873 { "bss_flush", wpa_cli_cmd_bss_flush, NULL,
39ee845f
DS
2874 cli_cmd_flag_none,
2875 "<value> = set BSS flush age (0 by default)" },
b49039bd 2876 { "stkstart", wpa_cli_cmd_stkstart, NULL,
dfa141b1
ER
2877 cli_cmd_flag_none,
2878 "<addr> = request STK negotiation with <addr>" },
b49039bd 2879 { "ft_ds", wpa_cli_cmd_ft_ds, wpa_cli_complete_bss,
dfa141b1
ER
2880 cli_cmd_flag_none,
2881 "<addr> = request over-the-DS FT with <addr>" },
b49039bd 2882 { "wps_pbc", wpa_cli_cmd_wps_pbc, wpa_cli_complete_bss,
dfa141b1
ER
2883 cli_cmd_flag_none,
2884 "[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" },
b49039bd 2885 { "wps_pin", wpa_cli_cmd_wps_pin, wpa_cli_complete_bss,
dfa141b1
ER
2886 cli_cmd_flag_sensitive,
2887 "<BSSID> [PIN] = start WPS PIN method (returns PIN, if not "
2888 "hardcoded)" },
b49039bd 2889 { "wps_check_pin", wpa_cli_cmd_wps_check_pin, NULL,
3981cb3c
JM
2890 cli_cmd_flag_sensitive,
2891 "<PIN> = verify PIN checksum" },
b49039bd 2892 { "wps_cancel", wpa_cli_cmd_wps_cancel, NULL, cli_cmd_flag_none,
2f9929ff 2893 "Cancels the pending WPS operation" },
71892384 2894#ifdef CONFIG_WPS_NFC
b49039bd 2895 { "wps_nfc", wpa_cli_cmd_wps_nfc, wpa_cli_complete_bss,
3f2c8ba6
JM
2896 cli_cmd_flag_none,
2897 "[BSSID] = start Wi-Fi Protected Setup: NFC" },
bbf41865
JM
2898 { "wps_nfc_config_token", wpa_cli_cmd_wps_nfc_config_token, NULL,
2899 cli_cmd_flag_none,
2900 "<WPS|NDEF> = build configuration token" },
b49039bd 2901 { "wps_nfc_token", wpa_cli_cmd_wps_nfc_token, NULL,
3f2c8ba6
JM
2902 cli_cmd_flag_none,
2903 "<WPS|NDEF> = create password token" },
b49039bd 2904 { "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read, NULL,
d7645d23
JM
2905 cli_cmd_flag_sensitive,
2906 "<hexdump of payload> = report read NFC tag with WPS data" },
e65552dd
JM
2907 { "nfc_get_handover_req", wpa_cli_cmd_nfc_get_handover_req, NULL,
2908 cli_cmd_flag_none,
2909 "<NDEF> <WPS> = create NFC handover request" },
2910 { "nfc_get_handover_sel", wpa_cli_cmd_nfc_get_handover_sel, NULL,
2911 cli_cmd_flag_none,
2912 "<NDEF> <WPS> = create NFC handover select" },
e4758827
JM
2913 { "nfc_report_handover", wpa_cli_cmd_nfc_report_handover, NULL,
2914 cli_cmd_flag_none,
2915 "<role> <type> <hexdump of req> <hexdump of sel> = report completed "
2916 "NFC handover" },
71892384 2917#endif /* CONFIG_WPS_NFC */
b49039bd 2918 { "wps_reg", wpa_cli_cmd_wps_reg, wpa_cli_complete_bss,
dfa141b1
ER
2919 cli_cmd_flag_sensitive,
2920 "<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
b49039bd 2921 { "wps_ap_pin", wpa_cli_cmd_wps_ap_pin, NULL,
70d84f11
JM
2922 cli_cmd_flag_sensitive,
2923 "[params..] = enable/disable AP PIN" },
b49039bd 2924 { "wps_er_start", wpa_cli_cmd_wps_er_start, NULL,
e9bcfebf 2925 cli_cmd_flag_none,
08486685 2926 "[IP address] = start Wi-Fi Protected Setup External Registrar" },
b49039bd 2927 { "wps_er_stop", wpa_cli_cmd_wps_er_stop, NULL,
e9bcfebf
JM
2928 cli_cmd_flag_none,
2929 "= stop Wi-Fi Protected Setup External Registrar" },
b49039bd 2930 { "wps_er_pin", wpa_cli_cmd_wps_er_pin, NULL,
72df2f5f
JM
2931 cli_cmd_flag_sensitive,
2932 "<UUID> <PIN> = add an Enrollee PIN to External Registrar" },
b49039bd 2933 { "wps_er_pbc", wpa_cli_cmd_wps_er_pbc, NULL,
564cd7fa
JM
2934 cli_cmd_flag_none,
2935 "<UUID> = accept an Enrollee PBC using External Registrar" },
b49039bd 2936 { "wps_er_learn", wpa_cli_cmd_wps_er_learn, NULL,
e64dcfd5
JM
2937 cli_cmd_flag_sensitive,
2938 "<UUID> <PIN> = learn AP configuration" },
b49039bd 2939 { "wps_er_set_config", wpa_cli_cmd_wps_er_set_config, NULL,
ef10f473
JM
2940 cli_cmd_flag_none,
2941 "<UUID> <network id> = set AP configuration for enrolling" },
b49039bd 2942 { "wps_er_config", wpa_cli_cmd_wps_er_config, NULL,
7d6640a6
JM
2943 cli_cmd_flag_sensitive,
2944 "<UUID> <PIN> <SSID> <auth> <encr> <key> = configure AP" },
1cea09a9 2945#ifdef CONFIG_WPS_NFC
b49039bd 2946 { "wps_er_nfc_config_token", wpa_cli_cmd_wps_er_nfc_config_token, NULL,
1cea09a9
JM
2947 cli_cmd_flag_none,
2948 "<WPS/NDEF> <UUID> = build NFC configuration token" },
2949#endif /* CONFIG_WPS_NFC */
b49039bd 2950 { "ibss_rsn", wpa_cli_cmd_ibss_rsn, NULL,
11ef8d35
JM
2951 cli_cmd_flag_none,
2952 "<addr> = request RSN authentication with <addr> in IBSS" },
e653b622 2953#ifdef CONFIG_AP
b49039bd 2954 { "sta", wpa_cli_cmd_sta, NULL,
e653b622
JM
2955 cli_cmd_flag_none,
2956 "<addr> = get information about an associated station (AP)" },
b49039bd 2957 { "all_sta", wpa_cli_cmd_all_sta, NULL,
e653b622
JM
2958 cli_cmd_flag_none,
2959 "= get information about all associated stations (AP)" },
b49039bd 2960 { "deauthenticate", wpa_cli_cmd_deauthenticate, NULL,
e60b2951
JJ
2961 cli_cmd_flag_none,
2962 "<addr> = deauthenticate a station" },
b49039bd 2963 { "disassociate", wpa_cli_cmd_disassociate, NULL,
e60b2951
JJ
2964 cli_cmd_flag_none,
2965 "<addr> = disassociate a station" },
334bf36a
AO
2966 { "chan_switch", wpa_cli_cmd_chanswitch, NULL,
2967 cli_cmd_flag_none,
2968 "<cs_count> <freq> [sec_channel_offset=] [center_freq1=]"
2969 " [center_freq2=] [bandwidth=] [blocktx] [ht|vht]"
2970 " = CSA parameters" },
e653b622 2971#endif /* CONFIG_AP */
b49039bd 2972 { "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none,
207ef3fb 2973 "= notification of suspend/hibernate" },
b49039bd 2974 { "resume", wpa_cli_cmd_resume, NULL, cli_cmd_flag_none,
207ef3fb 2975 "= notification of resume/thaw" },
9ff4de6d 2976#ifdef CONFIG_TESTING_OPTIONS
b49039bd 2977 { "drop_sa", wpa_cli_cmd_drop_sa, NULL, cli_cmd_flag_none,
32d5295f 2978 "= drop SA without deauth/disassoc (test command)" },
9ff4de6d 2979#endif /* CONFIG_TESTING_OPTIONS */
b49039bd 2980 { "roam", wpa_cli_cmd_roam, wpa_cli_complete_bss,
86d4f806
JM
2981 cli_cmd_flag_none,
2982 "<addr> = roam to the specified BSS" },
603a3f34 2983#ifdef CONFIG_MESH
5b78493f
MH
2984 { "mesh_interface_add", wpa_cli_cmd_mesh_interface_add, NULL,
2985 cli_cmd_flag_none,
2986 "[ifname] = Create a new mesh interface" },
603a3f34
JL
2987 { "mesh_group_add", wpa_cli_cmd_mesh_group_add, NULL,
2988 cli_cmd_flag_none,
2989 "<network id> = join a mesh network (disable others)" },
2990 { "mesh_group_remove", wpa_cli_cmd_mesh_group_remove, NULL,
2991 cli_cmd_flag_none,
2992 "<ifname> = Remove mesh group interface" },
2993#endif /* CONFIG_MESH */
57faa1ce 2994#ifdef CONFIG_P2P
01335e2c
JM
2995 { "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find,
2996 cli_cmd_flag_none,
57faa1ce 2997 "[timeout] [type=*] = find P2P Devices for up-to timeout seconds" },
b49039bd 2998 { "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, NULL, cli_cmd_flag_none,
57faa1ce 2999 "= stop P2P Devices search" },
f309c18e
KV
3000 { "p2p_asp_provision", wpa_cli_cmd_p2p_asp_provision, NULL,
3001 cli_cmd_flag_none,
3002 "<addr> adv_id=<adv_id> conncap=<conncap> [info=<infodata>] = provision with a P2P ASP Device" },
3003 { "p2p_asp_provision_resp", wpa_cli_cmd_p2p_asp_provision_resp, NULL,
3004 cli_cmd_flag_none,
3005 "<addr> adv_id=<adv_id> [role<conncap>] [info=<infodata>] = provision with a P2P ASP Device" },
b49039bd
JM
3006 { "p2p_connect", wpa_cli_cmd_p2p_connect, wpa_cli_complete_p2p_connect,
3007 cli_cmd_flag_none,
e2308e4b 3008 "<addr> <\"pbc\"|PIN> [ht40] = connect to a P2P Device" },
b49039bd 3009 { "p2p_listen", wpa_cli_cmd_p2p_listen, NULL, cli_cmd_flag_none,
57faa1ce 3010 "[timeout] = listen for P2P Devices for up-to timeout seconds" },
b49039bd
JM
3011 { "p2p_group_remove", wpa_cli_cmd_p2p_group_remove,
3012 wpa_cli_complete_p2p_group_remove, cli_cmd_flag_none,
4d2ea6a6 3013 "<ifname> = remove P2P group interface (terminate group if GO)" },
b49039bd 3014 { "p2p_group_add", wpa_cli_cmd_p2p_group_add, NULL, cli_cmd_flag_none,
7aeac985 3015 "[ht40] = add a new P2P group (local end as GO)" },
b49039bd
JM
3016 { "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc,
3017 wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
57faa1ce 3018 "<addr> <method> = request provisioning discovery" },
b49039bd 3019 { "p2p_get_passphrase", wpa_cli_cmd_p2p_get_passphrase, NULL,
57faa1ce
JM
3020 cli_cmd_flag_none,
3021 "= get the passphrase for a group (GO only)" },
3022 { "p2p_serv_disc_req", wpa_cli_cmd_p2p_serv_disc_req,
b49039bd 3023 wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
57faa1ce
JM
3024 "<addr> <TLVs> = schedule service discovery request" },
3025 { "p2p_serv_disc_cancel_req", wpa_cli_cmd_p2p_serv_disc_cancel_req,
b49039bd 3026 NULL, cli_cmd_flag_none,
57faa1ce 3027 "<id> = cancel pending service discovery request" },
b49039bd 3028 { "p2p_serv_disc_resp", wpa_cli_cmd_p2p_serv_disc_resp, NULL,
57faa1ce
JM
3029 cli_cmd_flag_none,
3030 "<freq> <addr> <dialog token> <TLVs> = service discovery response" },
b49039bd 3031 { "p2p_service_update", wpa_cli_cmd_p2p_service_update, NULL,
57faa1ce
JM
3032 cli_cmd_flag_none,
3033 "= indicate change in local services" },
b49039bd 3034 { "p2p_serv_disc_external", wpa_cli_cmd_p2p_serv_disc_external, NULL,
57faa1ce
JM
3035 cli_cmd_flag_none,
3036 "<external> = set external processing of service discovery" },
b49039bd 3037 { "p2p_service_flush", wpa_cli_cmd_p2p_service_flush, NULL,
57faa1ce
JM
3038 cli_cmd_flag_none,
3039 "= remove all stored service entries" },
b49039bd 3040 { "p2p_service_add", wpa_cli_cmd_p2p_service_add, NULL,
57faa1ce 3041 cli_cmd_flag_none,
ae9d45f3 3042 "<bonjour|upnp|asp> <query|version> <response|service> = add a local "
57faa1ce 3043 "service" },
ae9d45f3
KV
3044 { "p2p_service_rep", wpa_cli_cmd_p2p_service_rep, NULL,
3045 cli_cmd_flag_none,
3046 "asp <auto> <adv_id> <svc_state> <svc_string> [<svc_info>] = replace "
3047 "local ASP service" },
b49039bd 3048 { "p2p_service_del", wpa_cli_cmd_p2p_service_del, NULL,
57faa1ce
JM
3049 cli_cmd_flag_none,
3050 "<bonjour|upnp> <query|version> [|service] = remove a local "
3051 "service" },
b49039bd 3052 { "p2p_reject", wpa_cli_cmd_p2p_reject, wpa_cli_complete_p2p_peer,
57faa1ce
JM
3053 cli_cmd_flag_none,
3054 "<addr> = reject connection attempts from a specific peer" },
b49039bd 3055 { "p2p_invite", wpa_cli_cmd_p2p_invite, NULL,
57faa1ce
JM
3056 cli_cmd_flag_none,
3057 "<cmd> [peer=addr] = invite peer" },
b49039bd 3058 { "p2p_peers", wpa_cli_cmd_p2p_peers, NULL, cli_cmd_flag_none,
57faa1ce
JM
3059 "[discovered] = list known (optionally, only fully discovered) P2P "
3060 "peers" },
b49039bd
JM
3061 { "p2p_peer", wpa_cli_cmd_p2p_peer, wpa_cli_complete_p2p_peer,
3062 cli_cmd_flag_none,
57faa1ce 3063 "<address> = show information about known P2P peer" },
698e921b
JM
3064 { "p2p_set", wpa_cli_cmd_p2p_set, wpa_cli_complete_p2p_set,
3065 cli_cmd_flag_none,
57faa1ce 3066 "<field> <value> = set a P2P parameter" },
b49039bd 3067 { "p2p_flush", wpa_cli_cmd_p2p_flush, NULL, cli_cmd_flag_none,
57faa1ce 3068 "= flush P2P state" },
b49039bd 3069 { "p2p_cancel", wpa_cli_cmd_p2p_cancel, NULL, cli_cmd_flag_none,
59eba7a2 3070 "= cancel P2P group formation" },
b49039bd
JM
3071 { "p2p_unauthorize", wpa_cli_cmd_p2p_unauthorize,
3072 wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
9d562b79 3073 "<address> = unauthorize a peer" },
b49039bd
JM
3074 { "p2p_presence_req", wpa_cli_cmd_p2p_presence_req, NULL,
3075 cli_cmd_flag_none,
57faa1ce
JM
3076 "[<duration> <interval>] [<duration> <interval>] = request GO "
3077 "presence" },
b49039bd
JM
3078 { "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, NULL,
3079 cli_cmd_flag_none,
57faa1ce 3080 "[<period> <interval>] = set extended listen timing" },
f2c56602
JM
3081 { "p2p_remove_client", wpa_cli_cmd_p2p_remove_client,
3082 wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
3083 "<address|iface=address> = remove a peer from all groups" },
57faa1ce 3084#endif /* CONFIG_P2P */
9675ce35
JM
3085#ifdef CONFIG_WIFI_DISPLAY
3086 { "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL,
3087 cli_cmd_flag_none,
3088 "<subelem> [contents] = set Wi-Fi Display subelement" },
3089 { "wfd_subelem_get", wpa_cli_cmd_wfd_subelem_get, NULL,
3090 cli_cmd_flag_none,
3091 "<subelem> = get Wi-Fi Display subelement" },
3092#endif /* CONFIG_WIFI_DISPLAY */
afc064fe 3093#ifdef CONFIG_INTERWORKING
b49039bd 3094 { "fetch_anqp", wpa_cli_cmd_fetch_anqp, NULL, cli_cmd_flag_none,
afc064fe 3095 "= fetch ANQP information for all APs" },
b49039bd
JM
3096 { "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, NULL,
3097 cli_cmd_flag_none,
afc064fe 3098 "= stop fetch_anqp operation" },
b49039bd 3099 { "interworking_select", wpa_cli_cmd_interworking_select, NULL,
b02fe7ff
JM
3100 cli_cmd_flag_none,
3101 "[auto] = perform Interworking network selection" },
3102 { "interworking_connect", wpa_cli_cmd_interworking_connect,
b49039bd 3103 wpa_cli_complete_bss, cli_cmd_flag_none,
b02fe7ff 3104 "<BSSID> = connect using Interworking credentials" },
f91a512f
JM
3105 { "interworking_add_network", wpa_cli_cmd_interworking_add_network,
3106 wpa_cli_complete_bss, cli_cmd_flag_none,
3107 "<BSSID> = connect using Interworking credentials" },
b49039bd
JM
3108 { "anqp_get", wpa_cli_cmd_anqp_get, wpa_cli_complete_bss,
3109 cli_cmd_flag_none,
afc064fe 3110 "<addr> <info id>[,<info id>]... = request ANQP information" },
b1f12296
JM
3111 { "gas_request", wpa_cli_cmd_gas_request, wpa_cli_complete_bss,
3112 cli_cmd_flag_none,
3113 "<addr> <AdvProtoID> [QueryReq] = GAS request" },
3114 { "gas_response_get", wpa_cli_cmd_gas_response_get,
3115 wpa_cli_complete_bss, cli_cmd_flag_none,
3116 "<addr> <dialog token> [start,len] = Fetch last GAS response" },
afc064fe 3117#endif /* CONFIG_INTERWORKING */
a8918e86 3118#ifdef CONFIG_HS20
b49039bd
JM
3119 { "hs20_anqp_get", wpa_cli_cmd_hs20_anqp_get, wpa_cli_complete_bss,
3120 cli_cmd_flag_none,
a8918e86
JK
3121 "<addr> <subtype>[,<subtype>]... = request HS 2.0 ANQP information"
3122 },
3123 { "nai_home_realm_list", wpa_cli_cmd_get_nai_home_realm_list,
b49039bd 3124 wpa_cli_complete_bss, cli_cmd_flag_none,
a8918e86 3125 "<addr> <home realm> = get HS20 nai home realm list" },
184e110c
JM
3126 { "hs20_icon_request", wpa_cli_cmd_hs20_icon_request,
3127 wpa_cli_complete_bss, cli_cmd_flag_none,
3128 "<addr> <icon name> = get Hotspot 2.0 OSU icon" },
b572df86
JM
3129 { "fetch_osu", wpa_cli_cmd_fetch_osu, NULL, cli_cmd_flag_none,
3130 "= fetch OSU provider information from all APs" },
3131 { "cancel_fetch_osu", wpa_cli_cmd_cancel_fetch_osu, NULL,
3132 cli_cmd_flag_none,
3133 "= cancel fetch_osu command" },
a8918e86 3134#endif /* CONFIG_HS20 */
b49039bd
JM
3135 { "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, NULL,
3136 cli_cmd_flag_none,
0d0a8ca1 3137 "<0/1> = disable/enable automatic reconnection" },
b49039bd 3138 { "tdls_discover", wpa_cli_cmd_tdls_discover, NULL,
281ff0aa
GP
3139 cli_cmd_flag_none,
3140 "<addr> = request TDLS discovery with <addr>" },
b49039bd 3141 { "tdls_setup", wpa_cli_cmd_tdls_setup, NULL,
281ff0aa
GP
3142 cli_cmd_flag_none,
3143 "<addr> = request TDLS setup with <addr>" },
b49039bd 3144 { "tdls_teardown", wpa_cli_cmd_tdls_teardown, NULL,
281ff0aa
GP
3145 cli_cmd_flag_none,
3146 "<addr> = tear down TDLS with <addr>" },
df9d340c
MB
3147 { "wmm_ac_addts", wpa_cli_cmd_wmm_ac_addts, NULL,
3148 cli_cmd_flag_none,
3149 "<uplink/downlink/bidi> <tsid=0..7> <up=0..7> [nominal_msdu_size=#] "
3150 "[mean_data_rate=#] [min_phy_rate=#] [sba=#] [fixed_nominal_msdu] "
3151 "= add WMM-AC traffic stream" },
3152 { "wmm_ac_delts", wpa_cli_cmd_wmm_ac_delts, NULL,
3153 cli_cmd_flag_none,
3154 "<tsid> = delete WMM-AC traffic stream" },
8506ea6f
MB
3155 { "wmm_ac_status", wpa_cli_cmd_wmm_ac_status, NULL,
3156 cli_cmd_flag_none,
3157 "= show status for Wireless Multi-Media Admission-Control" },
7db53bb8
AN
3158 { "tdls_chan_switch", wpa_cli_cmd_tdls_chan_switch, NULL,
3159 cli_cmd_flag_none,
3160 "<addr> <oper class> <freq> [sec_channel_offset=] [center_freq1=] "
3161 "[center_freq2=] [bandwidth=] [ht|vht] = enable channel switching "
3162 "with TDLS peer" },
3163 { "tdls_cancel_chan_switch", wpa_cli_cmd_tdls_cancel_chan_switch, NULL,
3164 cli_cmd_flag_none,
3165 "<addr> = disable channel switching with TDLS peer <addr>" },
b49039bd 3166 { "signal_poll", wpa_cli_cmd_signal_poll, NULL,
60b24b0d
DS
3167 cli_cmd_flag_none,
3168 "= get signal parameters" },
dc7785f8
YZ
3169 { "pktcnt_poll", wpa_cli_cmd_pktcnt_poll, NULL,
3170 cli_cmd_flag_none,
3171 "= get TX/RX packet counters" },
b49039bd
JM
3172 { "reauthenticate", wpa_cli_cmd_reauthenticate, NULL,
3173 cli_cmd_flag_none,
9482426e 3174 "= trigger IEEE 802.1X/EAPOL reauthentication" },
2bdd8342 3175#ifdef CONFIG_AUTOSCAN
b49039bd 3176 { "autoscan", wpa_cli_cmd_autoscan, NULL, cli_cmd_flag_none,
2bdd8342
TB
3177 "[params] = Set or unset (if none) autoscan parameters" },
3178#endif /* CONFIG_AUTOSCAN */
e9199e31
JM
3179#ifdef CONFIG_WNM
3180 { "wnm_sleep", wpa_cli_cmd_wnm_sleep, NULL, cli_cmd_flag_none,
3181 "<enter/exit> [interval=#] = enter/exit WNM-Sleep mode" },
65bcd0a9
VK
3182 { "wnm_bss_query", wpa_cli_cmd_wnm_bss_query, NULL, cli_cmd_flag_none,
3183 "<query reason> = Send BSS Transition Management Query" },
e9199e31 3184#endif /* CONFIG_WNM */
b49039bd 3185 { "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive,
27b80b5b 3186 "<params..> = Sent unprocessed command" },
acb54643
JM
3187 { "flush", wpa_cli_cmd_flush, NULL, cli_cmd_flag_none,
3188 "= flush wpa_supplicant state" },
5e2c3490
JM
3189#ifdef ANDROID
3190 { "driver", wpa_cli_cmd_driver, NULL, cli_cmd_flag_none,
3191 "<command> = driver private commands" },
3192#endif /* ANDROID */
1f965e62
JM
3193 { "radio_work", wpa_cli_cmd_radio_work, NULL, cli_cmd_flag_none,
3194 "= radio_work <show/add/done>" },
adef8948
BL
3195 { "vendor", wpa_cli_cmd_vendor, NULL, cli_cmd_flag_none,
3196 "<vendor id> <command id> [<hex formatted command argument>] = Send vendor command"
3197 },
66d21434
AK
3198 { "neighbor_rep_request",
3199 wpa_cli_cmd_neighbor_rep_request, NULL, cli_cmd_flag_none,
3200 "[ssid=<SSID>] = Trigger request to AP for neighboring AP report "
3201 "(with optional given SSID, default: current SSID)"
3202 },
65d9a5e2
JM
3203 { "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none,
3204 "= flush ERP keys" },
8b48e320
IP
3205 { "mac_rand_scan",
3206 wpa_cli_cmd_mac_rand_scan, NULL, cli_cmd_flag_none,
3207 "<scan|sched|pno|all> enable=<0/1> [addr=mac-address "
3208 "mask=mac-address-mask] = scan MAC randomization"
3209 },
b49039bd 3210 { NULL, NULL, NULL, cli_cmd_flag_none, NULL }
6fc6879b
JM
3211};
3212
3213
dfa141b1
ER
3214/*
3215 * Prints command usage, lines are padded with the specified string.
3216 */
3217static void print_cmd_help(struct wpa_cli_cmd *cmd, const char *pad)
3218{
3219 char c;
3220 size_t n;
3221
3222 printf("%s%s ", pad, cmd->cmd);
3223 for (n = 0; (c = cmd->usage[n]); n++) {
3224 printf("%c", c);
3225 if (c == '\n')
3226 printf("%s", pad);
3227 }
3228 printf("\n");
3229}
3230
3231
2af4d404 3232static void print_help(const char *cmd)
dfa141b1
ER
3233{
3234 int n;
3235 printf("commands:\n");
2af4d404
JM
3236 for (n = 0; wpa_cli_commands[n].cmd; n++) {
3237 if (cmd == NULL || str_starts(wpa_cli_commands[n].cmd, cmd))
3238 print_cmd_help(&wpa_cli_commands[n], " ");
3239 }
dfa141b1
ER
3240}
3241
3242
e8ecb5fb 3243static int wpa_cli_edit_filter_history_cb(void *ctx, const char *cmd)
40fd868c
ER
3244{
3245 const char *c, *delim;
3246 int n;
3247 size_t len;
3248
3249 delim = os_strchr(cmd, ' ');
3250 if (delim)
3251 len = delim - cmd;
3252 else
3253 len = os_strlen(cmd);
3254
3255 for (n = 0; (c = wpa_cli_commands[n].cmd); n++) {
3256 if (os_strncasecmp(cmd, c, len) == 0 && len == os_strlen(c))
3257 return (wpa_cli_commands[n].flags &
3258 cli_cmd_flag_sensitive);
3259 }
3260 return 0;
3261}
e8ecb5fb
JM
3262
3263
3264static char ** wpa_list_cmd_list(void)
3265{
3266 char **res;
3267 int i, count;
37620493 3268 struct cli_txt_entry *e;
e8ecb5fb 3269
e7ecab4a 3270 count = ARRAY_SIZE(wpa_cli_commands);
37620493
JM
3271 count += dl_list_len(&p2p_groups);
3272 count += dl_list_len(&ifnames);
3273 res = os_calloc(count + 1, sizeof(char *));
e8ecb5fb
JM
3274 if (res == NULL)
3275 return NULL;
3276
3277 for (i = 0; wpa_cli_commands[i].cmd; i++) {
3278 res[i] = os_strdup(wpa_cli_commands[i].cmd);
3279 if (res[i] == NULL)
3280 break;
3281 }
3282
37620493
JM
3283 dl_list_for_each(e, &p2p_groups, struct cli_txt_entry, list) {
3284 size_t len = 8 + os_strlen(e->txt);
3285 res[i] = os_malloc(len);
3286 if (res[i] == NULL)
3287 break;
3288 os_snprintf(res[i], len, "ifname=%s", e->txt);
3289 i++;
3290 }
3291
3292 dl_list_for_each(e, &ifnames, struct cli_txt_entry, list) {
3293 res[i] = os_strdup(e->txt);
3294 if (res[i] == NULL)
3295 break;
3296 i++;
3297 }
3298
e8ecb5fb
JM
3299 return res;
3300}
3301
3302
3303static char ** wpa_cli_cmd_completion(const char *cmd, const char *str,
3304 int pos)
3305{
3306 int i;
3307
3308 for (i = 0; wpa_cli_commands[i].cmd; i++) {
3309 if (os_strcasecmp(wpa_cli_commands[i].cmd, cmd) == 0) {
e4f6873c
JM
3310 if (wpa_cli_commands[i].completion)
3311 return wpa_cli_commands[i].completion(str,
3312 pos);
e8ecb5fb
JM
3313 edit_clear_line();
3314 printf("\r%s\n", wpa_cli_commands[i].usage);
3315 edit_redraw();
3316 break;
3317 }
3318 }
3319
3320 return NULL;
3321}
3322
3323
3324static char ** wpa_cli_edit_completion_cb(void *ctx, const char *str, int pos)
3325{
3326 char **res;
3327 const char *end;
3328 char *cmd;
3329
37620493
JM
3330 if (pos > 7 && os_strncasecmp(str, "IFNAME=", 7) == 0) {
3331 end = os_strchr(str, ' ');
3332 if (end && pos > end - str) {
3333 pos -= end - str + 1;
3334 str = end + 1;
3335 }
3336 }
3337
e8ecb5fb
JM
3338 end = os_strchr(str, ' ');
3339 if (end == NULL || str + pos < end)
3340 return wpa_list_cmd_list();
3341
3342 cmd = os_malloc(pos + 1);
3343 if (cmd == NULL)
3344 return NULL;
3345 os_memcpy(cmd, str, pos);
3346 cmd[end - str] = '\0';
3347 res = wpa_cli_cmd_completion(cmd, str, pos);
3348 os_free(cmd);
3349 return res;
3350}
40fd868c
ER
3351
3352
6fc6879b
JM
3353static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
3354{
3355 struct wpa_cli_cmd *cmd, *match = NULL;
3356 int count;
3357 int ret = 0;
3358
13b11ba7
JM
3359 if (argc > 1 && os_strncasecmp(argv[0], "IFNAME=", 7) == 0) {
3360 ifname_prefix = argv[0] + 7;
3361 argv = &argv[1];
3362 argc--;
3363 } else
3364 ifname_prefix = NULL;
3365
3366 if (argc == 0)
3367 return -1;
3368
6fc6879b
JM
3369 count = 0;
3370 cmd = wpa_cli_commands;
3371 while (cmd->cmd) {
3372 if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0)
3373 {
3374 match = cmd;
3375 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
3376 /* we have an exact match */
3377 count = 1;
3378 break;
3379 }
3380 count++;
3381 }
3382 cmd++;
3383 }
3384
3385 if (count > 1) {
3386 printf("Ambiguous command '%s'; possible commands:", argv[0]);
3387 cmd = wpa_cli_commands;
3388 while (cmd->cmd) {
3389 if (os_strncasecmp(cmd->cmd, argv[0],
3390 os_strlen(argv[0])) == 0) {
3391 printf(" %s", cmd->cmd);
3392 }
3393 cmd++;
3394 }
3395 printf("\n");
3396 ret = 1;
3397 } else if (count == 0) {
3398 printf("Unknown command '%s'\n", argv[0]);
3399 ret = 1;
3400 } else {
3401 ret = match->handler(ctrl, argc - 1, &argv[1]);
3402 }
3403
3404 return ret;
3405}
3406
3407
3408static int str_match(const char *a, const char *b)
3409{
3410 return os_strncmp(a, b, os_strlen(b)) == 0;
3411}
3412
3413
3414static int wpa_cli_exec(const char *program, const char *arg1,
3415 const char *arg2)
3416{
c5f258de 3417 char *arg;
6fc6879b
JM
3418 size_t len;
3419 int res;
3420
c5f258de
JM
3421 len = os_strlen(arg1) + os_strlen(arg2) + 2;
3422 arg = os_malloc(len);
3423 if (arg == NULL)
6fc6879b 3424 return -1;
c5f258de
JM
3425 os_snprintf(arg, len, "%s %s", arg1, arg2);
3426 res = os_exec(program, arg, 1);
3427 os_free(arg);
6fc6879b 3428
c5f258de 3429 return res;
6fc6879b
JM
3430}
3431
3432
3433static void wpa_cli_action_process(const char *msg)
3434{
3435 const char *pos;
3436 char *copy = NULL, *id, *pos2;
55c2bfa9
JM
3437 const char *ifname = ctrl_ifname;
3438 char ifname_buf[100];
6fc6879b
JM
3439
3440 pos = msg;
55c2bfa9
JM
3441 if (os_strncmp(pos, "IFNAME=", 7) == 0) {
3442 const char *end;
3443 end = os_strchr(pos + 7, ' ');
3444 if (end && (unsigned int) (end - pos) < sizeof(ifname_buf)) {
3445 pos += 7;
3446 os_memcpy(ifname_buf, pos, end - pos);
3447 ifname_buf[end - pos] = '\0';
3448 ifname = ifname_buf;
3449 pos = end + 1;
3450 }
3451 }
6fc6879b 3452 if (*pos == '<') {
55c2bfa9 3453 const char *prev = pos;
6fc6879b
JM
3454 /* skip priority */
3455 pos = os_strchr(pos, '>');
3456 if (pos)
3457 pos++;
3458 else
55c2bfa9 3459 pos = prev;
6fc6879b
JM
3460 }
3461
3462 if (str_match(pos, WPA_EVENT_CONNECTED)) {
3463 int new_id = -1;
3464 os_unsetenv("WPA_ID");
3465 os_unsetenv("WPA_ID_STR");
3466 os_unsetenv("WPA_CTRL_DIR");
3467
3468 pos = os_strstr(pos, "[id=");
3469 if (pos)
3470 copy = os_strdup(pos + 4);
3471
3472 if (copy) {
3473 pos2 = id = copy;
3474 while (*pos2 && *pos2 != ' ')
3475 pos2++;
3476 *pos2++ = '\0';
3477 new_id = atoi(id);
3478 os_setenv("WPA_ID", id, 1);
3479 while (*pos2 && *pos2 != '=')
3480 pos2++;
3481 if (*pos2 == '=')
3482 pos2++;
3483 id = pos2;
3484 while (*pos2 && *pos2 != ']')
3485 pos2++;
3486 *pos2 = '\0';
3487 os_setenv("WPA_ID_STR", id, 1);
3488 os_free(copy);
3489 }
3490
3491 os_setenv("WPA_CTRL_DIR", ctrl_iface_dir, 1);
3492
02a3e5c0 3493 if (wpa_cli_connected <= 0 || new_id != wpa_cli_last_id) {
6fc6879b
JM
3494 wpa_cli_connected = 1;
3495 wpa_cli_last_id = new_id;
55c2bfa9 3496 wpa_cli_exec(action_file, ifname, "CONNECTED");
6fc6879b
JM
3497 }
3498 } else if (str_match(pos, WPA_EVENT_DISCONNECTED)) {
3499 if (wpa_cli_connected) {
3500 wpa_cli_connected = 0;
55c2bfa9 3501 wpa_cli_exec(action_file, ifname, "DISCONNECTED");
6fc6879b 3502 }
44a1662a
MH
3503 } else if (str_match(pos, MESH_GROUP_STARTED)) {
3504 wpa_cli_exec(action_file, ctrl_ifname, pos);
3505 } else if (str_match(pos, MESH_GROUP_REMOVED)) {
3506 wpa_cli_exec(action_file, ctrl_ifname, pos);
3507 } else if (str_match(pos, MESH_PEER_CONNECTED)) {
3508 wpa_cli_exec(action_file, ctrl_ifname, pos);
3509 } else if (str_match(pos, MESH_PEER_DISCONNECTED)) {
3510 wpa_cli_exec(action_file, ctrl_ifname, pos);
42f0101b 3511 } else if (str_match(pos, P2P_EVENT_GROUP_STARTED)) {
55c2bfa9 3512 wpa_cli_exec(action_file, ifname, pos);
42f0101b 3513 } else if (str_match(pos, P2P_EVENT_GROUP_REMOVED)) {
55c2bfa9 3514 wpa_cli_exec(action_file, ifname, pos);
72044390 3515 } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) {
55c2bfa9 3516 wpa_cli_exec(action_file, ifname, pos);
72044390 3517 } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) {
55c2bfa9 3518 wpa_cli_exec(action_file, ifname, pos);
e670738a 3519 } else if (str_match(pos, P2P_EVENT_GO_NEG_FAILURE)) {
55c2bfa9 3520 wpa_cli_exec(action_file, ifname, pos);
876103dc 3521 } else if (str_match(pos, WPS_EVENT_SUCCESS)) {
55c2bfa9 3522 wpa_cli_exec(action_file, ifname, pos);
876103dc 3523 } else if (str_match(pos, WPS_EVENT_FAIL)) {
55c2bfa9 3524 wpa_cli_exec(action_file, ifname, pos);
653c4893 3525 } else if (str_match(pos, AP_STA_CONNECTED)) {
55c2bfa9 3526 wpa_cli_exec(action_file, ifname, pos);
653c4893 3527 } else if (str_match(pos, AP_STA_DISCONNECTED)) {
55c2bfa9 3528 wpa_cli_exec(action_file, ifname, pos);
ae8535b6 3529 } else if (str_match(pos, ESS_DISASSOC_IMMINENT)) {
55c2bfa9 3530 wpa_cli_exec(action_file, ifname, pos);
95a3ea94 3531 } else if (str_match(pos, HS20_SUBSCRIPTION_REMEDIATION)) {
55c2bfa9 3532 wpa_cli_exec(action_file, ifname, pos);
7ef69479 3533 } else if (str_match(pos, HS20_DEAUTH_IMMINENT_NOTICE)) {
55c2bfa9 3534 wpa_cli_exec(action_file, ifname, pos);
6fc6879b
JM
3535 } else if (str_match(pos, WPA_EVENT_TERMINATING)) {
3536 printf("wpa_supplicant is terminating - stop monitoring\n");
3537 wpa_cli_quit = 1;
3538 }
3539}
3540
3541
3542#ifndef CONFIG_ANSI_C_EXTRA
3543static void wpa_cli_action_cb(char *msg, size_t len)
3544{
3545 wpa_cli_action_process(msg);
3546}
3547#endif /* CONFIG_ANSI_C_EXTRA */
3548
3549
3550static void wpa_cli_reconnect(void)
3551{
3552 wpa_cli_close_connection();
059d3a90
JM
3553 if (wpa_cli_open_connection(ctrl_ifname, 1) < 0)
3554 return;
3555
3556 if (interactive) {
3557 edit_clear_line();
3558 printf("\rConnection to wpa_supplicant re-established\n");
3559 edit_redraw();
3560 }
6fc6879b
JM
3561}
3562
3563
a624f20b
JM
3564static void cli_event(const char *str)
3565{
3566 const char *start, *s;
3567
3568 start = os_strchr(str, '>');
3569 if (start == NULL)
3570 return;
3571
3572 start++;
3573
3574 if (str_starts(start, WPA_EVENT_BSS_ADDED)) {
3575 s = os_strchr(start, ' ');
3576 if (s == NULL)
3577 return;
3578 s = os_strchr(s + 1, ' ');
3579 if (s == NULL)
3580 return;
3581 cli_txt_list_add(&bsses, s + 1);
3582 return;
3583 }
3584
3585 if (str_starts(start, WPA_EVENT_BSS_REMOVED)) {
3586 s = os_strchr(start, ' ');
3587 if (s == NULL)
3588 return;
3589 s = os_strchr(s + 1, ' ');
3590 if (s == NULL)
3591 return;
3592 cli_txt_list_del_addr(&bsses, s + 1);
3593 return;
3594 }
3595
3596#ifdef CONFIG_P2P
3597 if (str_starts(start, P2P_EVENT_DEVICE_FOUND)) {
3598 s = os_strstr(start, " p2p_dev_addr=");
3599 if (s == NULL)
3600 return;
3601 cli_txt_list_add_addr(&p2p_peers, s + 14);
3602 return;
3603 }
3604
3605 if (str_starts(start, P2P_EVENT_DEVICE_LOST)) {
3606 s = os_strstr(start, " p2p_dev_addr=");
3607 if (s == NULL)
3608 return;
3609 cli_txt_list_del_addr(&p2p_peers, s + 14);
3610 return;
3611 }
76788542
JM
3612
3613 if (str_starts(start, P2P_EVENT_GROUP_STARTED)) {
3614 s = os_strchr(start, ' ');
3615 if (s == NULL)
3616 return;
3617 cli_txt_list_add_word(&p2p_groups, s + 1);
3618 return;
3619 }
3620
3621 if (str_starts(start, P2P_EVENT_GROUP_REMOVED)) {
3622 s = os_strchr(start, ' ');
3623 if (s == NULL)
3624 return;
3625 cli_txt_list_del_word(&p2p_groups, s + 1);
3626 return;
3627 }
a624f20b
JM
3628#endif /* CONFIG_P2P */
3629}
3630
3631
059d3a90
JM
3632static int check_terminating(const char *msg)
3633{
3634 const char *pos = msg;
3635
3636 if (*pos == '<') {
3637 /* skip priority */
3638 pos = os_strchr(pos, '>');
3639 if (pos)
3640 pos++;
3641 else
3642 pos = msg;
3643 }
3644
3645 if (str_match(pos, WPA_EVENT_TERMINATING) && ctrl_conn) {
3646 edit_clear_line();
3647 printf("\rConnection to wpa_supplicant lost - trying to "
3648 "reconnect\n");
3649 edit_redraw();
3650 wpa_cli_attached = 0;
3651 wpa_cli_close_connection();
3652 return 1;
3653 }
3654
3655 return 0;
3656}
3657
3658
cd101567 3659static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor)
6fc6879b 3660{
6fc6879b
JM
3661 if (ctrl_conn == NULL) {
3662 wpa_cli_reconnect();
3663 return;
3664 }
3665 while (wpa_ctrl_pending(ctrl) > 0) {
063f8504 3666 char buf[4096];
6fc6879b
JM
3667 size_t len = sizeof(buf) - 1;
3668 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
3669 buf[len] = '\0';
3670 if (action_monitor)
3671 wpa_cli_action_process(buf);
3672 else {
a624f20b 3673 cli_event(buf);
f3f0f648 3674 if (wpa_cli_show_event(buf)) {
82a855bd 3675 edit_clear_line();
cd101567 3676 printf("\r%s\n", buf);
bdc45634 3677 edit_redraw();
f3f0f648 3678 }
059d3a90
JM
3679
3680 if (interactive && check_terminating(buf) > 0)
3681 return;
6fc6879b
JM
3682 }
3683 } else {
3684 printf("Could not read pending message.\n");
3685 break;
3686 }
3687 }
3688
3689 if (wpa_ctrl_pending(ctrl) < 0) {
3690 printf("Connection to wpa_supplicant lost - trying to "
3691 "reconnect\n");
3692 wpa_cli_reconnect();
3693 }
3694}
3695
6f1c6549
JM
3696#define max_args 10
3697
3698static int tokenize_cmd(char *cmd, char *argv[])
3699{
3700 char *pos;
3701 int argc = 0;
3702
3703 pos = cmd;
3704 for (;;) {
3705 while (*pos == ' ')
3706 pos++;
3707 if (*pos == '\0')
3708 break;
3709 argv[argc] = pos;
3710 argc++;
3711 if (argc == max_args)
3712 break;
3713 if (*pos == '"') {
3714 char *pos2 = os_strrchr(pos, '"');
3715 if (pos2)
3716 pos = pos2 + 1;
3717 }
3718 while (*pos != '\0' && *pos != ' ')
3719 pos++;
3720 if (*pos == ' ')
3721 *pos++ = '\0';
3722 }
3723
3724 return argc;
3725}
3726
3727
cd101567
JM
3728static void wpa_cli_ping(void *eloop_ctx, void *timeout_ctx)
3729{
fa0e9176
JM
3730 if (ctrl_conn) {
3731 int res;
3732 char *prefix = ifname_prefix;
3733
3734 ifname_prefix = NULL;
3735 res = _wpa_ctrl_command(ctrl_conn, "PING", 0);
3736 ifname_prefix = prefix;
3737 if (res) {
3738 printf("Connection to wpa_supplicant lost - trying to "
3739 "reconnect\n");
3740 wpa_cli_close_connection();
3741 }
cd101567
JM
3742 }
3743 if (!ctrl_conn)
3744 wpa_cli_reconnect();
3745 eloop_register_timeout(ping_interval, 0, wpa_cli_ping, NULL, NULL);
3746}
3747
3748
cd101567
JM
3749static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx)
3750{
3751 wpa_cli_recv_pending(mon_conn, 0);
3752}
3753
3754
82a855bd 3755static void wpa_cli_edit_cmd_cb(void *ctx, char *cmd)
aee680e8
JM
3756{
3757 char *argv[max_args];
3758 int argc;
82a855bd 3759 argc = tokenize_cmd(cmd, argv);
aee680e8
JM
3760 if (argc)
3761 wpa_request(ctrl_conn, argc, argv);
aee680e8
JM
3762}
3763
3764
82a855bd 3765static void wpa_cli_edit_eof_cb(void *ctx)
6f1c6549 3766{
82a855bd 3767 eloop_terminate();
cd101567
JM
3768}
3769
3770
4be9f275
JM
3771static int warning_displayed = 0;
3772static char *hfile = NULL;
3773static int edit_started = 0;
aee680e8 3774
4be9f275
JM
3775static void start_edit(void)
3776{
3777 char *home;
db3a0322
JM
3778 char *ps = NULL;
3779
3780#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
3781 ps = wpa_ctrl_get_remote_ifname(ctrl_conn);
3782#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
cd101567 3783
ba87329d
MK
3784#ifdef CONFIG_WPA_CLI_HISTORY_DIR
3785 home = CONFIG_WPA_CLI_HISTORY_DIR;
3786#else /* CONFIG_WPA_CLI_HISTORY_DIR */
8953e968 3787 home = getenv("HOME");
ba87329d 3788#endif /* CONFIG_WPA_CLI_HISTORY_DIR */
8953e968
JM
3789 if (home) {
3790 const char *fname = ".wpa_cli_history";
3791 int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
3792 hfile = os_malloc(hfile_len);
3793 if (hfile)
3794 os_snprintf(hfile, hfile_len, "%s/%s", home, fname);
3795 }
3796
4be9f275 3797 if (edit_init(wpa_cli_edit_cmd_cb, wpa_cli_edit_eof_cb,
db3a0322 3798 wpa_cli_edit_completion_cb, NULL, hfile, ps) < 0) {
4be9f275
JM
3799 eloop_terminate();
3800 return;
3801 }
3802
3803 edit_started = 1;
cd101567 3804 eloop_register_timeout(ping_interval, 0, wpa_cli_ping, NULL, NULL);
4be9f275
JM
3805}
3806
3807
9be37143
JM
3808static void update_bssid_list(struct wpa_ctrl *ctrl)
3809{
3810 char buf[4096];
3811 size_t len = sizeof(buf);
3812 int ret;
3813 char *cmd = "BSS RANGE=ALL MASK=0x2";
3814 char *pos, *end;
3815
3816 if (ctrl == NULL)
3817 return;
3818 ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL);
3819 if (ret < 0)
3820 return;
3821 buf[len] = '\0';
3822
3823 pos = buf;
3824 while (pos) {
3825 pos = os_strstr(pos, "bssid=");
3826 if (pos == NULL)
3827 break;
3828 pos += 6;
3829 end = os_strchr(pos, '\n');
3830 if (end == NULL)
3831 break;
3832 *end = '\0';
3833 cli_txt_list_add(&bsses, pos);
3834 pos = end + 1;
3835 }
3836}
3837
3838
37620493
JM
3839static void update_ifnames(struct wpa_ctrl *ctrl)
3840{
3841 char buf[4096];
3842 size_t len = sizeof(buf);
3843 int ret;
3844 char *cmd = "INTERFACES";
3845 char *pos, *end;
3846 char txt[200];
3847
3848 cli_txt_list_flush(&ifnames);
3849
3850 if (ctrl == NULL)
3851 return;
3852 ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL);
3853 if (ret < 0)
3854 return;
3855 buf[len] = '\0';
3856
3857 pos = buf;
3858 while (pos) {
3859 end = os_strchr(pos, '\n');
3860 if (end == NULL)
3861 break;
3862 *end = '\0';
3863 ret = os_snprintf(txt, sizeof(txt), "ifname=%s", pos);
a80ba67a 3864 if (!os_snprintf_error(sizeof(txt), ret))
37620493
JM
3865 cli_txt_list_add(&ifnames, txt);
3866 pos = end + 1;
3867 }
3868}
3869
3870
4be9f275
JM
3871static void try_connection(void *eloop_ctx, void *timeout_ctx)
3872{
6fd5ceaf
JM
3873 if (ctrl_conn)
3874 goto done;
3875
8e897ae3
JM
3876 if (ctrl_ifname == NULL)
3877 ctrl_ifname = wpa_cli_get_default_ifname();
3878
4be9f275
JM
3879 if (!wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
3880 if (!warning_displayed) {
3881 printf("Could not connect to wpa_supplicant: "
30f459c0
EL
3882 "%s - re-trying\n",
3883 ctrl_ifname ? ctrl_ifname : "(nil)");
4be9f275
JM
3884 warning_displayed = 1;
3885 }
3886 eloop_register_timeout(1, 0, try_connection, NULL, NULL);
3887 return;
3888 }
3889
9be37143
JM
3890 update_bssid_list(ctrl_conn);
3891
4be9f275
JM
3892 if (warning_displayed)
3893 printf("Connection established.\n");
3894
6fd5ceaf 3895done:
4be9f275
JM
3896 start_edit();
3897}
3898
cd101567 3899
4be9f275
JM
3900static void wpa_cli_interactive(void)
3901{
3902 printf("\nInteractive mode\n\n");
3903
3904 eloop_register_timeout(0, 0, try_connection, NULL, NULL);
cd101567 3905 eloop_run();
4be9f275 3906 eloop_cancel_timeout(try_connection, NULL, NULL);
cd101567 3907
a624f20b 3908 cli_txt_list_flush(&p2p_peers);
76788542 3909 cli_txt_list_flush(&p2p_groups);
a624f20b 3910 cli_txt_list_flush(&bsses);
37620493 3911 cli_txt_list_flush(&ifnames);
4be9f275
JM
3912 if (edit_started)
3913 edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
8953e968 3914 os_free(hfile);
cd101567
JM
3915 eloop_cancel_timeout(wpa_cli_ping, NULL, NULL);
3916 wpa_cli_close_connection();
6f1c6549
JM
3917}
3918
6fc6879b
JM
3919
3920static void wpa_cli_action(struct wpa_ctrl *ctrl)
3921{
3922#ifdef CONFIG_ANSI_C_EXTRA
3923 /* TODO: ANSI C version(?) */
3924 printf("Action processing not supported in ANSI C build.\n");
3925#else /* CONFIG_ANSI_C_EXTRA */
3926 fd_set rfds;
3927 int fd, res;
3928 struct timeval tv;
3929 char buf[256]; /* note: large enough to fit in unsolicited messages */
3930 size_t len;
3931
3932 fd = wpa_ctrl_get_fd(ctrl);
3933
3934 while (!wpa_cli_quit) {
3935 FD_ZERO(&rfds);
3936 FD_SET(fd, &rfds);
1cc84c1c 3937 tv.tv_sec = ping_interval;
6fc6879b
JM
3938 tv.tv_usec = 0;
3939 res = select(fd + 1, &rfds, NULL, NULL, &tv);
3940 if (res < 0 && errno != EINTR) {
3941 perror("select");
3942 break;
3943 }
3944
3945 if (FD_ISSET(fd, &rfds))
cd101567 3946 wpa_cli_recv_pending(ctrl, 1);
6fc6879b
JM
3947 else {
3948 /* verify that connection is still working */
3949 len = sizeof(buf) - 1;
3950 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
3951 wpa_cli_action_cb) < 0 ||
3952 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
3953 printf("wpa_supplicant did not reply to PING "
3954 "command - exiting\n");
3955 break;
3956 }
3957 }
3958 }
3959#endif /* CONFIG_ANSI_C_EXTRA */
3960}
3961
3962
3963static void wpa_cli_cleanup(void)
3964{
3965 wpa_cli_close_connection();
3966 if (pid_file)
3967 os_daemonize_terminate(pid_file);
3968
3969 os_program_deinit();
3970}
3971
4be9f275
JM
3972
3973static void wpa_cli_terminate(int sig, void *ctx)
6fc6879b 3974{
4be9f275 3975 eloop_terminate();
6fc6879b
JM
3976}
3977
3978
6fc6879b
JM
3979static char * wpa_cli_get_default_ifname(void)
3980{
3981 char *ifname = NULL;
3982
3983#ifdef CONFIG_CTRL_IFACE_UNIX
3984 struct dirent *dent;
3985 DIR *dir = opendir(ctrl_iface_dir);
b1001e4c
DS
3986 if (!dir) {
3987#ifdef ANDROID
3988 char ifprop[PROPERTY_VALUE_MAX];
3989 if (property_get("wifi.interface", ifprop, NULL) != 0) {
3990 ifname = os_strdup(ifprop);
3991 printf("Using interface '%s'\n", ifname);
3992 return ifname;
3993 }
3994#endif /* ANDROID */
6fc6879b 3995 return NULL;
b1001e4c 3996 }
6fc6879b
JM
3997 while ((dent = readdir(dir))) {
3998#ifdef _DIRENT_HAVE_D_TYPE
3999 /*
4000 * Skip the file if it is not a socket. Also accept
4001 * DT_UNKNOWN (0) in case the C library or underlying
4002 * file system does not support d_type.
4003 */
4004 if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
4005 continue;
4006#endif /* _DIRENT_HAVE_D_TYPE */
4007 if (os_strcmp(dent->d_name, ".") == 0 ||
4008 os_strcmp(dent->d_name, "..") == 0)
4009 continue;
4010 printf("Selected interface '%s'\n", dent->d_name);
4011 ifname = os_strdup(dent->d_name);
4012 break;
4013 }
4014 closedir(dir);
4015#endif /* CONFIG_CTRL_IFACE_UNIX */
4016
4017#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
89c7ac57 4018 char buf[4096], *pos;
6fc6879b
JM
4019 size_t len;
4020 struct wpa_ctrl *ctrl;
4021 int ret;
4022
4023 ctrl = wpa_ctrl_open(NULL);
4024 if (ctrl == NULL)
4025 return NULL;
4026
4027 len = sizeof(buf) - 1;
4028 ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL);
4029 if (ret >= 0) {
4030 buf[len] = '\0';
4031 pos = os_strchr(buf, '\n');
4032 if (pos)
4033 *pos = '\0';
4034 ifname = os_strdup(buf);
4035 }
4036 wpa_ctrl_close(ctrl);
4037#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
4038
4039 return ifname;
4040}
4041
4042
4043int main(int argc, char *argv[])
4044{
6fc6879b
JM
4045 int c;
4046 int daemonize = 0;
4047 int ret = 0;
4048 const char *global = NULL;
4049
4050 if (os_program_init())
4051 return -1;
4052
4053 for (;;) {
1cc84c1c 4054 c = getopt(argc, argv, "a:Bg:G:hi:p:P:v");
6fc6879b
JM
4055 if (c < 0)
4056 break;
4057 switch (c) {
4058 case 'a':
4059 action_file = optarg;
4060 break;
4061 case 'B':
4062 daemonize = 1;
4063 break;
4064 case 'g':
4065 global = optarg;
4066 break;
1cc84c1c
JM
4067 case 'G':
4068 ping_interval = atoi(optarg);
4069 break;
6fc6879b
JM
4070 case 'h':
4071 usage();
4072 return 0;
4073 case 'v':
4074 printf("%s\n", wpa_cli_version);
4075 return 0;
4076 case 'i':
4077 os_free(ctrl_ifname);
4078 ctrl_ifname = os_strdup(optarg);
4079 break;
4080 case 'p':
4081 ctrl_iface_dir = optarg;
4082 break;
4083 case 'P':
4084 pid_file = optarg;
4085 break;
4086 default:
4087 usage();
4088 return -1;
4089 }
4090 }
4091
4092 interactive = (argc == optind) && (action_file == NULL);
4093
4094 if (interactive)
4095 printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license);
4096
cd101567
JM
4097 if (eloop_init())
4098 return -1;
4099
6fc6879b
JM
4100 if (global) {
4101#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
4102 ctrl_conn = wpa_ctrl_open(NULL);
4103#else /* CONFIG_CTRL_IFACE_NAMED_PIPE */
4104 ctrl_conn = wpa_ctrl_open(global);
4105#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
4106 if (ctrl_conn == NULL) {
5a49459e
BG
4107 fprintf(stderr, "Failed to connect to wpa_supplicant "
4108 "global interface: %s error: %s\n",
4109 global, strerror(errno));
6fc6879b
JM
4110 return -1;
4111 }
214e428b
JM
4112
4113 if (interactive) {
37620493 4114 update_ifnames(ctrl_conn);
214e428b
JM
4115 mon_conn = wpa_ctrl_open(global);
4116 if (mon_conn) {
4117 if (wpa_ctrl_attach(mon_conn) == 0) {
4118 wpa_cli_attached = 1;
4119 eloop_register_read_sock(
4120 wpa_ctrl_get_fd(mon_conn),
4121 wpa_cli_mon_receive,
4122 NULL, NULL);
4123 } else {
4124 printf("Failed to open monitor "
4125 "connection through global "
4126 "control interface\n");
4127 }
4128 }
4129 }
6fc6879b
JM
4130 }
4131
4be9f275 4132 eloop_register_signal_terminate(wpa_cli_terminate, NULL);
6fc6879b 4133
4a3ade4e
JM
4134 if (ctrl_ifname == NULL)
4135 ctrl_ifname = wpa_cli_get_default_ifname();
4136
4137 if (interactive) {
4be9f275 4138 wpa_cli_interactive();
4a3ade4e
JM
4139 } else {
4140 if (!global &&
4141 wpa_cli_open_connection(ctrl_ifname, 0) < 0) {
5a49459e
BG
4142 fprintf(stderr, "Failed to connect to non-global "
4143 "ctrl_ifname: %s error: %s\n",
30f459c0
EL
4144 ctrl_ifname ? ctrl_ifname : "(nil)",
4145 strerror(errno));
4a3ade4e
JM
4146 return -1;
4147 }
4148
4149 if (action_file) {
4150 if (wpa_ctrl_attach(ctrl_conn) == 0) {
4151 wpa_cli_attached = 1;
4152 } else {
4153 printf("Warning: Failed to attach to "
4154 "wpa_supplicant.\n");
6fc6879b 4155 return -1;
4a3ade4e 4156 }
6fc6879b 4157 }
6fc6879b 4158
4be9f275
JM
4159 if (daemonize && os_daemonize(pid_file))
4160 return -1;
6fc6879b 4161
4be9f275
JM
4162 if (action_file)
4163 wpa_cli_action(ctrl_conn);
4164 else
4165 ret = wpa_request(ctrl_conn, argc - optind,
4166 &argv[optind]);
4167 }
6fc6879b
JM
4168
4169 os_free(ctrl_ifname);
cd101567 4170 eloop_destroy();
6fc6879b
JM
4171 wpa_cli_cleanup();
4172
4173 return ret;
4174}
4175
4176#else /* CONFIG_CTRL_IFACE */
4177int main(int argc, char *argv[])
4178{
4179 printf("CONFIG_CTRL_IFACE not defined - wpa_cli disabled\n");
4180 return -1;
4181}
4182#endif /* CONFIG_CTRL_IFACE */