]> git.ipfire.org Git - thirdparty/hostap.git/blame - wpa_supplicant/wpa_cli.c
WPS: Add more debug prints for authorized MACs operations
[thirdparty/hostap.git] / wpa_supplicant / wpa_cli.c
CommitLineData
6fc6879b
JM
1/*
2 * WPA Supplicant - command line interface for wpa_supplicant daemon
dff0f701 3 * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
6fc6879b
JM
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "includes.h"
16
17#ifdef CONFIG_CTRL_IFACE
18
19#ifdef CONFIG_CTRL_IFACE_UNIX
20#include <dirent.h>
21#endif /* CONFIG_CTRL_IFACE_UNIX */
22#ifdef CONFIG_READLINE
23#include <readline/readline.h>
24#include <readline/history.h>
25#endif /* CONFIG_READLINE */
cbf78558
JM
26#ifdef CONFIG_WPA_CLI_FORK
27#include <sys/wait.h>
28#endif /* CONFIG_WPA_CLI_FORK */
6fc6879b 29
90973fb2 30#include "common/wpa_ctrl.h"
6fc6879b 31#include "common.h"
90973fb2 32#include "common/version.h"
6fc6879b
JM
33
34
35static const char *wpa_cli_version =
36"wpa_cli v" VERSION_STR "\n"
dff0f701 37"Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi> and contributors";
6fc6879b
JM
38
39
40static const char *wpa_cli_license =
41"This program is free software. You can distribute it and/or modify it\n"
42"under the terms of the GNU General Public License version 2.\n"
43"\n"
44"Alternatively, this software may be distributed under the terms of the\n"
45"BSD license. See README and COPYING for more details.\n";
46
47static const char *wpa_cli_full_license =
48"This program is free software; you can redistribute it and/or modify\n"
49"it under the terms of the GNU General Public License version 2 as\n"
50"published by the Free Software Foundation.\n"
51"\n"
52"This program is distributed in the hope that it will be useful,\n"
53"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
54"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
55"GNU General Public License for more details.\n"
56"\n"
57"You should have received a copy of the GNU General Public License\n"
58"along with this program; if not, write to the Free Software\n"
59"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
60"\n"
61"Alternatively, this software may be distributed under the terms of the\n"
62"BSD license.\n"
63"\n"
64"Redistribution and use in source and binary forms, with or without\n"
65"modification, are permitted provided that the following conditions are\n"
66"met:\n"
67"\n"
68"1. Redistributions of source code must retain the above copyright\n"
69" notice, this list of conditions and the following disclaimer.\n"
70"\n"
71"2. Redistributions in binary form must reproduce the above copyright\n"
72" notice, this list of conditions and the following disclaimer in the\n"
73" documentation and/or other materials provided with the distribution.\n"
74"\n"
75"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
76" names of its contributors may be used to endorse or promote products\n"
77" derived from this software without specific prior written permission.\n"
78"\n"
79"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
80"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
81"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
82"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
83"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
84"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
85"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
86"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
87"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
88"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
89"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
90"\n";
91
6fc6879b 92static struct wpa_ctrl *ctrl_conn;
4a3ade4e 93static struct wpa_ctrl *mon_conn;
cbf78558
JM
94#ifdef CONFIG_WPA_CLI_FORK
95static pid_t mon_pid = 0;
96#endif /* CONFIG_WPA_CLI_FORK */
6fc6879b
JM
97static int wpa_cli_quit = 0;
98static int wpa_cli_attached = 0;
99static int wpa_cli_connected = 0;
100static int wpa_cli_last_id = 0;
101static const char *ctrl_iface_dir = "/var/run/wpa_supplicant";
102static char *ctrl_ifname = NULL;
103static const char *pid_file = NULL;
104static const char *action_file = NULL;
1cc84c1c 105static int ping_interval = 5;
4a3ade4e 106static int interactive = 0;
6fc6879b
JM
107
108
dfa141b1
ER
109static void print_help();
110
111
6fc6879b
JM
112static void usage(void)
113{
114 printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] "
115 "[-a<action file>] \\\n"
1cc84c1c
JM
116 " [-P<pid file>] [-g<global ctrl>] [-G<ping interval>] "
117 "[command..]\n"
6fc6879b
JM
118 " -h = help (show this usage text)\n"
119 " -v = shown version information\n"
120 " -a = run in daemon mode executing the action file based on "
121 "events from\n"
122 " wpa_supplicant\n"
123 " -B = run a daemon in the background\n"
124 " default path: /var/run/wpa_supplicant\n"
dfa141b1
ER
125 " default interface: first interface found in socket path\n");
126 print_help();
6fc6879b
JM
127}
128
129
f3f0f648
JM
130static void readline_redraw()
131{
132#ifdef CONFIG_READLINE
133 rl_on_new_line();
134 rl_redisplay();
135#endif /* CONFIG_READLINE */
136}
137
138
139static int str_starts(const char *src, const char *match)
140{
141 return os_strncmp(src, match, os_strlen(match)) == 0;
142}
143
144
145static int wpa_cli_show_event(const char *event)
146{
147 const char *start;
148
149 start = os_strchr(event, '>');
150 if (start == NULL)
151 return 1;
152
153 start++;
154 /*
155 * Skip BSS added/removed events since they can be relatively frequent
156 * and are likely of not much use for an interactive user.
157 */
158 if (str_starts(start, WPA_EVENT_BSS_ADDED) ||
159 str_starts(start, WPA_EVENT_BSS_REMOVED))
160 return 0;
161
162 return 1;
163}
164
165
cbf78558 166#ifdef CONFIG_WPA_CLI_FORK
dd63f314
JM
167static int in_query = 0;
168
169static void wpa_cli_monitor_sig(int sig)
170{
171 if (sig == SIGUSR1)
172 in_query = 1;
173 else if (sig == SIGUSR2)
174 in_query = 0;
175}
176
f3f0f648 177
cbf78558
JM
178static void wpa_cli_monitor(void)
179{
180 char buf[256];
181 size_t len = sizeof(buf) - 1;
182 struct timeval tv;
183 fd_set rfds;
f3f0f648 184 int ppid;
cbf78558 185
dd63f314
JM
186 signal(SIGUSR1, wpa_cli_monitor_sig);
187 signal(SIGUSR2, wpa_cli_monitor_sig);
188
f3f0f648 189 ppid = getppid();
cbf78558
JM
190 while (mon_conn) {
191 int s = wpa_ctrl_get_fd(mon_conn);
192 tv.tv_sec = 5;
193 tv.tv_usec = 0;
194 FD_ZERO(&rfds);
195 FD_SET(s, &rfds);
196 if (select(s + 1, &rfds, NULL, NULL, &tv) < 0) {
dd63f314
JM
197 if (errno == EINTR)
198 continue;
cbf78558
JM
199 perror("select");
200 break;
201 }
202 if (mon_conn == NULL)
203 break;
204 if (FD_ISSET(s, &rfds)) {
205 len = sizeof(buf) - 1;
206 int res = wpa_ctrl_recv(mon_conn, buf, &len);
207 if (res < 0) {
208 perror("wpa_ctrl_recv");
209 break;
210 }
211 buf[len] = '\0';
f3f0f648
JM
212 if (wpa_cli_show_event(buf)) {
213 if (in_query)
214 printf("\r");
215 printf("%s\n", buf);
216 kill(ppid, SIGUSR1);
217 }
cbf78558
JM
218 }
219 }
220}
221#endif /* CONFIG_WPA_CLI_FORK */
222
223
4a3ade4e 224static int wpa_cli_open_connection(const char *ifname, int attach)
6fc6879b
JM
225{
226#if defined(CONFIG_CTRL_IFACE_UDP) || defined(CONFIG_CTRL_IFACE_NAMED_PIPE)
227 ctrl_conn = wpa_ctrl_open(ifname);
4a3ade4e
JM
228 if (ctrl_conn == NULL)
229 return -1;
230
231 if (attach && interactive)
232 mon_conn = wpa_ctrl_open(ifname);
233 else
234 mon_conn = NULL;
6fc6879b
JM
235#else /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
236 char *cfile;
237 int flen, res;
238
239 if (ifname == NULL)
4a3ade4e 240 return -1;
6fc6879b
JM
241
242 flen = os_strlen(ctrl_iface_dir) + os_strlen(ifname) + 2;
243 cfile = os_malloc(flen);
244 if (cfile == NULL)
4a3ade4e 245 return -1L;
6fc6879b
JM
246 res = os_snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
247 if (res < 0 || res >= flen) {
248 os_free(cfile);
4a3ade4e 249 return -1;
6fc6879b
JM
250 }
251
252 ctrl_conn = wpa_ctrl_open(cfile);
4a3ade4e
JM
253 if (ctrl_conn == NULL) {
254 os_free(cfile);
255 return -1;
256 }
257
258 if (attach && interactive)
259 mon_conn = wpa_ctrl_open(cfile);
260 else
261 mon_conn = NULL;
6fc6879b 262 os_free(cfile);
6fc6879b 263#endif /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
4a3ade4e
JM
264
265 if (mon_conn) {
266 if (wpa_ctrl_attach(mon_conn) == 0) {
267 wpa_cli_attached = 1;
268 } else {
269 printf("Warning: Failed to attach to "
270 "wpa_supplicant.\n");
271 return -1;
272 }
cbf78558
JM
273
274#ifdef CONFIG_WPA_CLI_FORK
275 {
276 pid_t p = fork();
277 if (p < 0) {
278 perror("fork");
279 return -1;
280 }
281 if (p == 0) {
282 wpa_cli_monitor();
283 exit(0);
284 } else
285 mon_pid = p;
286 }
287#endif /* CONFIG_WPA_CLI_FORK */
4a3ade4e
JM
288 }
289
290 return 0;
6fc6879b
JM
291}
292
293
294static void wpa_cli_close_connection(void)
295{
296 if (ctrl_conn == NULL)
297 return;
298
037f83eb
JM
299#ifdef CONFIG_WPA_CLI_FORK
300 if (mon_pid) {
301 int status;
302 kill(mon_pid, SIGPIPE);
303 wait(&status);
304 mon_pid = 0;
305 }
306#endif /* CONFIG_WPA_CLI_FORK */
307
6fc6879b 308 if (wpa_cli_attached) {
4a3ade4e 309 wpa_ctrl_detach(interactive ? mon_conn : ctrl_conn);
6fc6879b
JM
310 wpa_cli_attached = 0;
311 }
312 wpa_ctrl_close(ctrl_conn);
313 ctrl_conn = NULL;
4a3ade4e
JM
314 if (mon_conn) {
315 wpa_ctrl_close(mon_conn);
316 mon_conn = NULL;
317 }
6fc6879b
JM
318}
319
320
321static void wpa_cli_msg_cb(char *msg, size_t len)
322{
323 printf("%s\n", msg);
324}
325
326
327static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
328{
329 char buf[2048];
330 size_t len;
331 int ret;
332
333 if (ctrl_conn == NULL) {
334 printf("Not connected to wpa_supplicant - command dropped.\n");
335 return -1;
336 }
337 len = sizeof(buf) - 1;
338 ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
339 wpa_cli_msg_cb);
340 if (ret == -2) {
341 printf("'%s' command timed out.\n", cmd);
342 return -2;
343 } else if (ret < 0) {
344 printf("'%s' command failed.\n", cmd);
345 return -1;
346 }
347 if (print) {
348 buf[len] = '\0';
349 printf("%s", buf);
350 }
351 return 0;
352}
353
354
355static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
356{
357 return _wpa_ctrl_command(ctrl, cmd, 1);
358}
359
360
361static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
362{
363 int verbose = argc > 0 && os_strcmp(argv[0], "verbose") == 0;
364 return wpa_ctrl_command(ctrl, verbose ? "STATUS-VERBOSE" : "STATUS");
365}
366
367
368static int wpa_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
369{
370 return wpa_ctrl_command(ctrl, "PING");
371}
372
373
77895cd9
JM
374static int wpa_cli_cmd_note(struct wpa_ctrl *ctrl, int argc, char *argv[])
375{
376 char cmd[256];
377 int ret;
378 if (argc == 0)
379 return -1;
380 ret = os_snprintf(cmd, sizeof(cmd), "NOTE %s", argv[0]);
381 if (ret < 0 || (size_t) ret >= sizeof(cmd))
382 return -1;
383 return wpa_ctrl_command(ctrl, cmd);
384}
385
386
6fc6879b
JM
387static int wpa_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
388{
389 return wpa_ctrl_command(ctrl, "MIB");
390}
391
392
393static int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
394{
395 return wpa_ctrl_command(ctrl, "PMKSA");
396}
397
398
399static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
400{
dfa141b1 401 print_help();
6fc6879b
JM
402 return 0;
403}
404
405
406static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[])
407{
408 printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license);
409 return 0;
410}
411
412
413static int wpa_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
414{
415 wpa_cli_quit = 1;
416 return 0;
417}
418
419
420static void wpa_cli_show_variables(void)
421{
422 printf("set variables:\n"
423 " EAPOL::heldPeriod (EAPOL state machine held period, "
424 "in seconds)\n"
425 " EAPOL::authPeriod (EAPOL state machine authentication "
426 "period, in seconds)\n"
427 " EAPOL::startPeriod (EAPOL state machine start period, in "
428 "seconds)\n"
429 " EAPOL::maxStart (EAPOL state machine maximum start "
430 "attempts)\n");
431 printf(" dot11RSNAConfigPMKLifetime (WPA/WPA2 PMK lifetime in "
432 "seconds)\n"
433 " dot11RSNAConfigPMKReauthThreshold (WPA/WPA2 reauthentication"
434 " threshold\n\tpercentage)\n"
435 " dot11RSNAConfigSATimeout (WPA/WPA2 timeout for completing "
436 "security\n\tassociation in seconds)\n");
437}
438
439
440static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
441{
442 char cmd[256];
443 int res;
444
445 if (argc == 0) {
446 wpa_cli_show_variables();
447 return 0;
448 }
449
450 if (argc != 2) {
451 printf("Invalid SET command: needs two arguments (variable "
452 "name and value)\n");
453 return -1;
454 }
455
456 res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
457 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
458 printf("Too long SET command.\n");
459 return -1;
460 }
461 return wpa_ctrl_command(ctrl, cmd);
462}
463
464
465static int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[])
466{
467 return wpa_ctrl_command(ctrl, "LOGOFF");
468}
469
470
471static int wpa_cli_cmd_logon(struct wpa_ctrl *ctrl, int argc, char *argv[])
472{
473 return wpa_ctrl_command(ctrl, "LOGON");
474}
475
476
477static int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc,
478 char *argv[])
479{
480 return wpa_ctrl_command(ctrl, "REASSOCIATE");
481}
482
483
484static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc,
485 char *argv[])
486{
487 char cmd[256];
488 int res;
489
490 if (argc != 1) {
491 printf("Invalid PREAUTH command: needs one argument "
492 "(BSSID)\n");
493 return -1;
494 }
495
496 res = os_snprintf(cmd, sizeof(cmd), "PREAUTH %s", argv[0]);
497 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
498 printf("Too long PREAUTH command.\n");
499 return -1;
500 }
501 return wpa_ctrl_command(ctrl, cmd);
502}
503
504
505static int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
506{
507 char cmd[256];
508 int res;
509
510 if (argc != 1) {
511 printf("Invalid AP_SCAN command: needs one argument (ap_scan "
512 "value)\n");
513 return -1;
514 }
515 res = os_snprintf(cmd, sizeof(cmd), "AP_SCAN %s", argv[0]);
516 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
517 printf("Too long AP_SCAN command.\n");
518 return -1;
519 }
520 return wpa_ctrl_command(ctrl, cmd);
521}
522
523
524static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc,
525 char *argv[])
526{
527 char cmd[256];
528 int res;
529
530 if (argc != 1) {
531 printf("Invalid STKSTART command: needs one argument "
532 "(Peer STA MAC address)\n");
533 return -1;
534 }
535
536 res = os_snprintf(cmd, sizeof(cmd), "STKSTART %s", argv[0]);
537 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
538 printf("Too long STKSTART command.\n");
539 return -1;
540 }
541 return wpa_ctrl_command(ctrl, cmd);
542}
543
544
545static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[])
546{
547 char cmd[256];
548 int res;
549
550 if (argc != 1) {
551 printf("Invalid FT_DS command: needs one argument "
552 "(Target AP MAC address)\n");
553 return -1;
554 }
555
556 res = os_snprintf(cmd, sizeof(cmd), "FT_DS %s", argv[0]);
557 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
558 printf("Too long FT_DS command.\n");
559 return -1;
560 }
561 return wpa_ctrl_command(ctrl, cmd);
562}
563
564
fcc60db4
JM
565static int wpa_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[])
566{
567 char cmd[256];
568 int res;
569
570 if (argc == 0) {
571 /* Any BSSID */
572 return wpa_ctrl_command(ctrl, "WPS_PBC");
573 }
574
575 /* Specific BSSID */
576 res = os_snprintf(cmd, sizeof(cmd), "WPS_PBC %s", argv[0]);
577 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
578 printf("Too long WPS_PBC command.\n");
579 return -1;
580 }
581 return wpa_ctrl_command(ctrl, cmd);
582}
583
584
585static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
586{
587 char cmd[256];
588 int res;
589
590 if (argc == 0) {
591 printf("Invalid WPS_PIN command: need one or two arguments:\n"
592 "- BSSID: use 'any' to select any\n"
593 "- PIN: optional, used only with devices that have no "
594 "display\n");
595 return -1;
596 }
597
598 if (argc == 1) {
599 /* Use dynamically generated PIN (returned as reply) */
600 res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s", argv[0]);
601 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
602 printf("Too long WPS_PIN command.\n");
603 return -1;
604 }
605 return wpa_ctrl_command(ctrl, cmd);
606 }
607
608 /* Use hardcoded PIN from a label */
609 res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s", argv[0], argv[1]);
610 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
611 printf("Too long WPS_PIN command.\n");
612 return -1;
613 }
614 return wpa_ctrl_command(ctrl, cmd);
615}
616
617
116f7bb0 618#ifdef CONFIG_WPS_OOB
46bdb83a
MH
619static int wpa_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, char *argv[])
620{
621 char cmd[256];
622 int res;
623
e1ee6b60
MH
624 if (argc != 3 && argc != 4) {
625 printf("Invalid WPS_OOB command: need three or four "
626 "arguments:\n"
627 "- DEV_TYPE: use 'ufd' or 'nfc'\n"
628 "- PATH: path of OOB device like '/mnt'\n"
629 "- METHOD: OOB method 'pin-e' or 'pin-r', "
630 "'cred'\n"
631 "- DEV_NAME: (only for NFC) device name like "
632 "'pn531'\n");
46bdb83a
MH
633 return -1;
634 }
635
e1ee6b60
MH
636 if (argc == 3)
637 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
638 argv[0], argv[1], argv[2]);
639 else
640 res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
641 argv[0], argv[1], argv[2], argv[3]);
46bdb83a
MH
642 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
643 printf("Too long WPS_OOB command.\n");
644 return -1;
645 }
646 return wpa_ctrl_command(ctrl, cmd);
647}
116f7bb0 648#endif /* CONFIG_WPS_OOB */
46bdb83a
MH
649
650
fcc60db4
JM
651static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
652{
653 char cmd[256];
654 int res;
655
52eb293d
JM
656 if (argc == 2)
657 res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s",
658 argv[0], argv[1]);
7d6640a6 659 else if (argc == 5 || argc == 6) {
52eb293d
JM
660 char ssid_hex[2 * 32 + 1];
661 char key_hex[2 * 64 + 1];
662 int i;
663
664 ssid_hex[0] = '\0';
665 for (i = 0; i < 32; i++) {
666 if (argv[2][i] == '\0')
667 break;
668 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]);
669 }
670
671 key_hex[0] = '\0';
7d6640a6
JM
672 if (argc == 6) {
673 for (i = 0; i < 64; i++) {
674 if (argv[5][i] == '\0')
675 break;
676 os_snprintf(&key_hex[i * 2], 3, "%02x",
677 argv[5][i]);
678 }
52eb293d
JM
679 }
680
681 res = os_snprintf(cmd, sizeof(cmd),
682 "WPS_REG %s %s %s %s %s %s",
683 argv[0], argv[1], ssid_hex, argv[3], argv[4],
684 key_hex);
685 } else {
fcc60db4
JM
686 printf("Invalid WPS_REG command: need two arguments:\n"
687 "- BSSID: use 'any' to select any\n"
688 "- AP PIN\n");
52eb293d
JM
689 printf("Alternatively, six arguments can be used to "
690 "reconfigure the AP:\n"
691 "- BSSID: use 'any' to select any\n"
692 "- AP PIN\n"
693 "- new SSID\n"
694 "- new auth (OPEN, WPAPSK, WPA2PSK)\n"
695 "- new encr (NONE, WEP, TKIP, CCMP)\n"
696 "- new key\n");
fcc60db4
JM
697 return -1;
698 }
699
fcc60db4
JM
700 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
701 printf("Too long WPS_REG command.\n");
702 return -1;
703 }
704 return wpa_ctrl_command(ctrl, cmd);
705}
706
707
e9bcfebf
JM
708static int wpa_cli_cmd_wps_er_start(struct wpa_ctrl *ctrl, int argc,
709 char *argv[])
710{
08486685
JM
711 char cmd[100];
712 if (argc > 0) {
713 os_snprintf(cmd, sizeof(cmd), "WPS_ER_START %s", argv[0]);
714 return wpa_ctrl_command(ctrl, cmd);
715 }
e9bcfebf 716 return wpa_ctrl_command(ctrl, "WPS_ER_START");
e9bcfebf
JM
717}
718
719
720static int wpa_cli_cmd_wps_er_stop(struct wpa_ctrl *ctrl, int argc,
721 char *argv[])
722{
723 return wpa_ctrl_command(ctrl, "WPS_ER_STOP");
724
725}
726
727
72df2f5f
JM
728static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc,
729 char *argv[])
730{
731 char cmd[256];
732 int res;
733
31fcea93
JM
734 if (argc < 2) {
735 printf("Invalid WPS_ER_PIN command: need at least two "
736 "arguments:\n"
72df2f5f 737 "- UUID: use 'any' to select any\n"
31fcea93
JM
738 "- PIN: Enrollee PIN\n"
739 "optional: - Enrollee MAC address\n");
72df2f5f
JM
740 return -1;
741 }
742
31fcea93
JM
743 if (argc > 2)
744 res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s %s",
745 argv[0], argv[1], argv[2]);
746 else
747 res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s",
748 argv[0], argv[1]);
72df2f5f
JM
749 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
750 printf("Too long WPS_ER_PIN command.\n");
751 return -1;
752 }
753 return wpa_ctrl_command(ctrl, cmd);
754}
755
756
564cd7fa
JM
757static int wpa_cli_cmd_wps_er_pbc(struct wpa_ctrl *ctrl, int argc,
758 char *argv[])
759{
760 char cmd[256];
761 int res;
762
763 if (argc != 1) {
764 printf("Invalid WPS_ER_PBC command: need one argument:\n"
765 "- UUID: Specify the Enrollee\n");
766 return -1;
767 }
768
769 res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PBC %s",
770 argv[0]);
771 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
772 printf("Too long WPS_ER_PBC command.\n");
773 return -1;
774 }
775 return wpa_ctrl_command(ctrl, cmd);
776}
777
778
e64dcfd5
JM
779static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc,
780 char *argv[])
781{
782 char cmd[256];
783 int res;
784
785 if (argc != 2) {
786 printf("Invalid WPS_ER_LEARN command: need two arguments:\n"
787 "- UUID: specify which AP to use\n"
788 "- PIN: AP PIN\n");
789 return -1;
790 }
791
792 res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_LEARN %s %s",
793 argv[0], argv[1]);
794 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
795 printf("Too long WPS_ER_LEARN command.\n");
796 return -1;
797 }
798 return wpa_ctrl_command(ctrl, cmd);
799}
800
801
7d6640a6
JM
802static int wpa_cli_cmd_wps_er_config(struct wpa_ctrl *ctrl, int argc,
803 char *argv[])
804{
805 char cmd[256];
806 int res;
807
808 if (argc == 5 || argc == 6) {
809 char ssid_hex[2 * 32 + 1];
810 char key_hex[2 * 64 + 1];
811 int i;
812
813 ssid_hex[0] = '\0';
814 for (i = 0; i < 32; i++) {
815 if (argv[2][i] == '\0')
816 break;
817 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]);
818 }
819
820 key_hex[0] = '\0';
821 if (argc == 6) {
822 for (i = 0; i < 64; i++) {
823 if (argv[5][i] == '\0')
824 break;
825 os_snprintf(&key_hex[i * 2], 3, "%02x",
826 argv[5][i]);
827 }
828 }
829
830 res = os_snprintf(cmd, sizeof(cmd),
831 "WPS_ER_CONFIG %s %s %s %s %s %s",
832 argv[0], argv[1], ssid_hex, argv[3], argv[4],
833 key_hex);
834 } else {
835 printf("Invalid WPS_ER_CONFIG command: need six arguments:\n"
836 "- AP UUID\n"
837 "- AP PIN\n"
838 "- new SSID\n"
839 "- new auth (OPEN, WPAPSK, WPA2PSK)\n"
840 "- new encr (NONE, WEP, TKIP, CCMP)\n"
841 "- new key\n");
842 return -1;
843 }
844
845 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
846 printf("Too long WPS_ER_CONFIG command.\n");
847 return -1;
848 }
849 return wpa_ctrl_command(ctrl, cmd);
850}
851
852
11ef8d35
JM
853static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[])
854{
855 char cmd[256];
856 int res;
857
858 if (argc != 1) {
859 printf("Invalid IBSS_RSN command: needs one argument "
860 "(Peer STA MAC address)\n");
861 return -1;
862 }
863
864 res = os_snprintf(cmd, sizeof(cmd), "IBSS_RSN %s", argv[0]);
865 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
866 printf("Too long IBSS_RSN command.\n");
867 return -1;
868 }
869 return wpa_ctrl_command(ctrl, cmd);
870}
871
872
6fc6879b
JM
873static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
874{
875 char cmd[256];
876 int res;
877
878 if (argc != 1) {
879 printf("Invalid LEVEL command: needs one argument (debug "
880 "level)\n");
881 return -1;
882 }
883 res = os_snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
884 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
885 printf("Too long LEVEL command.\n");
886 return -1;
887 }
888 return wpa_ctrl_command(ctrl, cmd);
889}
890
891
892static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[])
893{
894 char cmd[256], *pos, *end;
895 int i, ret;
896
897 if (argc < 2) {
898 printf("Invalid IDENTITY command: needs two arguments "
899 "(network id and identity)\n");
900 return -1;
901 }
902
903 end = cmd + sizeof(cmd);
904 pos = cmd;
905 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s",
906 argv[0], argv[1]);
907 if (ret < 0 || ret >= end - pos) {
908 printf("Too long IDENTITY command.\n");
909 return -1;
910 }
911 pos += ret;
912 for (i = 2; i < argc; i++) {
913 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
914 if (ret < 0 || ret >= end - pos) {
915 printf("Too long IDENTITY command.\n");
916 return -1;
917 }
918 pos += ret;
919 }
920
921 return wpa_ctrl_command(ctrl, cmd);
922}
923
924
925static int wpa_cli_cmd_password(struct wpa_ctrl *ctrl, int argc, char *argv[])
926{
927 char cmd[256], *pos, *end;
928 int i, ret;
929
930 if (argc < 2) {
931 printf("Invalid PASSWORD command: needs two arguments "
932 "(network id and password)\n");
933 return -1;
934 }
935
936 end = cmd + sizeof(cmd);
937 pos = cmd;
938 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s",
939 argv[0], argv[1]);
940 if (ret < 0 || ret >= end - pos) {
941 printf("Too long PASSWORD command.\n");
942 return -1;
943 }
944 pos += ret;
945 for (i = 2; i < argc; i++) {
946 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
947 if (ret < 0 || ret >= end - pos) {
948 printf("Too long PASSWORD command.\n");
949 return -1;
950 }
951 pos += ret;
952 }
953
954 return wpa_ctrl_command(ctrl, cmd);
955}
956
957
958static int wpa_cli_cmd_new_password(struct wpa_ctrl *ctrl, int argc,
959 char *argv[])
960{
961 char cmd[256], *pos, *end;
962 int i, ret;
963
964 if (argc < 2) {
965 printf("Invalid NEW_PASSWORD command: needs two arguments "
966 "(network id and password)\n");
967 return -1;
968 }
969
970 end = cmd + sizeof(cmd);
971 pos = cmd;
972 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s",
973 argv[0], argv[1]);
974 if (ret < 0 || ret >= end - pos) {
975 printf("Too long NEW_PASSWORD command.\n");
976 return -1;
977 }
978 pos += ret;
979 for (i = 2; i < argc; i++) {
980 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
981 if (ret < 0 || ret >= end - pos) {
982 printf("Too long NEW_PASSWORD command.\n");
983 return -1;
984 }
985 pos += ret;
986 }
987
988 return wpa_ctrl_command(ctrl, cmd);
989}
990
991
992static int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
993{
994 char cmd[256], *pos, *end;
995 int i, ret;
996
997 if (argc < 2) {
998 printf("Invalid PIN command: needs two arguments "
999 "(network id and pin)\n");
1000 return -1;
1001 }
1002
1003 end = cmd + sizeof(cmd);
1004 pos = cmd;
1005 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s",
1006 argv[0], argv[1]);
1007 if (ret < 0 || ret >= end - pos) {
1008 printf("Too long PIN command.\n");
1009 return -1;
1010 }
1011 pos += ret;
1012 for (i = 2; i < argc; i++) {
1013 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
1014 if (ret < 0 || ret >= end - pos) {
1015 printf("Too long PIN command.\n");
1016 return -1;
1017 }
1018 pos += ret;
1019 }
1020 return wpa_ctrl_command(ctrl, cmd);
1021}
1022
1023
1024static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[])
1025{
1026 char cmd[256], *pos, *end;
1027 int i, ret;
1028
1029 if (argc < 2) {
1030 printf("Invalid OTP command: needs two arguments (network "
1031 "id and password)\n");
1032 return -1;
1033 }
1034
1035 end = cmd + sizeof(cmd);
1036 pos = cmd;
1037 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s",
1038 argv[0], argv[1]);
1039 if (ret < 0 || ret >= end - pos) {
1040 printf("Too long OTP command.\n");
1041 return -1;
1042 }
1043 pos += ret;
1044 for (i = 2; i < argc; i++) {
1045 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
1046 if (ret < 0 || ret >= end - pos) {
1047 printf("Too long OTP command.\n");
1048 return -1;
1049 }
1050 pos += ret;
1051 }
1052
1053 return wpa_ctrl_command(ctrl, cmd);
1054}
1055
1056
1057static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
1058 char *argv[])
1059{
1060 char cmd[256], *pos, *end;
1061 int i, ret;
1062
1063 if (argc < 2) {
1064 printf("Invalid PASSPHRASE command: needs two arguments "
1065 "(network id and passphrase)\n");
1066 return -1;
1067 }
1068
1069 end = cmd + sizeof(cmd);
1070 pos = cmd;
1071 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s",
1072 argv[0], argv[1]);
1073 if (ret < 0 || ret >= end - pos) {
1074 printf("Too long PASSPHRASE command.\n");
1075 return -1;
1076 }
1077 pos += ret;
1078 for (i = 2; i < argc; i++) {
1079 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
1080 if (ret < 0 || ret >= end - pos) {
1081 printf("Too long PASSPHRASE command.\n");
1082 return -1;
1083 }
1084 pos += ret;
1085 }
1086
1087 return wpa_ctrl_command(ctrl, cmd);
1088}
1089
1090
1091static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[])
1092{
1093 char cmd[256], *pos, *end;
1094 int i, ret;
1095
1096 if (argc < 2) {
1097 printf("Invalid BSSID command: needs two arguments (network "
1098 "id and BSSID)\n");
1099 return -1;
1100 }
1101
1102 end = cmd + sizeof(cmd);
1103 pos = cmd;
1104 ret = os_snprintf(pos, end - pos, "BSSID");
1105 if (ret < 0 || ret >= end - pos) {
1106 printf("Too long BSSID command.\n");
1107 return -1;
1108 }
1109 pos += ret;
1110 for (i = 0; i < argc; i++) {
1111 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
1112 if (ret < 0 || ret >= end - pos) {
1113 printf("Too long BSSID command.\n");
1114 return -1;
1115 }
1116 pos += ret;
1117 }
1118
1119 return wpa_ctrl_command(ctrl, cmd);
1120}
1121
1122
1123static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc,
1124 char *argv[])
1125{
1126 return wpa_ctrl_command(ctrl, "LIST_NETWORKS");
1127}
1128
1129
1130static int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc,
1131 char *argv[])
1132{
1133 char cmd[32];
1134 int res;
1135
1136 if (argc < 1) {
1137 printf("Invalid SELECT_NETWORK command: needs one argument "
1138 "(network id)\n");
1139 return -1;
1140 }
1141
1142 res = os_snprintf(cmd, sizeof(cmd), "SELECT_NETWORK %s", argv[0]);
1143 if (res < 0 || (size_t) res >= sizeof(cmd))
1144 return -1;
1145 cmd[sizeof(cmd) - 1] = '\0';
1146
1147 return wpa_ctrl_command(ctrl, cmd);
1148}
1149
1150
1151static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc,
1152 char *argv[])
1153{
1154 char cmd[32];
1155 int res;
1156
1157 if (argc < 1) {
1158 printf("Invalid ENABLE_NETWORK command: needs one argument "
1159 "(network id)\n");
1160 return -1;
1161 }
1162
1163 res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s", argv[0]);
1164 if (res < 0 || (size_t) res >= sizeof(cmd))
1165 return -1;
1166 cmd[sizeof(cmd) - 1] = '\0';
1167
1168 return wpa_ctrl_command(ctrl, cmd);
1169}
1170
1171
1172static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc,
1173 char *argv[])
1174{
1175 char cmd[32];
1176 int res;
1177
1178 if (argc < 1) {
1179 printf("Invalid DISABLE_NETWORK command: needs one argument "
1180 "(network id)\n");
1181 return -1;
1182 }
1183
1184 res = os_snprintf(cmd, sizeof(cmd), "DISABLE_NETWORK %s", argv[0]);
1185 if (res < 0 || (size_t) res >= sizeof(cmd))
1186 return -1;
1187 cmd[sizeof(cmd) - 1] = '\0';
1188
1189 return wpa_ctrl_command(ctrl, cmd);
1190}
1191
1192
1193static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc,
1194 char *argv[])
1195{
1196 return wpa_ctrl_command(ctrl, "ADD_NETWORK");
1197}
1198
1199
1200static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc,
1201 char *argv[])
1202{
1203 char cmd[32];
1204 int res;
1205
1206 if (argc < 1) {
1207 printf("Invalid REMOVE_NETWORK command: needs one argument "
1208 "(network id)\n");
1209 return -1;
1210 }
1211
1212 res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %s", argv[0]);
1213 if (res < 0 || (size_t) res >= sizeof(cmd))
1214 return -1;
1215 cmd[sizeof(cmd) - 1] = '\0';
1216
1217 return wpa_ctrl_command(ctrl, cmd);
1218}
1219
1220
1221static void wpa_cli_show_network_variables(void)
1222{
1223 printf("set_network variables:\n"
1224 " ssid (network name, SSID)\n"
1225 " psk (WPA passphrase or pre-shared key)\n"
1226 " key_mgmt (key management protocol)\n"
1227 " identity (EAP identity)\n"
1228 " password (EAP password)\n"
1229 " ...\n"
1230 "\n"
1231 "Note: Values are entered in the same format as the "
1232 "configuration file is using,\n"
1233 "i.e., strings values need to be inside double quotation "
1234 "marks.\n"
1235 "For example: set_network 1 ssid \"network name\"\n"
1236 "\n"
1237 "Please see wpa_supplicant.conf documentation for full list "
1238 "of\navailable variables.\n");
1239}
1240
1241
1242static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc,
1243 char *argv[])
1244{
1245 char cmd[256];
1246 int res;
1247
1248 if (argc == 0) {
1249 wpa_cli_show_network_variables();
1250 return 0;
1251 }
1252
1253 if (argc != 3) {
1254 printf("Invalid SET_NETWORK command: needs three arguments\n"
1255 "(network id, variable name, and value)\n");
1256 return -1;
1257 }
1258
1259 res = os_snprintf(cmd, sizeof(cmd), "SET_NETWORK %s %s %s",
1260 argv[0], argv[1], argv[2]);
1261 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
1262 printf("Too long SET_NETWORK command.\n");
1263 return -1;
1264 }
1265 return wpa_ctrl_command(ctrl, cmd);
1266}
1267
1268
1269static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
1270 char *argv[])
1271{
1272 char cmd[256];
1273 int res;
1274
1275 if (argc == 0) {
1276 wpa_cli_show_network_variables();
1277 return 0;
1278 }
1279
1280 if (argc != 2) {
1281 printf("Invalid GET_NETWORK command: needs two arguments\n"
1282 "(network id and variable name)\n");
1283 return -1;
1284 }
1285
1286 res = os_snprintf(cmd, sizeof(cmd), "GET_NETWORK %s %s",
1287 argv[0], argv[1]);
1288 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
1289 printf("Too long GET_NETWORK command.\n");
1290 return -1;
1291 }
1292 return wpa_ctrl_command(ctrl, cmd);
1293}
1294
1295
1296static int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc,
1297 char *argv[])
1298{
1299 return wpa_ctrl_command(ctrl, "DISCONNECT");
1300}
1301
1302
1303static int wpa_cli_cmd_reconnect(struct wpa_ctrl *ctrl, int argc,
1304 char *argv[])
1305{
1306 return wpa_ctrl_command(ctrl, "RECONNECT");
1307}
1308
1309
1310static int wpa_cli_cmd_save_config(struct wpa_ctrl *ctrl, int argc,
1311 char *argv[])
1312{
1313 return wpa_ctrl_command(ctrl, "SAVE_CONFIG");
1314}
1315
1316
1317static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
1318{
1319 return wpa_ctrl_command(ctrl, "SCAN");
1320}
1321
1322
1323static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc,
1324 char *argv[])
1325{
1326 return wpa_ctrl_command(ctrl, "SCAN_RESULTS");
1327}
1328
1329
1330static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
1331{
1332 char cmd[64];
1333 int res;
1334
1335 if (argc != 1) {
1336 printf("Invalid BSS command: need one argument (index or "
1337 "BSSID)\n");
1338 return -1;
1339 }
1340
1341 res = os_snprintf(cmd, sizeof(cmd), "BSS %s", argv[0]);
1342 if (res < 0 || (size_t) res >= sizeof(cmd))
1343 return -1;
1344 cmd[sizeof(cmd) - 1] = '\0';
1345
1346 return wpa_ctrl_command(ctrl, cmd);
1347}
1348
1349
1350static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
1351 char *argv[])
1352{
1353 char cmd[64];
1354 int res;
1355
1356 if (argc < 1 || argc > 2) {
1357 printf("Invalid GET_CAPABILITY command: need either one or "
1358 "two arguments\n");
1359 return -1;
1360 }
1361
1362 if ((argc == 2) && os_strcmp(argv[1], "strict") != 0) {
1363 printf("Invalid GET_CAPABILITY command: second argument, "
1364 "if any, must be 'strict'\n");
1365 return -1;
1366 }
1367
1368 res = os_snprintf(cmd, sizeof(cmd), "GET_CAPABILITY %s%s", argv[0],
1369 (argc == 2) ? " strict" : "");
1370 if (res < 0 || (size_t) res >= sizeof(cmd))
1371 return -1;
1372 cmd[sizeof(cmd) - 1] = '\0';
1373
1374 return wpa_ctrl_command(ctrl, cmd);
1375}
1376
1377
1378static int wpa_cli_list_interfaces(struct wpa_ctrl *ctrl)
1379{
1380 printf("Available interfaces:\n");
1381 return wpa_ctrl_command(ctrl, "INTERFACES");
1382}
1383
1384
1385static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[])
1386{
1387 if (argc < 1) {
1388 wpa_cli_list_interfaces(ctrl);
1389 return 0;
1390 }
1391
1392 wpa_cli_close_connection();
1393 os_free(ctrl_ifname);
1394 ctrl_ifname = os_strdup(argv[0]);
1395
4a3ade4e 1396 if (wpa_cli_open_connection(ctrl_ifname, 1)) {
6fc6879b 1397 printf("Connected to interface '%s.\n", ctrl_ifname);
6fc6879b
JM
1398 } else {
1399 printf("Could not connect to interface '%s' - re-trying\n",
1400 ctrl_ifname);
1401 }
1402 return 0;
1403}
1404
1405
1406static int wpa_cli_cmd_reconfigure(struct wpa_ctrl *ctrl, int argc,
1407 char *argv[])
1408{
1409 return wpa_ctrl_command(ctrl, "RECONFIGURE");
1410}
1411
1412
1413static int wpa_cli_cmd_terminate(struct wpa_ctrl *ctrl, int argc,
1414 char *argv[])
1415{
1416 return wpa_ctrl_command(ctrl, "TERMINATE");
1417}
1418
1419
1420static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc,
1421 char *argv[])
1422{
1423 char cmd[256];
1424 int res;
1425
1426 if (argc < 1) {
1427 printf("Invalid INTERFACE_ADD command: needs at least one "
1428 "argument (interface name)\n"
1429 "All arguments: ifname confname driver ctrl_interface "
1430 "driver_param bridge_name\n");
1431 return -1;
1432 }
1433
1434 /*
1435 * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
1436 * <driver_param>TAB<bridge_name>
1437 */
1438 res = os_snprintf(cmd, sizeof(cmd),
1439 "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s",
1440 argv[0],
1441 argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "",
1442 argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "",
1443 argc > 5 ? argv[5] : "");
1444 if (res < 0 || (size_t) res >= sizeof(cmd))
1445 return -1;
1446 cmd[sizeof(cmd) - 1] = '\0';
1447 return wpa_ctrl_command(ctrl, cmd);
1448}
1449
1450
1451static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc,
1452 char *argv[])
1453{
1454 char cmd[128];
1455 int res;
1456
1457 if (argc != 1) {
1458 printf("Invalid INTERFACE_REMOVE command: needs one argument "
1459 "(interface name)\n");
1460 return -1;
1461 }
1462
1463 res = os_snprintf(cmd, sizeof(cmd), "INTERFACE_REMOVE %s", argv[0]);
1464 if (res < 0 || (size_t) res >= sizeof(cmd))
1465 return -1;
1466 cmd[sizeof(cmd) - 1] = '\0';
1467 return wpa_ctrl_command(ctrl, cmd);
1468}
1469
1470
4b4a8ae5
JM
1471static int wpa_cli_cmd_interface_list(struct wpa_ctrl *ctrl, int argc,
1472 char *argv[])
1473{
1474 return wpa_ctrl_command(ctrl, "INTERFACE_LIST");
1475}
1476
1477
e653b622
JM
1478#ifdef CONFIG_AP
1479static int wpa_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
1480{
1481 char buf[64];
1482 if (argc != 1) {
1483 printf("Invalid 'sta' command - exactly one argument, STA "
1484 "address, is required.\n");
1485 return -1;
1486 }
e824cc46 1487 os_snprintf(buf, sizeof(buf), "STA %s", argv[0]);
e653b622
JM
1488 return wpa_ctrl_command(ctrl, buf);
1489}
1490
1491
1492static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
1493 char *addr, size_t addr_len)
1494{
1495 char buf[4096], *pos;
1496 size_t len;
1497 int ret;
1498
1499 if (ctrl_conn == NULL) {
1500 printf("Not connected to hostapd - command dropped.\n");
1501 return -1;
1502 }
1503 len = sizeof(buf) - 1;
1504 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
1505 wpa_cli_msg_cb);
1506 if (ret == -2) {
1507 printf("'%s' command timed out.\n", cmd);
1508 return -2;
1509 } else if (ret < 0) {
1510 printf("'%s' command failed.\n", cmd);
1511 return -1;
1512 }
1513
1514 buf[len] = '\0';
1515 if (memcmp(buf, "FAIL", 4) == 0)
1516 return -1;
1517 printf("%s", buf);
1518
1519 pos = buf;
1520 while (*pos != '\0' && *pos != '\n')
1521 pos++;
1522 *pos = '\0';
1523 os_strlcpy(addr, buf, addr_len);
1524 return 0;
1525}
1526
1527
1528static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
1529{
1530 char addr[32], cmd[64];
1531
1532 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
1533 return 0;
1534 do {
e824cc46 1535 os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
e653b622
JM
1536 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
1537
1538 return -1;
1539}
1540#endif /* CONFIG_AP */
1541
1542
207ef3fb
JM
1543static int wpa_cli_cmd_suspend(struct wpa_ctrl *ctrl, int argc, char *argv[])
1544{
1545 return wpa_ctrl_command(ctrl, "SUSPEND");
1546}
1547
1548
1549static int wpa_cli_cmd_resume(struct wpa_ctrl *ctrl, int argc, char *argv[])
1550{
1551 return wpa_ctrl_command(ctrl, "RESUME");
1552}
1553
1554
32d5295f
JM
1555static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[])
1556{
1557 return wpa_ctrl_command(ctrl, "DROP_SA");
1558}
1559
1560
86d4f806
JM
1561static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
1562{
1563 char cmd[128];
1564 int res;
1565
1566 if (argc != 1) {
1567 printf("Invalid ROAM command: needs one argument "
1568 "(target AP's BSSID)\n");
1569 return -1;
1570 }
1571
1572 res = os_snprintf(cmd, sizeof(cmd), "ROAM %s", argv[0]);
1573 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
1574 printf("Too long ROAM command.\n");
1575 return -1;
1576 }
1577 return wpa_ctrl_command(ctrl, cmd);
1578}
1579
1580
40fd868c
ER
1581enum wpa_cli_cmd_flags {
1582 cli_cmd_flag_none = 0x00,
1583 cli_cmd_flag_sensitive = 0x01
1584};
1585
6fc6879b
JM
1586struct wpa_cli_cmd {
1587 const char *cmd;
1588 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
40fd868c 1589 enum wpa_cli_cmd_flags flags;
dfa141b1 1590 const char *usage;
6fc6879b
JM
1591};
1592
1593static struct wpa_cli_cmd wpa_cli_commands[] = {
40fd868c 1594 { "status", wpa_cli_cmd_status,
dfa141b1
ER
1595 cli_cmd_flag_none,
1596 "[verbose] = get current WPA/EAPOL/EAP status" },
40fd868c 1597 { "ping", wpa_cli_cmd_ping,
dfa141b1
ER
1598 cli_cmd_flag_none,
1599 "= pings wpa_supplicant" },
77895cd9
JM
1600 { "note", wpa_cli_cmd_note,
1601 cli_cmd_flag_none,
1602 "<text> = add a note to wpa_supplicant debug log" },
40fd868c 1603 { "mib", wpa_cli_cmd_mib,
dfa141b1
ER
1604 cli_cmd_flag_none,
1605 "= get MIB variables (dot1x, dot11)" },
40fd868c 1606 { "help", wpa_cli_cmd_help,
dfa141b1
ER
1607 cli_cmd_flag_none,
1608 "= show this usage help" },
40fd868c 1609 { "interface", wpa_cli_cmd_interface,
dfa141b1
ER
1610 cli_cmd_flag_none,
1611 "[ifname] = show interfaces/select interface" },
40fd868c 1612 { "level", wpa_cli_cmd_level,
dfa141b1
ER
1613 cli_cmd_flag_none,
1614 "<debug level> = change debug level" },
40fd868c 1615 { "license", wpa_cli_cmd_license,
dfa141b1
ER
1616 cli_cmd_flag_none,
1617 "= show full wpa_cli license" },
40fd868c 1618 { "quit", wpa_cli_cmd_quit,
dfa141b1
ER
1619 cli_cmd_flag_none,
1620 "= exit wpa_cli" },
40fd868c 1621 { "set", wpa_cli_cmd_set,
dfa141b1
ER
1622 cli_cmd_flag_none,
1623 "= set variables (shows list of variables when run without "
1624 "arguments)" },
40fd868c 1625 { "logon", wpa_cli_cmd_logon,
dfa141b1
ER
1626 cli_cmd_flag_none,
1627 "= IEEE 802.1X EAPOL state machine logon" },
40fd868c 1628 { "logoff", wpa_cli_cmd_logoff,
dfa141b1
ER
1629 cli_cmd_flag_none,
1630 "= IEEE 802.1X EAPOL state machine logoff" },
40fd868c 1631 { "pmksa", wpa_cli_cmd_pmksa,
dfa141b1
ER
1632 cli_cmd_flag_none,
1633 "= show PMKSA cache" },
40fd868c 1634 { "reassociate", wpa_cli_cmd_reassociate,
dfa141b1
ER
1635 cli_cmd_flag_none,
1636 "= force reassociation" },
40fd868c 1637 { "preauthenticate", wpa_cli_cmd_preauthenticate,
dfa141b1
ER
1638 cli_cmd_flag_none,
1639 "<BSSID> = force preauthentication" },
40fd868c 1640 { "identity", wpa_cli_cmd_identity,
dfa141b1
ER
1641 cli_cmd_flag_none,
1642 "<network id> <identity> = configure identity for an SSID" },
40fd868c 1643 { "password", wpa_cli_cmd_password,
dfa141b1
ER
1644 cli_cmd_flag_sensitive,
1645 "<network id> <password> = configure password for an SSID" },
40fd868c 1646 { "new_password", wpa_cli_cmd_new_password,
dfa141b1
ER
1647 cli_cmd_flag_sensitive,
1648 "<network id> <password> = change password for an SSID" },
40fd868c 1649 { "pin", wpa_cli_cmd_pin,
dfa141b1
ER
1650 cli_cmd_flag_sensitive,
1651 "<network id> <pin> = configure pin for an SSID" },
40fd868c 1652 { "otp", wpa_cli_cmd_otp,
dfa141b1
ER
1653 cli_cmd_flag_sensitive,
1654 "<network id> <password> = configure one-time-password for an SSID"
1655 },
40fd868c 1656 { "passphrase", wpa_cli_cmd_passphrase,
dfa141b1
ER
1657 cli_cmd_flag_sensitive,
1658 "<network id> <passphrase> = configure private key passphrase\n"
1659 " for an SSID" },
40fd868c 1660 { "bssid", wpa_cli_cmd_bssid,
dfa141b1
ER
1661 cli_cmd_flag_none,
1662 "<network id> <BSSID> = set preferred BSSID for an SSID" },
40fd868c 1663 { "list_networks", wpa_cli_cmd_list_networks,
dfa141b1
ER
1664 cli_cmd_flag_none,
1665 "= list configured networks" },
40fd868c 1666 { "select_network", wpa_cli_cmd_select_network,
dfa141b1
ER
1667 cli_cmd_flag_none,
1668 "<network id> = select a network (disable others)" },
40fd868c 1669 { "enable_network", wpa_cli_cmd_enable_network,
dfa141b1
ER
1670 cli_cmd_flag_none,
1671 "<network id> = enable a network" },
40fd868c 1672 { "disable_network", wpa_cli_cmd_disable_network,
dfa141b1
ER
1673 cli_cmd_flag_none,
1674 "<network id> = disable a network" },
40fd868c 1675 { "add_network", wpa_cli_cmd_add_network,
dfa141b1
ER
1676 cli_cmd_flag_none,
1677 "= add a network" },
40fd868c 1678 { "remove_network", wpa_cli_cmd_remove_network,
dfa141b1
ER
1679 cli_cmd_flag_none,
1680 "<network id> = remove a network" },
40fd868c 1681 { "set_network", wpa_cli_cmd_set_network,
dfa141b1
ER
1682 cli_cmd_flag_sensitive,
1683 "<network id> <variable> <value> = set network variables (shows\n"
1684 " list of variables when run without arguments)" },
40fd868c 1685 { "get_network", wpa_cli_cmd_get_network,
dfa141b1
ER
1686 cli_cmd_flag_none,
1687 "<network id> <variable> = get network variables" },
40fd868c 1688 { "save_config", wpa_cli_cmd_save_config,
dfa141b1
ER
1689 cli_cmd_flag_none,
1690 "= save the current configuration" },
40fd868c 1691 { "disconnect", wpa_cli_cmd_disconnect,
dfa141b1
ER
1692 cli_cmd_flag_none,
1693 "= disconnect and wait for reassociate/reconnect command before\n"
1694 " connecting" },
40fd868c 1695 { "reconnect", wpa_cli_cmd_reconnect,
dfa141b1
ER
1696 cli_cmd_flag_none,
1697 "= like reassociate, but only takes effect if already disconnected"
1698 },
40fd868c 1699 { "scan", wpa_cli_cmd_scan,
dfa141b1
ER
1700 cli_cmd_flag_none,
1701 "= request new BSS scan" },
40fd868c 1702 { "scan_results", wpa_cli_cmd_scan_results,
dfa141b1
ER
1703 cli_cmd_flag_none,
1704 "= get latest scan results" },
40fd868c 1705 { "bss", wpa_cli_cmd_bss,
dfa141b1
ER
1706 cli_cmd_flag_none,
1707 "<<idx> | <bssid>> = get detailed scan result info" },
40fd868c 1708 { "get_capability", wpa_cli_cmd_get_capability,
dfa141b1
ER
1709 cli_cmd_flag_none,
1710 "<eap/pairwise/group/key_mgmt/proto/auth_alg> = get capabilies" },
40fd868c 1711 { "reconfigure", wpa_cli_cmd_reconfigure,
dfa141b1
ER
1712 cli_cmd_flag_none,
1713 "= force wpa_supplicant to re-read its configuration file" },
40fd868c 1714 { "terminate", wpa_cli_cmd_terminate,
dfa141b1
ER
1715 cli_cmd_flag_none,
1716 "= terminate wpa_supplicant" },
40fd868c 1717 { "interface_add", wpa_cli_cmd_interface_add,
dfa141b1
ER
1718 cli_cmd_flag_none,
1719 "<ifname> <confname> <driver> <ctrl_interface> <driver_param>\n"
1720 " <bridge_name> = adds new interface, all parameters but <ifname>\n"
1721 " are optional" },
40fd868c 1722 { "interface_remove", wpa_cli_cmd_interface_remove,
dfa141b1
ER
1723 cli_cmd_flag_none,
1724 "<ifname> = removes the interface" },
40fd868c 1725 { "interface_list", wpa_cli_cmd_interface_list,
dfa141b1
ER
1726 cli_cmd_flag_none,
1727 "= list available interfaces" },
40fd868c 1728 { "ap_scan", wpa_cli_cmd_ap_scan,
dfa141b1
ER
1729 cli_cmd_flag_none,
1730 "<value> = set ap_scan parameter" },
40fd868c 1731 { "stkstart", wpa_cli_cmd_stkstart,
dfa141b1
ER
1732 cli_cmd_flag_none,
1733 "<addr> = request STK negotiation with <addr>" },
40fd868c 1734 { "ft_ds", wpa_cli_cmd_ft_ds,
dfa141b1
ER
1735 cli_cmd_flag_none,
1736 "<addr> = request over-the-DS FT with <addr>" },
40fd868c 1737 { "wps_pbc", wpa_cli_cmd_wps_pbc,
dfa141b1
ER
1738 cli_cmd_flag_none,
1739 "[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" },
40fd868c 1740 { "wps_pin", wpa_cli_cmd_wps_pin,
dfa141b1
ER
1741 cli_cmd_flag_sensitive,
1742 "<BSSID> [PIN] = start WPS PIN method (returns PIN, if not "
1743 "hardcoded)" },
116f7bb0 1744#ifdef CONFIG_WPS_OOB
46bdb83a
MH
1745 { "wps_oob", wpa_cli_cmd_wps_oob,
1746 cli_cmd_flag_sensitive,
e1ee6b60 1747 "<DEV_TYPE> <PATH> <METHOD> [DEV_NAME] = start WPS OOB" },
116f7bb0 1748#endif /* CONFIG_WPS_OOB */
40fd868c 1749 { "wps_reg", wpa_cli_cmd_wps_reg,
dfa141b1
ER
1750 cli_cmd_flag_sensitive,
1751 "<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
e9bcfebf
JM
1752 { "wps_er_start", wpa_cli_cmd_wps_er_start,
1753 cli_cmd_flag_none,
08486685 1754 "[IP address] = start Wi-Fi Protected Setup External Registrar" },
e9bcfebf
JM
1755 { "wps_er_stop", wpa_cli_cmd_wps_er_stop,
1756 cli_cmd_flag_none,
1757 "= stop Wi-Fi Protected Setup External Registrar" },
72df2f5f
JM
1758 { "wps_er_pin", wpa_cli_cmd_wps_er_pin,
1759 cli_cmd_flag_sensitive,
1760 "<UUID> <PIN> = add an Enrollee PIN to External Registrar" },
564cd7fa
JM
1761 { "wps_er_pbc", wpa_cli_cmd_wps_er_pbc,
1762 cli_cmd_flag_none,
1763 "<UUID> = accept an Enrollee PBC using External Registrar" },
e64dcfd5
JM
1764 { "wps_er_learn", wpa_cli_cmd_wps_er_learn,
1765 cli_cmd_flag_sensitive,
1766 "<UUID> <PIN> = learn AP configuration" },
7d6640a6
JM
1767 { "wps_er_config", wpa_cli_cmd_wps_er_config,
1768 cli_cmd_flag_sensitive,
1769 "<UUID> <PIN> <SSID> <auth> <encr> <key> = configure AP" },
11ef8d35
JM
1770 { "ibss_rsn", wpa_cli_cmd_ibss_rsn,
1771 cli_cmd_flag_none,
1772 "<addr> = request RSN authentication with <addr> in IBSS" },
e653b622
JM
1773#ifdef CONFIG_AP
1774 { "sta", wpa_cli_cmd_sta,
1775 cli_cmd_flag_none,
1776 "<addr> = get information about an associated station (AP)" },
1777 { "all_sta", wpa_cli_cmd_all_sta,
1778 cli_cmd_flag_none,
1779 "= get information about all associated stations (AP)" },
1780#endif /* CONFIG_AP */
207ef3fb
JM
1781 { "suspend", wpa_cli_cmd_suspend, cli_cmd_flag_none,
1782 "= notification of suspend/hibernate" },
1783 { "resume", wpa_cli_cmd_resume, cli_cmd_flag_none,
1784 "= notification of resume/thaw" },
32d5295f
JM
1785 { "drop_sa", wpa_cli_cmd_drop_sa, cli_cmd_flag_none,
1786 "= drop SA without deauth/disassoc (test command)" },
86d4f806
JM
1787 { "roam", wpa_cli_cmd_roam,
1788 cli_cmd_flag_none,
1789 "<addr> = roam to the specified BSS" },
dfa141b1 1790 { NULL, NULL, cli_cmd_flag_none, NULL }
6fc6879b
JM
1791};
1792
1793
dfa141b1
ER
1794/*
1795 * Prints command usage, lines are padded with the specified string.
1796 */
1797static void print_cmd_help(struct wpa_cli_cmd *cmd, const char *pad)
1798{
1799 char c;
1800 size_t n;
1801
1802 printf("%s%s ", pad, cmd->cmd);
1803 for (n = 0; (c = cmd->usage[n]); n++) {
1804 printf("%c", c);
1805 if (c == '\n')
1806 printf("%s", pad);
1807 }
1808 printf("\n");
1809}
1810
1811
1812static void print_help(void)
1813{
1814 int n;
1815 printf("commands:\n");
1816 for (n = 0; wpa_cli_commands[n].cmd; n++)
1817 print_cmd_help(&wpa_cli_commands[n], " ");
1818}
1819
1820
40fd868c
ER
1821#ifdef CONFIG_READLINE
1822static int cmd_has_sensitive_data(const char *cmd)
1823{
1824 const char *c, *delim;
1825 int n;
1826 size_t len;
1827
1828 delim = os_strchr(cmd, ' ');
1829 if (delim)
1830 len = delim - cmd;
1831 else
1832 len = os_strlen(cmd);
1833
1834 for (n = 0; (c = wpa_cli_commands[n].cmd); n++) {
1835 if (os_strncasecmp(cmd, c, len) == 0 && len == os_strlen(c))
1836 return (wpa_cli_commands[n].flags &
1837 cli_cmd_flag_sensitive);
1838 }
1839 return 0;
1840}
1841#endif /* CONFIG_READLINE */
1842
1843
6fc6879b
JM
1844static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
1845{
1846 struct wpa_cli_cmd *cmd, *match = NULL;
1847 int count;
1848 int ret = 0;
1849
1850 count = 0;
1851 cmd = wpa_cli_commands;
1852 while (cmd->cmd) {
1853 if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0)
1854 {
1855 match = cmd;
1856 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1857 /* we have an exact match */
1858 count = 1;
1859 break;
1860 }
1861 count++;
1862 }
1863 cmd++;
1864 }
1865
1866 if (count > 1) {
1867 printf("Ambiguous command '%s'; possible commands:", argv[0]);
1868 cmd = wpa_cli_commands;
1869 while (cmd->cmd) {
1870 if (os_strncasecmp(cmd->cmd, argv[0],
1871 os_strlen(argv[0])) == 0) {
1872 printf(" %s", cmd->cmd);
1873 }
1874 cmd++;
1875 }
1876 printf("\n");
1877 ret = 1;
1878 } else if (count == 0) {
1879 printf("Unknown command '%s'\n", argv[0]);
1880 ret = 1;
1881 } else {
1882 ret = match->handler(ctrl, argc - 1, &argv[1]);
1883 }
1884
1885 return ret;
1886}
1887
1888
1889static int str_match(const char *a, const char *b)
1890{
1891 return os_strncmp(a, b, os_strlen(b)) == 0;
1892}
1893
1894
1895static int wpa_cli_exec(const char *program, const char *arg1,
1896 const char *arg2)
1897{
1898 char *cmd;
1899 size_t len;
1900 int res;
308a4ec8 1901 int ret = 0;
6fc6879b
JM
1902
1903 len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
1904 cmd = os_malloc(len);
1905 if (cmd == NULL)
1906 return -1;
1907 res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
1908 if (res < 0 || (size_t) res >= len) {
1909 os_free(cmd);
1910 return -1;
1911 }
1912 cmd[len - 1] = '\0';
1913#ifndef _WIN32_WCE
308a4ec8
JM
1914 if (system(cmd) < 0)
1915 ret = -1;
6fc6879b
JM
1916#endif /* _WIN32_WCE */
1917 os_free(cmd);
1918
308a4ec8 1919 return ret;
6fc6879b
JM
1920}
1921
1922
1923static void wpa_cli_action_process(const char *msg)
1924{
1925 const char *pos;
1926 char *copy = NULL, *id, *pos2;
1927
1928 pos = msg;
1929 if (*pos == '<') {
1930 /* skip priority */
1931 pos = os_strchr(pos, '>');
1932 if (pos)
1933 pos++;
1934 else
1935 pos = msg;
1936 }
1937
1938 if (str_match(pos, WPA_EVENT_CONNECTED)) {
1939 int new_id = -1;
1940 os_unsetenv("WPA_ID");
1941 os_unsetenv("WPA_ID_STR");
1942 os_unsetenv("WPA_CTRL_DIR");
1943
1944 pos = os_strstr(pos, "[id=");
1945 if (pos)
1946 copy = os_strdup(pos + 4);
1947
1948 if (copy) {
1949 pos2 = id = copy;
1950 while (*pos2 && *pos2 != ' ')
1951 pos2++;
1952 *pos2++ = '\0';
1953 new_id = atoi(id);
1954 os_setenv("WPA_ID", id, 1);
1955 while (*pos2 && *pos2 != '=')
1956 pos2++;
1957 if (*pos2 == '=')
1958 pos2++;
1959 id = pos2;
1960 while (*pos2 && *pos2 != ']')
1961 pos2++;
1962 *pos2 = '\0';
1963 os_setenv("WPA_ID_STR", id, 1);
1964 os_free(copy);
1965 }
1966
1967 os_setenv("WPA_CTRL_DIR", ctrl_iface_dir, 1);
1968
1969 if (!wpa_cli_connected || new_id != wpa_cli_last_id) {
1970 wpa_cli_connected = 1;
1971 wpa_cli_last_id = new_id;
1972 wpa_cli_exec(action_file, ctrl_ifname, "CONNECTED");
1973 }
1974 } else if (str_match(pos, WPA_EVENT_DISCONNECTED)) {
1975 if (wpa_cli_connected) {
1976 wpa_cli_connected = 0;
1977 wpa_cli_exec(action_file, ctrl_ifname, "DISCONNECTED");
1978 }
1979 } else if (str_match(pos, WPA_EVENT_TERMINATING)) {
1980 printf("wpa_supplicant is terminating - stop monitoring\n");
1981 wpa_cli_quit = 1;
1982 }
1983}
1984
1985
1986#ifndef CONFIG_ANSI_C_EXTRA
1987static void wpa_cli_action_cb(char *msg, size_t len)
1988{
1989 wpa_cli_action_process(msg);
1990}
1991#endif /* CONFIG_ANSI_C_EXTRA */
1992
1993
1994static void wpa_cli_reconnect(void)
1995{
1996 wpa_cli_close_connection();
4a3ade4e 1997 wpa_cli_open_connection(ctrl_ifname, 1);
6fc6879b
JM
1998}
1999
2000
2001static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
2002 int action_monitor)
2003{
2004 int first = 1;
2005 if (ctrl_conn == NULL) {
2006 wpa_cli_reconnect();
2007 return;
2008 }
2009 while (wpa_ctrl_pending(ctrl) > 0) {
2010 char buf[256];
2011 size_t len = sizeof(buf) - 1;
2012 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
2013 buf[len] = '\0';
2014 if (action_monitor)
2015 wpa_cli_action_process(buf);
2016 else {
f3f0f648
JM
2017 if (wpa_cli_show_event(buf)) {
2018 if (in_read && first)
2019 printf("\r");
2020 first = 0;
2021 printf("%s\n", buf);
2022 readline_redraw();
2023 }
6fc6879b
JM
2024 }
2025 } else {
2026 printf("Could not read pending message.\n");
2027 break;
2028 }
2029 }
2030
2031 if (wpa_ctrl_pending(ctrl) < 0) {
2032 printf("Connection to wpa_supplicant lost - trying to "
2033 "reconnect\n");
2034 wpa_cli_reconnect();
2035 }
2036}
2037
2038
2039#ifdef CONFIG_READLINE
2040static char * wpa_cli_cmd_gen(const char *text, int state)
2041{
2042 static int i, len;
2043 const char *cmd;
2044
2045 if (state == 0) {
2046 i = 0;
2047 len = os_strlen(text);
2048 }
2049
2050 while ((cmd = wpa_cli_commands[i].cmd)) {
2051 i++;
2052 if (os_strncasecmp(cmd, text, len) == 0)
d566f415 2053 return strdup(cmd);
6fc6879b
JM
2054 }
2055
2056 return NULL;
2057}
2058
2059
2060static char * wpa_cli_dummy_gen(const char *text, int state)
2061{
a7918ec7
JM
2062 int i;
2063
2064 for (i = 0; wpa_cli_commands[i].cmd; i++) {
2065 const char *cmd = wpa_cli_commands[i].cmd;
2066 size_t len = os_strlen(cmd);
2067 if (os_strncasecmp(rl_line_buffer, cmd, len) == 0 &&
2068 rl_line_buffer[len] == ' ') {
2069 printf("\n%s\n", wpa_cli_commands[i].usage);
f3f0f648 2070 readline_redraw();
a7918ec7
JM
2071 break;
2072 }
2073 }
2074
2075 rl_attempted_completion_over = 1;
2076 return NULL;
2077}
2078
2079
2080static char * wpa_cli_status_gen(const char *text, int state)
2081{
2082 static int i, len;
2083 char *options[] = {
2084 "verbose", NULL
2085 };
2086 char *t;
2087
2088 if (state == 0) {
2089 i = 0;
2090 len = os_strlen(text);
2091 }
2092
2093 while ((t = options[i])) {
2094 i++;
2095 if (os_strncasecmp(t, text, len) == 0)
2096 return strdup(t);
2097 }
2098
2099 rl_attempted_completion_over = 1;
6fc6879b
JM
2100 return NULL;
2101}
2102
2103
2104static char ** wpa_cli_completion(const char *text, int start, int end)
2105{
a7918ec7
JM
2106 char * (*func)(const char *text, int state);
2107
2108 if (start == 0)
2109 func = wpa_cli_cmd_gen;
2110 else if (os_strncasecmp(rl_line_buffer, "status ", 7) == 0)
2111 func = wpa_cli_status_gen;
2112 else
2113 func = wpa_cli_dummy_gen;
2114 return rl_completion_matches(text, func);
6fc6879b
JM
2115}
2116#endif /* CONFIG_READLINE */
2117
2118
2119static void wpa_cli_interactive(void)
2120{
2121#define max_args 10
2122 char cmdbuf[256], *cmd, *argv[max_args], *pos;
2123 int argc;
2124#ifdef CONFIG_READLINE
2125 char *home, *hfile = NULL;
2126#endif /* CONFIG_READLINE */
2127
2128 printf("\nInteractive mode\n\n");
2129
2130#ifdef CONFIG_READLINE
2131 rl_attempted_completion_function = wpa_cli_completion;
2132 home = getenv("HOME");
2133 if (home) {
2134 const char *fname = ".wpa_cli_history";
2135 int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
2136 hfile = os_malloc(hfile_len);
2137 if (hfile) {
2138 int res;
2139 res = os_snprintf(hfile, hfile_len, "%s/%s", home,
2140 fname);
2141 if (res >= 0 && res < hfile_len) {
2142 hfile[hfile_len - 1] = '\0';
2143 read_history(hfile);
2144 stifle_history(100);
2145 }
2146 }
2147 }
2148#endif /* CONFIG_READLINE */
2149
2150 do {
4a3ade4e 2151 wpa_cli_recv_pending(mon_conn, 0, 0);
6fc6879b 2152#ifndef CONFIG_NATIVE_WINDOWS
1cc84c1c 2153 alarm(ping_interval);
6fc6879b 2154#endif /* CONFIG_NATIVE_WINDOWS */
dd63f314
JM
2155#ifdef CONFIG_WPA_CLI_FORK
2156 if (mon_pid)
2157 kill(mon_pid, SIGUSR1);
2158#endif /* CONFIG_WPA_CLI_FORK */
6fc6879b
JM
2159#ifdef CONFIG_READLINE
2160 cmd = readline("> ");
2161 if (cmd && *cmd) {
2162 HIST_ENTRY *h;
2163 while (next_history())
2164 ;
2165 h = previous_history();
2166 if (h == NULL || os_strcmp(cmd, h->line) != 0)
2167 add_history(cmd);
2168 next_history();
2169 }
2170#else /* CONFIG_READLINE */
2171 printf("> ");
2172 cmd = fgets(cmdbuf, sizeof(cmdbuf), stdin);
2173#endif /* CONFIG_READLINE */
2174#ifndef CONFIG_NATIVE_WINDOWS
2175 alarm(0);
2176#endif /* CONFIG_NATIVE_WINDOWS */
2177 if (cmd == NULL)
2178 break;
4a3ade4e 2179 wpa_cli_recv_pending(mon_conn, 0, 0);
6fc6879b
JM
2180 pos = cmd;
2181 while (*pos != '\0') {
2182 if (*pos == '\n') {
2183 *pos = '\0';
2184 break;
2185 }
2186 pos++;
2187 }
2188 argc = 0;
2189 pos = cmd;
2190 for (;;) {
2191 while (*pos == ' ')
2192 pos++;
2193 if (*pos == '\0')
2194 break;
2195 argv[argc] = pos;
2196 argc++;
2197 if (argc == max_args)
2198 break;
2199 if (*pos == '"') {
2200 char *pos2 = os_strrchr(pos, '"');
2201 if (pos2)
2202 pos = pos2 + 1;
2203 }
2204 while (*pos != '\0' && *pos != ' ')
2205 pos++;
2206 if (*pos == ' ')
2207 *pos++ = '\0';
2208 }
2209 if (argc)
2210 wpa_request(ctrl_conn, argc, argv);
2211
2212 if (cmd != cmdbuf)
a24eb842 2213 free(cmd);
dd63f314
JM
2214#ifdef CONFIG_WPA_CLI_FORK
2215 if (mon_pid)
2216 kill(mon_pid, SIGUSR2);
2217#endif /* CONFIG_WPA_CLI_FORK */
6fc6879b
JM
2218 } while (!wpa_cli_quit);
2219
2220#ifdef CONFIG_READLINE
2221 if (hfile) {
2222 /* Save command history, excluding lines that may contain
2223 * passwords. */
2224 HIST_ENTRY *h;
2225 history_set_pos(0);
413653e8 2226 while ((h = current_history())) {
6fc6879b
JM
2227 char *p = h->line;
2228 while (*p == ' ' || *p == '\t')
2229 p++;
40fd868c 2230 if (cmd_has_sensitive_data(p)) {
6fc6879b
JM
2231 h = remove_history(where_history());
2232 if (h) {
2233 os_free(h->line);
2234 os_free(h->data);
2235 os_free(h);
413653e8
ER
2236 } else
2237 next_history();
2238 } else
2239 next_history();
6fc6879b
JM
2240 }
2241 write_history(hfile);
2242 os_free(hfile);
2243 }
2244#endif /* CONFIG_READLINE */
2245}
2246
2247
2248static void wpa_cli_action(struct wpa_ctrl *ctrl)
2249{
2250#ifdef CONFIG_ANSI_C_EXTRA
2251 /* TODO: ANSI C version(?) */
2252 printf("Action processing not supported in ANSI C build.\n");
2253#else /* CONFIG_ANSI_C_EXTRA */
2254 fd_set rfds;
2255 int fd, res;
2256 struct timeval tv;
2257 char buf[256]; /* note: large enough to fit in unsolicited messages */
2258 size_t len;
2259
2260 fd = wpa_ctrl_get_fd(ctrl);
2261
2262 while (!wpa_cli_quit) {
2263 FD_ZERO(&rfds);
2264 FD_SET(fd, &rfds);
1cc84c1c 2265 tv.tv_sec = ping_interval;
6fc6879b
JM
2266 tv.tv_usec = 0;
2267 res = select(fd + 1, &rfds, NULL, NULL, &tv);
2268 if (res < 0 && errno != EINTR) {
2269 perror("select");
2270 break;
2271 }
2272
2273 if (FD_ISSET(fd, &rfds))
2274 wpa_cli_recv_pending(ctrl, 0, 1);
2275 else {
2276 /* verify that connection is still working */
2277 len = sizeof(buf) - 1;
2278 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
2279 wpa_cli_action_cb) < 0 ||
2280 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
2281 printf("wpa_supplicant did not reply to PING "
2282 "command - exiting\n");
2283 break;
2284 }
2285 }
2286 }
2287#endif /* CONFIG_ANSI_C_EXTRA */
2288}
2289
2290
2291static void wpa_cli_cleanup(void)
2292{
2293 wpa_cli_close_connection();
2294 if (pid_file)
2295 os_daemonize_terminate(pid_file);
2296
2297 os_program_deinit();
2298}
2299
2300static void wpa_cli_terminate(int sig)
2301{
2302 wpa_cli_cleanup();
2303 exit(0);
2304}
2305
2306
dd63f314
JM
2307#ifdef CONFIG_WPA_CLI_FORK
2308static void wpa_cli_usr1(int sig)
2309{
f3f0f648 2310 readline_redraw();
dd63f314
JM
2311}
2312#endif /* CONFIG_WPA_CLI_FORK */
2313
2314
6fc6879b
JM
2315#ifndef CONFIG_NATIVE_WINDOWS
2316static void wpa_cli_alarm(int sig)
2317{
2318 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
2319 printf("Connection to wpa_supplicant lost - trying to "
2320 "reconnect\n");
2321 wpa_cli_close_connection();
2322 }
2323 if (!ctrl_conn)
2324 wpa_cli_reconnect();
4a3ade4e
JM
2325 if (mon_conn)
2326 wpa_cli_recv_pending(mon_conn, 1, 0);
1cc84c1c 2327 alarm(ping_interval);
6fc6879b
JM
2328}
2329#endif /* CONFIG_NATIVE_WINDOWS */
2330
2331
2332static char * wpa_cli_get_default_ifname(void)
2333{
2334 char *ifname = NULL;
2335
2336#ifdef CONFIG_CTRL_IFACE_UNIX
2337 struct dirent *dent;
2338 DIR *dir = opendir(ctrl_iface_dir);
2339 if (!dir)
2340 return NULL;
2341 while ((dent = readdir(dir))) {
2342#ifdef _DIRENT_HAVE_D_TYPE
2343 /*
2344 * Skip the file if it is not a socket. Also accept
2345 * DT_UNKNOWN (0) in case the C library or underlying
2346 * file system does not support d_type.
2347 */
2348 if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
2349 continue;
2350#endif /* _DIRENT_HAVE_D_TYPE */
2351 if (os_strcmp(dent->d_name, ".") == 0 ||
2352 os_strcmp(dent->d_name, "..") == 0)
2353 continue;
2354 printf("Selected interface '%s'\n", dent->d_name);
2355 ifname = os_strdup(dent->d_name);
2356 break;
2357 }
2358 closedir(dir);
2359#endif /* CONFIG_CTRL_IFACE_UNIX */
2360
2361#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
2362 char buf[2048], *pos;
2363 size_t len;
2364 struct wpa_ctrl *ctrl;
2365 int ret;
2366
2367 ctrl = wpa_ctrl_open(NULL);
2368 if (ctrl == NULL)
2369 return NULL;
2370
2371 len = sizeof(buf) - 1;
2372 ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL);
2373 if (ret >= 0) {
2374 buf[len] = '\0';
2375 pos = os_strchr(buf, '\n');
2376 if (pos)
2377 *pos = '\0';
2378 ifname = os_strdup(buf);
2379 }
2380 wpa_ctrl_close(ctrl);
2381#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
2382
2383 return ifname;
2384}
2385
2386
2387int main(int argc, char *argv[])
2388{
6fc6879b
JM
2389 int warning_displayed = 0;
2390 int c;
2391 int daemonize = 0;
2392 int ret = 0;
2393 const char *global = NULL;
2394
2395 if (os_program_init())
2396 return -1;
2397
2398 for (;;) {
1cc84c1c 2399 c = getopt(argc, argv, "a:Bg:G:hi:p:P:v");
6fc6879b
JM
2400 if (c < 0)
2401 break;
2402 switch (c) {
2403 case 'a':
2404 action_file = optarg;
2405 break;
2406 case 'B':
2407 daemonize = 1;
2408 break;
2409 case 'g':
2410 global = optarg;
2411 break;
1cc84c1c
JM
2412 case 'G':
2413 ping_interval = atoi(optarg);
2414 break;
6fc6879b
JM
2415 case 'h':
2416 usage();
2417 return 0;
2418 case 'v':
2419 printf("%s\n", wpa_cli_version);
2420 return 0;
2421 case 'i':
2422 os_free(ctrl_ifname);
2423 ctrl_ifname = os_strdup(optarg);
2424 break;
2425 case 'p':
2426 ctrl_iface_dir = optarg;
2427 break;
2428 case 'P':
2429 pid_file = optarg;
2430 break;
2431 default:
2432 usage();
2433 return -1;
2434 }
2435 }
2436
2437 interactive = (argc == optind) && (action_file == NULL);
2438
2439 if (interactive)
2440 printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license);
2441
2442 if (global) {
2443#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
2444 ctrl_conn = wpa_ctrl_open(NULL);
2445#else /* CONFIG_CTRL_IFACE_NAMED_PIPE */
2446 ctrl_conn = wpa_ctrl_open(global);
2447#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
2448 if (ctrl_conn == NULL) {
2449 perror("Failed to connect to wpa_supplicant - "
2450 "wpa_ctrl_open");
2451 return -1;
2452 }
2453 }
2454
6fc6879b
JM
2455#ifndef _WIN32_WCE
2456 signal(SIGINT, wpa_cli_terminate);
2457 signal(SIGTERM, wpa_cli_terminate);
2458#endif /* _WIN32_WCE */
2459#ifndef CONFIG_NATIVE_WINDOWS
2460 signal(SIGALRM, wpa_cli_alarm);
2461#endif /* CONFIG_NATIVE_WINDOWS */
dd63f314
JM
2462#ifdef CONFIG_WPA_CLI_FORK
2463 signal(SIGUSR1, wpa_cli_usr1);
2464#endif /* CONFIG_WPA_CLI_FORK */
6fc6879b 2465
4a3ade4e
JM
2466 if (ctrl_ifname == NULL)
2467 ctrl_ifname = wpa_cli_get_default_ifname();
2468
2469 if (interactive) {
2470 for (; !global;) {
2471 if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
2472 if (warning_displayed)
2473 printf("Connection established.\n");
2474 break;
2475 }
2476
2477 if (!warning_displayed) {
2478 printf("Could not connect to wpa_supplicant - "
2479 "re-trying\n");
2480 warning_displayed = 1;
2481 }
2482 os_sleep(1, 0);
2483 continue;
2484 }
2485 } else {
2486 if (!global &&
2487 wpa_cli_open_connection(ctrl_ifname, 0) < 0) {
2488 perror("Failed to connect to wpa_supplicant - "
2489 "wpa_ctrl_open");
2490 return -1;
2491 }
2492
2493 if (action_file) {
2494 if (wpa_ctrl_attach(ctrl_conn) == 0) {
2495 wpa_cli_attached = 1;
2496 } else {
2497 printf("Warning: Failed to attach to "
2498 "wpa_supplicant.\n");
6fc6879b 2499 return -1;
4a3ade4e 2500 }
6fc6879b
JM
2501 }
2502 }
2503
2504 if (daemonize && os_daemonize(pid_file))
2505 return -1;
2506
2507 if (interactive)
2508 wpa_cli_interactive();
2509 else if (action_file)
2510 wpa_cli_action(ctrl_conn);
2511 else
2512 ret = wpa_request(ctrl_conn, argc - optind, &argv[optind]);
2513
2514 os_free(ctrl_ifname);
2515 wpa_cli_cleanup();
2516
2517 return ret;
2518}
2519
2520#else /* CONFIG_CTRL_IFACE */
2521int main(int argc, char *argv[])
2522{
2523 printf("CONFIG_CTRL_IFACE not defined - wpa_cli disabled\n");
2524 return -1;
2525}
2526#endif /* CONFIG_CTRL_IFACE */