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