]> git.ipfire.org Git - thirdparty/hostap.git/blame - wpa_supplicant/wpa_cli.c
Renamed PMKSA cache functions to avoid duplicate symbols with supplicant
[thirdparty/hostap.git] / wpa_supplicant / wpa_cli.c
CommitLineData
6fc6879b
JM
1/*
2 * WPA Supplicant - command line interface for wpa_supplicant daemon
6f78f2fb 3 * Copyright (c) 2004-2009, 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 */
26
27#include "wpa_ctrl.h"
28#include "common.h"
29#include "version.h"
30
31
32static const char *wpa_cli_version =
33"wpa_cli v" VERSION_STR "\n"
6f78f2fb 34"Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> and contributors";
6fc6879b
JM
35
36
37static const char *wpa_cli_license =
38"This program is free software. You can distribute it and/or modify it\n"
39"under the terms of the GNU General Public License version 2.\n"
40"\n"
41"Alternatively, this software may be distributed under the terms of the\n"
42"BSD license. See README and COPYING for more details.\n";
43
44static const char *wpa_cli_full_license =
45"This program is free software; you can redistribute it and/or modify\n"
46"it under the terms of the GNU General Public License version 2 as\n"
47"published by the Free Software Foundation.\n"
48"\n"
49"This program is distributed in the hope that it will be useful,\n"
50"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
51"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
52"GNU General Public License for more details.\n"
53"\n"
54"You should have received a copy of the GNU General Public License\n"
55"along with this program; if not, write to the Free Software\n"
56"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
57"\n"
58"Alternatively, this software may be distributed under the terms of the\n"
59"BSD license.\n"
60"\n"
61"Redistribution and use in source and binary forms, with or without\n"
62"modification, are permitted provided that the following conditions are\n"
63"met:\n"
64"\n"
65"1. Redistributions of source code must retain the above copyright\n"
66" notice, this list of conditions and the following disclaimer.\n"
67"\n"
68"2. Redistributions in binary form must reproduce the above copyright\n"
69" notice, this list of conditions and the following disclaimer in the\n"
70" documentation and/or other materials provided with the distribution.\n"
71"\n"
72"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
73" names of its contributors may be used to endorse or promote products\n"
74" derived from this software without specific prior written permission.\n"
75"\n"
76"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
77"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
78"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
79"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
80"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
81"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
82"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
83"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
84"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
85"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
86"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
87"\n";
88
6fc6879b
JM
89static struct wpa_ctrl *ctrl_conn;
90static int wpa_cli_quit = 0;
91static int wpa_cli_attached = 0;
92static int wpa_cli_connected = 0;
93static int wpa_cli_last_id = 0;
94static const char *ctrl_iface_dir = "/var/run/wpa_supplicant";
95static char *ctrl_ifname = NULL;
96static const char *pid_file = NULL;
97static const char *action_file = NULL;
98
99
dfa141b1
ER
100static void print_help();
101
102
6fc6879b
JM
103static void usage(void)
104{
105 printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] "
106 "[-a<action file>] \\\n"
107 " [-P<pid file>] [-g<global ctrl>] [command..]\n"
108 " -h = help (show this usage text)\n"
109 " -v = shown version information\n"
110 " -a = run in daemon mode executing the action file based on "
111 "events from\n"
112 " wpa_supplicant\n"
113 " -B = run a daemon in the background\n"
114 " default path: /var/run/wpa_supplicant\n"
dfa141b1
ER
115 " default interface: first interface found in socket path\n");
116 print_help();
6fc6879b
JM
117}
118
119
120static struct wpa_ctrl * wpa_cli_open_connection(const char *ifname)
121{
122#if defined(CONFIG_CTRL_IFACE_UDP) || defined(CONFIG_CTRL_IFACE_NAMED_PIPE)
123 ctrl_conn = wpa_ctrl_open(ifname);
124 return ctrl_conn;
125#else /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
126 char *cfile;
127 int flen, res;
128
129 if (ifname == NULL)
130 return NULL;
131
132 flen = os_strlen(ctrl_iface_dir) + os_strlen(ifname) + 2;
133 cfile = os_malloc(flen);
134 if (cfile == NULL)
135 return NULL;
136 res = os_snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
137 if (res < 0 || res >= flen) {
138 os_free(cfile);
139 return NULL;
140 }
141
142 ctrl_conn = wpa_ctrl_open(cfile);
143 os_free(cfile);
144 return ctrl_conn;
145#endif /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
146}
147
148
149static void wpa_cli_close_connection(void)
150{
151 if (ctrl_conn == NULL)
152 return;
153
154 if (wpa_cli_attached) {
155 wpa_ctrl_detach(ctrl_conn);
156 wpa_cli_attached = 0;
157 }
158 wpa_ctrl_close(ctrl_conn);
159 ctrl_conn = NULL;
160}
161
162
163static void wpa_cli_msg_cb(char *msg, size_t len)
164{
165 printf("%s\n", msg);
166}
167
168
169static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
170{
171 char buf[2048];
172 size_t len;
173 int ret;
174
175 if (ctrl_conn == NULL) {
176 printf("Not connected to wpa_supplicant - command dropped.\n");
177 return -1;
178 }
179 len = sizeof(buf) - 1;
180 ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
181 wpa_cli_msg_cb);
182 if (ret == -2) {
183 printf("'%s' command timed out.\n", cmd);
184 return -2;
185 } else if (ret < 0) {
186 printf("'%s' command failed.\n", cmd);
187 return -1;
188 }
189 if (print) {
190 buf[len] = '\0';
191 printf("%s", buf);
192 }
193 return 0;
194}
195
196
197static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
198{
199 return _wpa_ctrl_command(ctrl, cmd, 1);
200}
201
202
203static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
204{
205 int verbose = argc > 0 && os_strcmp(argv[0], "verbose") == 0;
206 return wpa_ctrl_command(ctrl, verbose ? "STATUS-VERBOSE" : "STATUS");
207}
208
209
210static int wpa_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
211{
212 return wpa_ctrl_command(ctrl, "PING");
213}
214
215
216static int wpa_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
217{
218 return wpa_ctrl_command(ctrl, "MIB");
219}
220
221
222static int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
223{
224 return wpa_ctrl_command(ctrl, "PMKSA");
225}
226
227
228static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
229{
dfa141b1 230 print_help();
6fc6879b
JM
231 return 0;
232}
233
234
235static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[])
236{
237 printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license);
238 return 0;
239}
240
241
242static int wpa_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
243{
244 wpa_cli_quit = 1;
245 return 0;
246}
247
248
249static void wpa_cli_show_variables(void)
250{
251 printf("set variables:\n"
252 " EAPOL::heldPeriod (EAPOL state machine held period, "
253 "in seconds)\n"
254 " EAPOL::authPeriod (EAPOL state machine authentication "
255 "period, in seconds)\n"
256 " EAPOL::startPeriod (EAPOL state machine start period, in "
257 "seconds)\n"
258 " EAPOL::maxStart (EAPOL state machine maximum start "
259 "attempts)\n");
260 printf(" dot11RSNAConfigPMKLifetime (WPA/WPA2 PMK lifetime in "
261 "seconds)\n"
262 " dot11RSNAConfigPMKReauthThreshold (WPA/WPA2 reauthentication"
263 " threshold\n\tpercentage)\n"
264 " dot11RSNAConfigSATimeout (WPA/WPA2 timeout for completing "
265 "security\n\tassociation in seconds)\n");
266}
267
268
269static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
270{
271 char cmd[256];
272 int res;
273
274 if (argc == 0) {
275 wpa_cli_show_variables();
276 return 0;
277 }
278
279 if (argc != 2) {
280 printf("Invalid SET command: needs two arguments (variable "
281 "name and value)\n");
282 return -1;
283 }
284
285 res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
286 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
287 printf("Too long SET command.\n");
288 return -1;
289 }
290 return wpa_ctrl_command(ctrl, cmd);
291}
292
293
294static int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[])
295{
296 return wpa_ctrl_command(ctrl, "LOGOFF");
297}
298
299
300static int wpa_cli_cmd_logon(struct wpa_ctrl *ctrl, int argc, char *argv[])
301{
302 return wpa_ctrl_command(ctrl, "LOGON");
303}
304
305
306static int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc,
307 char *argv[])
308{
309 return wpa_ctrl_command(ctrl, "REASSOCIATE");
310}
311
312
313static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc,
314 char *argv[])
315{
316 char cmd[256];
317 int res;
318
319 if (argc != 1) {
320 printf("Invalid PREAUTH command: needs one argument "
321 "(BSSID)\n");
322 return -1;
323 }
324
325 res = os_snprintf(cmd, sizeof(cmd), "PREAUTH %s", argv[0]);
326 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
327 printf("Too long PREAUTH command.\n");
328 return -1;
329 }
330 return wpa_ctrl_command(ctrl, cmd);
331}
332
333
334static int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
335{
336 char cmd[256];
337 int res;
338
339 if (argc != 1) {
340 printf("Invalid AP_SCAN command: needs one argument (ap_scan "
341 "value)\n");
342 return -1;
343 }
344 res = os_snprintf(cmd, sizeof(cmd), "AP_SCAN %s", argv[0]);
345 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
346 printf("Too long AP_SCAN command.\n");
347 return -1;
348 }
349 return wpa_ctrl_command(ctrl, cmd);
350}
351
352
353static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc,
354 char *argv[])
355{
356 char cmd[256];
357 int res;
358
359 if (argc != 1) {
360 printf("Invalid STKSTART command: needs one argument "
361 "(Peer STA MAC address)\n");
362 return -1;
363 }
364
365 res = os_snprintf(cmd, sizeof(cmd), "STKSTART %s", argv[0]);
366 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
367 printf("Too long STKSTART command.\n");
368 return -1;
369 }
370 return wpa_ctrl_command(ctrl, cmd);
371}
372
373
374static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[])
375{
376 char cmd[256];
377 int res;
378
379 if (argc != 1) {
380 printf("Invalid FT_DS command: needs one argument "
381 "(Target AP MAC address)\n");
382 return -1;
383 }
384
385 res = os_snprintf(cmd, sizeof(cmd), "FT_DS %s", argv[0]);
386 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
387 printf("Too long FT_DS command.\n");
388 return -1;
389 }
390 return wpa_ctrl_command(ctrl, cmd);
391}
392
393
fcc60db4
JM
394static int wpa_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[])
395{
396 char cmd[256];
397 int res;
398
399 if (argc == 0) {
400 /* Any BSSID */
401 return wpa_ctrl_command(ctrl, "WPS_PBC");
402 }
403
404 /* Specific BSSID */
405 res = os_snprintf(cmd, sizeof(cmd), "WPS_PBC %s", argv[0]);
406 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
407 printf("Too long WPS_PBC command.\n");
408 return -1;
409 }
410 return wpa_ctrl_command(ctrl, cmd);
411}
412
413
414static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
415{
416 char cmd[256];
417 int res;
418
419 if (argc == 0) {
420 printf("Invalid WPS_PIN command: need one or two arguments:\n"
421 "- BSSID: use 'any' to select any\n"
422 "- PIN: optional, used only with devices that have no "
423 "display\n");
424 return -1;
425 }
426
427 if (argc == 1) {
428 /* Use dynamically generated PIN (returned as reply) */
429 res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s", argv[0]);
430 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
431 printf("Too long WPS_PIN command.\n");
432 return -1;
433 }
434 return wpa_ctrl_command(ctrl, cmd);
435 }
436
437 /* Use hardcoded PIN from a label */
438 res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s", argv[0], argv[1]);
439 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
440 printf("Too long WPS_PIN command.\n");
441 return -1;
442 }
443 return wpa_ctrl_command(ctrl, cmd);
444}
445
446
447static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
448{
449 char cmd[256];
450 int res;
451
452 if (argc != 2) {
453 printf("Invalid WPS_REG command: need two arguments:\n"
454 "- BSSID: use 'any' to select any\n"
455 "- AP PIN\n");
456 return -1;
457 }
458
459 res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s", argv[0], argv[1]);
460 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
461 printf("Too long WPS_REG command.\n");
462 return -1;
463 }
464 return wpa_ctrl_command(ctrl, cmd);
465}
466
467
6fc6879b
JM
468static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
469{
470 char cmd[256];
471 int res;
472
473 if (argc != 1) {
474 printf("Invalid LEVEL command: needs one argument (debug "
475 "level)\n");
476 return -1;
477 }
478 res = os_snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
479 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
480 printf("Too long LEVEL command.\n");
481 return -1;
482 }
483 return wpa_ctrl_command(ctrl, cmd);
484}
485
486
487static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[])
488{
489 char cmd[256], *pos, *end;
490 int i, ret;
491
492 if (argc < 2) {
493 printf("Invalid IDENTITY command: needs two arguments "
494 "(network id and identity)\n");
495 return -1;
496 }
497
498 end = cmd + sizeof(cmd);
499 pos = cmd;
500 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s",
501 argv[0], argv[1]);
502 if (ret < 0 || ret >= end - pos) {
503 printf("Too long IDENTITY command.\n");
504 return -1;
505 }
506 pos += ret;
507 for (i = 2; i < argc; i++) {
508 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
509 if (ret < 0 || ret >= end - pos) {
510 printf("Too long IDENTITY command.\n");
511 return -1;
512 }
513 pos += ret;
514 }
515
516 return wpa_ctrl_command(ctrl, cmd);
517}
518
519
520static int wpa_cli_cmd_password(struct wpa_ctrl *ctrl, int argc, char *argv[])
521{
522 char cmd[256], *pos, *end;
523 int i, ret;
524
525 if (argc < 2) {
526 printf("Invalid PASSWORD command: needs two arguments "
527 "(network id and password)\n");
528 return -1;
529 }
530
531 end = cmd + sizeof(cmd);
532 pos = cmd;
533 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s",
534 argv[0], argv[1]);
535 if (ret < 0 || ret >= end - pos) {
536 printf("Too long PASSWORD command.\n");
537 return -1;
538 }
539 pos += ret;
540 for (i = 2; i < argc; i++) {
541 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
542 if (ret < 0 || ret >= end - pos) {
543 printf("Too long PASSWORD command.\n");
544 return -1;
545 }
546 pos += ret;
547 }
548
549 return wpa_ctrl_command(ctrl, cmd);
550}
551
552
553static int wpa_cli_cmd_new_password(struct wpa_ctrl *ctrl, int argc,
554 char *argv[])
555{
556 char cmd[256], *pos, *end;
557 int i, ret;
558
559 if (argc < 2) {
560 printf("Invalid NEW_PASSWORD command: needs two arguments "
561 "(network id and password)\n");
562 return -1;
563 }
564
565 end = cmd + sizeof(cmd);
566 pos = cmd;
567 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s",
568 argv[0], argv[1]);
569 if (ret < 0 || ret >= end - pos) {
570 printf("Too long NEW_PASSWORD command.\n");
571 return -1;
572 }
573 pos += ret;
574 for (i = 2; i < argc; i++) {
575 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
576 if (ret < 0 || ret >= end - pos) {
577 printf("Too long NEW_PASSWORD command.\n");
578 return -1;
579 }
580 pos += ret;
581 }
582
583 return wpa_ctrl_command(ctrl, cmd);
584}
585
586
587static int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
588{
589 char cmd[256], *pos, *end;
590 int i, ret;
591
592 if (argc < 2) {
593 printf("Invalid PIN command: needs two arguments "
594 "(network id and pin)\n");
595 return -1;
596 }
597
598 end = cmd + sizeof(cmd);
599 pos = cmd;
600 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s",
601 argv[0], argv[1]);
602 if (ret < 0 || ret >= end - pos) {
603 printf("Too long PIN command.\n");
604 return -1;
605 }
606 pos += ret;
607 for (i = 2; i < argc; i++) {
608 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
609 if (ret < 0 || ret >= end - pos) {
610 printf("Too long PIN command.\n");
611 return -1;
612 }
613 pos += ret;
614 }
615 return wpa_ctrl_command(ctrl, cmd);
616}
617
618
619static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[])
620{
621 char cmd[256], *pos, *end;
622 int i, ret;
623
624 if (argc < 2) {
625 printf("Invalid OTP command: needs two arguments (network "
626 "id and password)\n");
627 return -1;
628 }
629
630 end = cmd + sizeof(cmd);
631 pos = cmd;
632 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s",
633 argv[0], argv[1]);
634 if (ret < 0 || ret >= end - pos) {
635 printf("Too long OTP command.\n");
636 return -1;
637 }
638 pos += ret;
639 for (i = 2; i < argc; i++) {
640 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
641 if (ret < 0 || ret >= end - pos) {
642 printf("Too long OTP command.\n");
643 return -1;
644 }
645 pos += ret;
646 }
647
648 return wpa_ctrl_command(ctrl, cmd);
649}
650
651
652static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
653 char *argv[])
654{
655 char cmd[256], *pos, *end;
656 int i, ret;
657
658 if (argc < 2) {
659 printf("Invalid PASSPHRASE command: needs two arguments "
660 "(network id and passphrase)\n");
661 return -1;
662 }
663
664 end = cmd + sizeof(cmd);
665 pos = cmd;
666 ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s",
667 argv[0], argv[1]);
668 if (ret < 0 || ret >= end - pos) {
669 printf("Too long PASSPHRASE command.\n");
670 return -1;
671 }
672 pos += ret;
673 for (i = 2; i < argc; i++) {
674 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
675 if (ret < 0 || ret >= end - pos) {
676 printf("Too long PASSPHRASE command.\n");
677 return -1;
678 }
679 pos += ret;
680 }
681
682 return wpa_ctrl_command(ctrl, cmd);
683}
684
685
686static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[])
687{
688 char cmd[256], *pos, *end;
689 int i, ret;
690
691 if (argc < 2) {
692 printf("Invalid BSSID command: needs two arguments (network "
693 "id and BSSID)\n");
694 return -1;
695 }
696
697 end = cmd + sizeof(cmd);
698 pos = cmd;
699 ret = os_snprintf(pos, end - pos, "BSSID");
700 if (ret < 0 || ret >= end - pos) {
701 printf("Too long BSSID command.\n");
702 return -1;
703 }
704 pos += ret;
705 for (i = 0; i < argc; i++) {
706 ret = os_snprintf(pos, end - pos, " %s", argv[i]);
707 if (ret < 0 || ret >= end - pos) {
708 printf("Too long BSSID command.\n");
709 return -1;
710 }
711 pos += ret;
712 }
713
714 return wpa_ctrl_command(ctrl, cmd);
715}
716
717
718static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc,
719 char *argv[])
720{
721 return wpa_ctrl_command(ctrl, "LIST_NETWORKS");
722}
723
724
725static int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc,
726 char *argv[])
727{
728 char cmd[32];
729 int res;
730
731 if (argc < 1) {
732 printf("Invalid SELECT_NETWORK command: needs one argument "
733 "(network id)\n");
734 return -1;
735 }
736
737 res = os_snprintf(cmd, sizeof(cmd), "SELECT_NETWORK %s", argv[0]);
738 if (res < 0 || (size_t) res >= sizeof(cmd))
739 return -1;
740 cmd[sizeof(cmd) - 1] = '\0';
741
742 return wpa_ctrl_command(ctrl, cmd);
743}
744
745
746static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc,
747 char *argv[])
748{
749 char cmd[32];
750 int res;
751
752 if (argc < 1) {
753 printf("Invalid ENABLE_NETWORK command: needs one argument "
754 "(network id)\n");
755 return -1;
756 }
757
758 res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s", argv[0]);
759 if (res < 0 || (size_t) res >= sizeof(cmd))
760 return -1;
761 cmd[sizeof(cmd) - 1] = '\0';
762
763 return wpa_ctrl_command(ctrl, cmd);
764}
765
766
767static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc,
768 char *argv[])
769{
770 char cmd[32];
771 int res;
772
773 if (argc < 1) {
774 printf("Invalid DISABLE_NETWORK command: needs one argument "
775 "(network id)\n");
776 return -1;
777 }
778
779 res = os_snprintf(cmd, sizeof(cmd), "DISABLE_NETWORK %s", argv[0]);
780 if (res < 0 || (size_t) res >= sizeof(cmd))
781 return -1;
782 cmd[sizeof(cmd) - 1] = '\0';
783
784 return wpa_ctrl_command(ctrl, cmd);
785}
786
787
788static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc,
789 char *argv[])
790{
791 return wpa_ctrl_command(ctrl, "ADD_NETWORK");
792}
793
794
795static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc,
796 char *argv[])
797{
798 char cmd[32];
799 int res;
800
801 if (argc < 1) {
802 printf("Invalid REMOVE_NETWORK command: needs one argument "
803 "(network id)\n");
804 return -1;
805 }
806
807 res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %s", argv[0]);
808 if (res < 0 || (size_t) res >= sizeof(cmd))
809 return -1;
810 cmd[sizeof(cmd) - 1] = '\0';
811
812 return wpa_ctrl_command(ctrl, cmd);
813}
814
815
816static void wpa_cli_show_network_variables(void)
817{
818 printf("set_network variables:\n"
819 " ssid (network name, SSID)\n"
820 " psk (WPA passphrase or pre-shared key)\n"
821 " key_mgmt (key management protocol)\n"
822 " identity (EAP identity)\n"
823 " password (EAP password)\n"
824 " ...\n"
825 "\n"
826 "Note: Values are entered in the same format as the "
827 "configuration file is using,\n"
828 "i.e., strings values need to be inside double quotation "
829 "marks.\n"
830 "For example: set_network 1 ssid \"network name\"\n"
831 "\n"
832 "Please see wpa_supplicant.conf documentation for full list "
833 "of\navailable variables.\n");
834}
835
836
837static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc,
838 char *argv[])
839{
840 char cmd[256];
841 int res;
842
843 if (argc == 0) {
844 wpa_cli_show_network_variables();
845 return 0;
846 }
847
848 if (argc != 3) {
849 printf("Invalid SET_NETWORK command: needs three arguments\n"
850 "(network id, variable name, and value)\n");
851 return -1;
852 }
853
854 res = os_snprintf(cmd, sizeof(cmd), "SET_NETWORK %s %s %s",
855 argv[0], argv[1], argv[2]);
856 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
857 printf("Too long SET_NETWORK command.\n");
858 return -1;
859 }
860 return wpa_ctrl_command(ctrl, cmd);
861}
862
863
864static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
865 char *argv[])
866{
867 char cmd[256];
868 int res;
869
870 if (argc == 0) {
871 wpa_cli_show_network_variables();
872 return 0;
873 }
874
875 if (argc != 2) {
876 printf("Invalid GET_NETWORK command: needs two arguments\n"
877 "(network id and variable name)\n");
878 return -1;
879 }
880
881 res = os_snprintf(cmd, sizeof(cmd), "GET_NETWORK %s %s",
882 argv[0], argv[1]);
883 if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
884 printf("Too long GET_NETWORK command.\n");
885 return -1;
886 }
887 return wpa_ctrl_command(ctrl, cmd);
888}
889
890
891static int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc,
892 char *argv[])
893{
894 return wpa_ctrl_command(ctrl, "DISCONNECT");
895}
896
897
898static int wpa_cli_cmd_reconnect(struct wpa_ctrl *ctrl, int argc,
899 char *argv[])
900{
901 return wpa_ctrl_command(ctrl, "RECONNECT");
902}
903
904
905static int wpa_cli_cmd_save_config(struct wpa_ctrl *ctrl, int argc,
906 char *argv[])
907{
908 return wpa_ctrl_command(ctrl, "SAVE_CONFIG");
909}
910
911
912static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
913{
914 return wpa_ctrl_command(ctrl, "SCAN");
915}
916
917
918static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc,
919 char *argv[])
920{
921 return wpa_ctrl_command(ctrl, "SCAN_RESULTS");
922}
923
924
925static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
926{
927 char cmd[64];
928 int res;
929
930 if (argc != 1) {
931 printf("Invalid BSS command: need one argument (index or "
932 "BSSID)\n");
933 return -1;
934 }
935
936 res = os_snprintf(cmd, sizeof(cmd), "BSS %s", argv[0]);
937 if (res < 0 || (size_t) res >= sizeof(cmd))
938 return -1;
939 cmd[sizeof(cmd) - 1] = '\0';
940
941 return wpa_ctrl_command(ctrl, cmd);
942}
943
944
945static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
946 char *argv[])
947{
948 char cmd[64];
949 int res;
950
951 if (argc < 1 || argc > 2) {
952 printf("Invalid GET_CAPABILITY command: need either one or "
953 "two arguments\n");
954 return -1;
955 }
956
957 if ((argc == 2) && os_strcmp(argv[1], "strict") != 0) {
958 printf("Invalid GET_CAPABILITY command: second argument, "
959 "if any, must be 'strict'\n");
960 return -1;
961 }
962
963 res = os_snprintf(cmd, sizeof(cmd), "GET_CAPABILITY %s%s", argv[0],
964 (argc == 2) ? " strict" : "");
965 if (res < 0 || (size_t) res >= sizeof(cmd))
966 return -1;
967 cmd[sizeof(cmd) - 1] = '\0';
968
969 return wpa_ctrl_command(ctrl, cmd);
970}
971
972
973static int wpa_cli_list_interfaces(struct wpa_ctrl *ctrl)
974{
975 printf("Available interfaces:\n");
976 return wpa_ctrl_command(ctrl, "INTERFACES");
977}
978
979
980static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[])
981{
982 if (argc < 1) {
983 wpa_cli_list_interfaces(ctrl);
984 return 0;
985 }
986
987 wpa_cli_close_connection();
988 os_free(ctrl_ifname);
989 ctrl_ifname = os_strdup(argv[0]);
990
991 if (wpa_cli_open_connection(ctrl_ifname)) {
992 printf("Connected to interface '%s.\n", ctrl_ifname);
993 if (wpa_ctrl_attach(ctrl_conn) == 0) {
994 wpa_cli_attached = 1;
995 } else {
996 printf("Warning: Failed to attach to "
997 "wpa_supplicant.\n");
998 }
999 } else {
1000 printf("Could not connect to interface '%s' - re-trying\n",
1001 ctrl_ifname);
1002 }
1003 return 0;
1004}
1005
1006
1007static int wpa_cli_cmd_reconfigure(struct wpa_ctrl *ctrl, int argc,
1008 char *argv[])
1009{
1010 return wpa_ctrl_command(ctrl, "RECONFIGURE");
1011}
1012
1013
1014static int wpa_cli_cmd_terminate(struct wpa_ctrl *ctrl, int argc,
1015 char *argv[])
1016{
1017 return wpa_ctrl_command(ctrl, "TERMINATE");
1018}
1019
1020
1021static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc,
1022 char *argv[])
1023{
1024 char cmd[256];
1025 int res;
1026
1027 if (argc < 1) {
1028 printf("Invalid INTERFACE_ADD command: needs at least one "
1029 "argument (interface name)\n"
1030 "All arguments: ifname confname driver ctrl_interface "
1031 "driver_param bridge_name\n");
1032 return -1;
1033 }
1034
1035 /*
1036 * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
1037 * <driver_param>TAB<bridge_name>
1038 */
1039 res = os_snprintf(cmd, sizeof(cmd),
1040 "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s",
1041 argv[0],
1042 argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "",
1043 argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "",
1044 argc > 5 ? argv[5] : "");
1045 if (res < 0 || (size_t) res >= sizeof(cmd))
1046 return -1;
1047 cmd[sizeof(cmd) - 1] = '\0';
1048 return wpa_ctrl_command(ctrl, cmd);
1049}
1050
1051
1052static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc,
1053 char *argv[])
1054{
1055 char cmd[128];
1056 int res;
1057
1058 if (argc != 1) {
1059 printf("Invalid INTERFACE_REMOVE command: needs one argument "
1060 "(interface name)\n");
1061 return -1;
1062 }
1063
1064 res = os_snprintf(cmd, sizeof(cmd), "INTERFACE_REMOVE %s", argv[0]);
1065 if (res < 0 || (size_t) res >= sizeof(cmd))
1066 return -1;
1067 cmd[sizeof(cmd) - 1] = '\0';
1068 return wpa_ctrl_command(ctrl, cmd);
1069}
1070
1071
4b4a8ae5
JM
1072static int wpa_cli_cmd_interface_list(struct wpa_ctrl *ctrl, int argc,
1073 char *argv[])
1074{
1075 return wpa_ctrl_command(ctrl, "INTERFACE_LIST");
1076}
1077
1078
40fd868c
ER
1079enum wpa_cli_cmd_flags {
1080 cli_cmd_flag_none = 0x00,
1081 cli_cmd_flag_sensitive = 0x01
1082};
1083
6fc6879b
JM
1084struct wpa_cli_cmd {
1085 const char *cmd;
1086 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
40fd868c 1087 enum wpa_cli_cmd_flags flags;
dfa141b1 1088 const char *usage;
6fc6879b
JM
1089};
1090
1091static struct wpa_cli_cmd wpa_cli_commands[] = {
40fd868c 1092 { "status", wpa_cli_cmd_status,
dfa141b1
ER
1093 cli_cmd_flag_none,
1094 "[verbose] = get current WPA/EAPOL/EAP status" },
40fd868c 1095 { "ping", wpa_cli_cmd_ping,
dfa141b1
ER
1096 cli_cmd_flag_none,
1097 "= pings wpa_supplicant" },
40fd868c 1098 { "mib", wpa_cli_cmd_mib,
dfa141b1
ER
1099 cli_cmd_flag_none,
1100 "= get MIB variables (dot1x, dot11)" },
40fd868c 1101 { "help", wpa_cli_cmd_help,
dfa141b1
ER
1102 cli_cmd_flag_none,
1103 "= show this usage help" },
40fd868c 1104 { "interface", wpa_cli_cmd_interface,
dfa141b1
ER
1105 cli_cmd_flag_none,
1106 "[ifname] = show interfaces/select interface" },
40fd868c 1107 { "level", wpa_cli_cmd_level,
dfa141b1
ER
1108 cli_cmd_flag_none,
1109 "<debug level> = change debug level" },
40fd868c 1110 { "license", wpa_cli_cmd_license,
dfa141b1
ER
1111 cli_cmd_flag_none,
1112 "= show full wpa_cli license" },
40fd868c 1113 { "quit", wpa_cli_cmd_quit,
dfa141b1
ER
1114 cli_cmd_flag_none,
1115 "= exit wpa_cli" },
40fd868c 1116 { "set", wpa_cli_cmd_set,
dfa141b1
ER
1117 cli_cmd_flag_none,
1118 "= set variables (shows list of variables when run without "
1119 "arguments)" },
40fd868c 1120 { "logon", wpa_cli_cmd_logon,
dfa141b1
ER
1121 cli_cmd_flag_none,
1122 "= IEEE 802.1X EAPOL state machine logon" },
40fd868c 1123 { "logoff", wpa_cli_cmd_logoff,
dfa141b1
ER
1124 cli_cmd_flag_none,
1125 "= IEEE 802.1X EAPOL state machine logoff" },
40fd868c 1126 { "pmksa", wpa_cli_cmd_pmksa,
dfa141b1
ER
1127 cli_cmd_flag_none,
1128 "= show PMKSA cache" },
40fd868c 1129 { "reassociate", wpa_cli_cmd_reassociate,
dfa141b1
ER
1130 cli_cmd_flag_none,
1131 "= force reassociation" },
40fd868c 1132 { "preauthenticate", wpa_cli_cmd_preauthenticate,
dfa141b1
ER
1133 cli_cmd_flag_none,
1134 "<BSSID> = force preauthentication" },
40fd868c 1135 { "identity", wpa_cli_cmd_identity,
dfa141b1
ER
1136 cli_cmd_flag_none,
1137 "<network id> <identity> = configure identity for an SSID" },
40fd868c 1138 { "password", wpa_cli_cmd_password,
dfa141b1
ER
1139 cli_cmd_flag_sensitive,
1140 "<network id> <password> = configure password for an SSID" },
40fd868c 1141 { "new_password", wpa_cli_cmd_new_password,
dfa141b1
ER
1142 cli_cmd_flag_sensitive,
1143 "<network id> <password> = change password for an SSID" },
40fd868c 1144 { "pin", wpa_cli_cmd_pin,
dfa141b1
ER
1145 cli_cmd_flag_sensitive,
1146 "<network id> <pin> = configure pin for an SSID" },
40fd868c 1147 { "otp", wpa_cli_cmd_otp,
dfa141b1
ER
1148 cli_cmd_flag_sensitive,
1149 "<network id> <password> = configure one-time-password for an SSID"
1150 },
40fd868c 1151 { "passphrase", wpa_cli_cmd_passphrase,
dfa141b1
ER
1152 cli_cmd_flag_sensitive,
1153 "<network id> <passphrase> = configure private key passphrase\n"
1154 " for an SSID" },
40fd868c 1155 { "bssid", wpa_cli_cmd_bssid,
dfa141b1
ER
1156 cli_cmd_flag_none,
1157 "<network id> <BSSID> = set preferred BSSID for an SSID" },
40fd868c 1158 { "list_networks", wpa_cli_cmd_list_networks,
dfa141b1
ER
1159 cli_cmd_flag_none,
1160 "= list configured networks" },
40fd868c 1161 { "select_network", wpa_cli_cmd_select_network,
dfa141b1
ER
1162 cli_cmd_flag_none,
1163 "<network id> = select a network (disable others)" },
40fd868c 1164 { "enable_network", wpa_cli_cmd_enable_network,
dfa141b1
ER
1165 cli_cmd_flag_none,
1166 "<network id> = enable a network" },
40fd868c 1167 { "disable_network", wpa_cli_cmd_disable_network,
dfa141b1
ER
1168 cli_cmd_flag_none,
1169 "<network id> = disable a network" },
40fd868c 1170 { "add_network", wpa_cli_cmd_add_network,
dfa141b1
ER
1171 cli_cmd_flag_none,
1172 "= add a network" },
40fd868c 1173 { "remove_network", wpa_cli_cmd_remove_network,
dfa141b1
ER
1174 cli_cmd_flag_none,
1175 "<network id> = remove a network" },
40fd868c 1176 { "set_network", wpa_cli_cmd_set_network,
dfa141b1
ER
1177 cli_cmd_flag_sensitive,
1178 "<network id> <variable> <value> = set network variables (shows\n"
1179 " list of variables when run without arguments)" },
40fd868c 1180 { "get_network", wpa_cli_cmd_get_network,
dfa141b1
ER
1181 cli_cmd_flag_none,
1182 "<network id> <variable> = get network variables" },
40fd868c 1183 { "save_config", wpa_cli_cmd_save_config,
dfa141b1
ER
1184 cli_cmd_flag_none,
1185 "= save the current configuration" },
40fd868c 1186 { "disconnect", wpa_cli_cmd_disconnect,
dfa141b1
ER
1187 cli_cmd_flag_none,
1188 "= disconnect and wait for reassociate/reconnect command before\n"
1189 " connecting" },
40fd868c 1190 { "reconnect", wpa_cli_cmd_reconnect,
dfa141b1
ER
1191 cli_cmd_flag_none,
1192 "= like reassociate, but only takes effect if already disconnected"
1193 },
40fd868c 1194 { "scan", wpa_cli_cmd_scan,
dfa141b1
ER
1195 cli_cmd_flag_none,
1196 "= request new BSS scan" },
40fd868c 1197 { "scan_results", wpa_cli_cmd_scan_results,
dfa141b1
ER
1198 cli_cmd_flag_none,
1199 "= get latest scan results" },
40fd868c 1200 { "bss", wpa_cli_cmd_bss,
dfa141b1
ER
1201 cli_cmd_flag_none,
1202 "<<idx> | <bssid>> = get detailed scan result info" },
40fd868c 1203 { "get_capability", wpa_cli_cmd_get_capability,
dfa141b1
ER
1204 cli_cmd_flag_none,
1205 "<eap/pairwise/group/key_mgmt/proto/auth_alg> = get capabilies" },
40fd868c 1206 { "reconfigure", wpa_cli_cmd_reconfigure,
dfa141b1
ER
1207 cli_cmd_flag_none,
1208 "= force wpa_supplicant to re-read its configuration file" },
40fd868c 1209 { "terminate", wpa_cli_cmd_terminate,
dfa141b1
ER
1210 cli_cmd_flag_none,
1211 "= terminate wpa_supplicant" },
40fd868c 1212 { "interface_add", wpa_cli_cmd_interface_add,
dfa141b1
ER
1213 cli_cmd_flag_none,
1214 "<ifname> <confname> <driver> <ctrl_interface> <driver_param>\n"
1215 " <bridge_name> = adds new interface, all parameters but <ifname>\n"
1216 " are optional" },
40fd868c 1217 { "interface_remove", wpa_cli_cmd_interface_remove,
dfa141b1
ER
1218 cli_cmd_flag_none,
1219 "<ifname> = removes the interface" },
40fd868c 1220 { "interface_list", wpa_cli_cmd_interface_list,
dfa141b1
ER
1221 cli_cmd_flag_none,
1222 "= list available interfaces" },
40fd868c 1223 { "ap_scan", wpa_cli_cmd_ap_scan,
dfa141b1
ER
1224 cli_cmd_flag_none,
1225 "<value> = set ap_scan parameter" },
40fd868c 1226 { "stkstart", wpa_cli_cmd_stkstart,
dfa141b1
ER
1227 cli_cmd_flag_none,
1228 "<addr> = request STK negotiation with <addr>" },
40fd868c 1229 { "ft_ds", wpa_cli_cmd_ft_ds,
dfa141b1
ER
1230 cli_cmd_flag_none,
1231 "<addr> = request over-the-DS FT with <addr>" },
40fd868c 1232 { "wps_pbc", wpa_cli_cmd_wps_pbc,
dfa141b1
ER
1233 cli_cmd_flag_none,
1234 "[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" },
40fd868c 1235 { "wps_pin", wpa_cli_cmd_wps_pin,
dfa141b1
ER
1236 cli_cmd_flag_sensitive,
1237 "<BSSID> [PIN] = start WPS PIN method (returns PIN, if not "
1238 "hardcoded)" },
40fd868c 1239 { "wps_reg", wpa_cli_cmd_wps_reg,
dfa141b1
ER
1240 cli_cmd_flag_sensitive,
1241 "<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
1242 { NULL, NULL, cli_cmd_flag_none, NULL }
6fc6879b
JM
1243};
1244
1245
dfa141b1
ER
1246/*
1247 * Prints command usage, lines are padded with the specified string.
1248 */
1249static void print_cmd_help(struct wpa_cli_cmd *cmd, const char *pad)
1250{
1251 char c;
1252 size_t n;
1253
1254 printf("%s%s ", pad, cmd->cmd);
1255 for (n = 0; (c = cmd->usage[n]); n++) {
1256 printf("%c", c);
1257 if (c == '\n')
1258 printf("%s", pad);
1259 }
1260 printf("\n");
1261}
1262
1263
1264static void print_help(void)
1265{
1266 int n;
1267 printf("commands:\n");
1268 for (n = 0; wpa_cli_commands[n].cmd; n++)
1269 print_cmd_help(&wpa_cli_commands[n], " ");
1270}
1271
1272
40fd868c
ER
1273#ifdef CONFIG_READLINE
1274static int cmd_has_sensitive_data(const char *cmd)
1275{
1276 const char *c, *delim;
1277 int n;
1278 size_t len;
1279
1280 delim = os_strchr(cmd, ' ');
1281 if (delim)
1282 len = delim - cmd;
1283 else
1284 len = os_strlen(cmd);
1285
1286 for (n = 0; (c = wpa_cli_commands[n].cmd); n++) {
1287 if (os_strncasecmp(cmd, c, len) == 0 && len == os_strlen(c))
1288 return (wpa_cli_commands[n].flags &
1289 cli_cmd_flag_sensitive);
1290 }
1291 return 0;
1292}
1293#endif /* CONFIG_READLINE */
1294
1295
6fc6879b
JM
1296static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
1297{
1298 struct wpa_cli_cmd *cmd, *match = NULL;
1299 int count;
1300 int ret = 0;
1301
1302 count = 0;
1303 cmd = wpa_cli_commands;
1304 while (cmd->cmd) {
1305 if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0)
1306 {
1307 match = cmd;
1308 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1309 /* we have an exact match */
1310 count = 1;
1311 break;
1312 }
1313 count++;
1314 }
1315 cmd++;
1316 }
1317
1318 if (count > 1) {
1319 printf("Ambiguous command '%s'; possible commands:", argv[0]);
1320 cmd = wpa_cli_commands;
1321 while (cmd->cmd) {
1322 if (os_strncasecmp(cmd->cmd, argv[0],
1323 os_strlen(argv[0])) == 0) {
1324 printf(" %s", cmd->cmd);
1325 }
1326 cmd++;
1327 }
1328 printf("\n");
1329 ret = 1;
1330 } else if (count == 0) {
1331 printf("Unknown command '%s'\n", argv[0]);
1332 ret = 1;
1333 } else {
1334 ret = match->handler(ctrl, argc - 1, &argv[1]);
1335 }
1336
1337 return ret;
1338}
1339
1340
1341static int str_match(const char *a, const char *b)
1342{
1343 return os_strncmp(a, b, os_strlen(b)) == 0;
1344}
1345
1346
1347static int wpa_cli_exec(const char *program, const char *arg1,
1348 const char *arg2)
1349{
1350 char *cmd;
1351 size_t len;
1352 int res;
308a4ec8 1353 int ret = 0;
6fc6879b
JM
1354
1355 len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
1356 cmd = os_malloc(len);
1357 if (cmd == NULL)
1358 return -1;
1359 res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
1360 if (res < 0 || (size_t) res >= len) {
1361 os_free(cmd);
1362 return -1;
1363 }
1364 cmd[len - 1] = '\0';
1365#ifndef _WIN32_WCE
308a4ec8
JM
1366 if (system(cmd) < 0)
1367 ret = -1;
6fc6879b
JM
1368#endif /* _WIN32_WCE */
1369 os_free(cmd);
1370
308a4ec8 1371 return ret;
6fc6879b
JM
1372}
1373
1374
1375static void wpa_cli_action_process(const char *msg)
1376{
1377 const char *pos;
1378 char *copy = NULL, *id, *pos2;
1379
1380 pos = msg;
1381 if (*pos == '<') {
1382 /* skip priority */
1383 pos = os_strchr(pos, '>');
1384 if (pos)
1385 pos++;
1386 else
1387 pos = msg;
1388 }
1389
1390 if (str_match(pos, WPA_EVENT_CONNECTED)) {
1391 int new_id = -1;
1392 os_unsetenv("WPA_ID");
1393 os_unsetenv("WPA_ID_STR");
1394 os_unsetenv("WPA_CTRL_DIR");
1395
1396 pos = os_strstr(pos, "[id=");
1397 if (pos)
1398 copy = os_strdup(pos + 4);
1399
1400 if (copy) {
1401 pos2 = id = copy;
1402 while (*pos2 && *pos2 != ' ')
1403 pos2++;
1404 *pos2++ = '\0';
1405 new_id = atoi(id);
1406 os_setenv("WPA_ID", id, 1);
1407 while (*pos2 && *pos2 != '=')
1408 pos2++;
1409 if (*pos2 == '=')
1410 pos2++;
1411 id = pos2;
1412 while (*pos2 && *pos2 != ']')
1413 pos2++;
1414 *pos2 = '\0';
1415 os_setenv("WPA_ID_STR", id, 1);
1416 os_free(copy);
1417 }
1418
1419 os_setenv("WPA_CTRL_DIR", ctrl_iface_dir, 1);
1420
1421 if (!wpa_cli_connected || new_id != wpa_cli_last_id) {
1422 wpa_cli_connected = 1;
1423 wpa_cli_last_id = new_id;
1424 wpa_cli_exec(action_file, ctrl_ifname, "CONNECTED");
1425 }
1426 } else if (str_match(pos, WPA_EVENT_DISCONNECTED)) {
1427 if (wpa_cli_connected) {
1428 wpa_cli_connected = 0;
1429 wpa_cli_exec(action_file, ctrl_ifname, "DISCONNECTED");
1430 }
1431 } else if (str_match(pos, WPA_EVENT_TERMINATING)) {
1432 printf("wpa_supplicant is terminating - stop monitoring\n");
1433 wpa_cli_quit = 1;
1434 }
1435}
1436
1437
1438#ifndef CONFIG_ANSI_C_EXTRA
1439static void wpa_cli_action_cb(char *msg, size_t len)
1440{
1441 wpa_cli_action_process(msg);
1442}
1443#endif /* CONFIG_ANSI_C_EXTRA */
1444
1445
1446static void wpa_cli_reconnect(void)
1447{
1448 wpa_cli_close_connection();
1449 ctrl_conn = wpa_cli_open_connection(ctrl_ifname);
1450 if (ctrl_conn) {
1451 printf("Connection to wpa_supplicant re-established\n");
1452 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1453 wpa_cli_attached = 1;
1454 } else {
1455 printf("Warning: Failed to attach to "
1456 "wpa_supplicant.\n");
1457 }
1458 }
1459}
1460
1461
1462static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
1463 int action_monitor)
1464{
1465 int first = 1;
1466 if (ctrl_conn == NULL) {
1467 wpa_cli_reconnect();
1468 return;
1469 }
1470 while (wpa_ctrl_pending(ctrl) > 0) {
1471 char buf[256];
1472 size_t len = sizeof(buf) - 1;
1473 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
1474 buf[len] = '\0';
1475 if (action_monitor)
1476 wpa_cli_action_process(buf);
1477 else {
1478 if (in_read && first)
1479 printf("\n");
1480 first = 0;
1481 printf("%s\n", buf);
1482 }
1483 } else {
1484 printf("Could not read pending message.\n");
1485 break;
1486 }
1487 }
1488
1489 if (wpa_ctrl_pending(ctrl) < 0) {
1490 printf("Connection to wpa_supplicant lost - trying to "
1491 "reconnect\n");
1492 wpa_cli_reconnect();
1493 }
1494}
1495
1496
1497#ifdef CONFIG_READLINE
1498static char * wpa_cli_cmd_gen(const char *text, int state)
1499{
1500 static int i, len;
1501 const char *cmd;
1502
1503 if (state == 0) {
1504 i = 0;
1505 len = os_strlen(text);
1506 }
1507
1508 while ((cmd = wpa_cli_commands[i].cmd)) {
1509 i++;
1510 if (os_strncasecmp(cmd, text, len) == 0)
1511 return os_strdup(cmd);
1512 }
1513
1514 return NULL;
1515}
1516
1517
1518static char * wpa_cli_dummy_gen(const char *text, int state)
1519{
1520 return NULL;
1521}
1522
1523
1524static char ** wpa_cli_completion(const char *text, int start, int end)
1525{
1526 return rl_completion_matches(text, start == 0 ?
1527 wpa_cli_cmd_gen : wpa_cli_dummy_gen);
1528}
1529#endif /* CONFIG_READLINE */
1530
1531
1532static void wpa_cli_interactive(void)
1533{
1534#define max_args 10
1535 char cmdbuf[256], *cmd, *argv[max_args], *pos;
1536 int argc;
1537#ifdef CONFIG_READLINE
1538 char *home, *hfile = NULL;
1539#endif /* CONFIG_READLINE */
1540
1541 printf("\nInteractive mode\n\n");
1542
1543#ifdef CONFIG_READLINE
1544 rl_attempted_completion_function = wpa_cli_completion;
1545 home = getenv("HOME");
1546 if (home) {
1547 const char *fname = ".wpa_cli_history";
1548 int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
1549 hfile = os_malloc(hfile_len);
1550 if (hfile) {
1551 int res;
1552 res = os_snprintf(hfile, hfile_len, "%s/%s", home,
1553 fname);
1554 if (res >= 0 && res < hfile_len) {
1555 hfile[hfile_len - 1] = '\0';
1556 read_history(hfile);
1557 stifle_history(100);
1558 }
1559 }
1560 }
1561#endif /* CONFIG_READLINE */
1562
1563 do {
1564 wpa_cli_recv_pending(ctrl_conn, 0, 0);
1565#ifndef CONFIG_NATIVE_WINDOWS
1566 alarm(1);
1567#endif /* CONFIG_NATIVE_WINDOWS */
1568#ifdef CONFIG_READLINE
1569 cmd = readline("> ");
1570 if (cmd && *cmd) {
1571 HIST_ENTRY *h;
1572 while (next_history())
1573 ;
1574 h = previous_history();
1575 if (h == NULL || os_strcmp(cmd, h->line) != 0)
1576 add_history(cmd);
1577 next_history();
1578 }
1579#else /* CONFIG_READLINE */
1580 printf("> ");
1581 cmd = fgets(cmdbuf, sizeof(cmdbuf), stdin);
1582#endif /* CONFIG_READLINE */
1583#ifndef CONFIG_NATIVE_WINDOWS
1584 alarm(0);
1585#endif /* CONFIG_NATIVE_WINDOWS */
1586 if (cmd == NULL)
1587 break;
1588 wpa_cli_recv_pending(ctrl_conn, 0, 0);
1589 pos = cmd;
1590 while (*pos != '\0') {
1591 if (*pos == '\n') {
1592 *pos = '\0';
1593 break;
1594 }
1595 pos++;
1596 }
1597 argc = 0;
1598 pos = cmd;
1599 for (;;) {
1600 while (*pos == ' ')
1601 pos++;
1602 if (*pos == '\0')
1603 break;
1604 argv[argc] = pos;
1605 argc++;
1606 if (argc == max_args)
1607 break;
1608 if (*pos == '"') {
1609 char *pos2 = os_strrchr(pos, '"');
1610 if (pos2)
1611 pos = pos2 + 1;
1612 }
1613 while (*pos != '\0' && *pos != ' ')
1614 pos++;
1615 if (*pos == ' ')
1616 *pos++ = '\0';
1617 }
1618 if (argc)
1619 wpa_request(ctrl_conn, argc, argv);
1620
1621 if (cmd != cmdbuf)
1622 os_free(cmd);
1623 } while (!wpa_cli_quit);
1624
1625#ifdef CONFIG_READLINE
1626 if (hfile) {
1627 /* Save command history, excluding lines that may contain
1628 * passwords. */
1629 HIST_ENTRY *h;
1630 history_set_pos(0);
413653e8 1631 while ((h = current_history())) {
6fc6879b
JM
1632 char *p = h->line;
1633 while (*p == ' ' || *p == '\t')
1634 p++;
40fd868c 1635 if (cmd_has_sensitive_data(p)) {
6fc6879b
JM
1636 h = remove_history(where_history());
1637 if (h) {
1638 os_free(h->line);
1639 os_free(h->data);
1640 os_free(h);
413653e8
ER
1641 } else
1642 next_history();
1643 } else
1644 next_history();
6fc6879b
JM
1645 }
1646 write_history(hfile);
1647 os_free(hfile);
1648 }
1649#endif /* CONFIG_READLINE */
1650}
1651
1652
1653static void wpa_cli_action(struct wpa_ctrl *ctrl)
1654{
1655#ifdef CONFIG_ANSI_C_EXTRA
1656 /* TODO: ANSI C version(?) */
1657 printf("Action processing not supported in ANSI C build.\n");
1658#else /* CONFIG_ANSI_C_EXTRA */
1659 fd_set rfds;
1660 int fd, res;
1661 struct timeval tv;
1662 char buf[256]; /* note: large enough to fit in unsolicited messages */
1663 size_t len;
1664
1665 fd = wpa_ctrl_get_fd(ctrl);
1666
1667 while (!wpa_cli_quit) {
1668 FD_ZERO(&rfds);
1669 FD_SET(fd, &rfds);
1670 tv.tv_sec = 2;
1671 tv.tv_usec = 0;
1672 res = select(fd + 1, &rfds, NULL, NULL, &tv);
1673 if (res < 0 && errno != EINTR) {
1674 perror("select");
1675 break;
1676 }
1677
1678 if (FD_ISSET(fd, &rfds))
1679 wpa_cli_recv_pending(ctrl, 0, 1);
1680 else {
1681 /* verify that connection is still working */
1682 len = sizeof(buf) - 1;
1683 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1684 wpa_cli_action_cb) < 0 ||
1685 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
1686 printf("wpa_supplicant did not reply to PING "
1687 "command - exiting\n");
1688 break;
1689 }
1690 }
1691 }
1692#endif /* CONFIG_ANSI_C_EXTRA */
1693}
1694
1695
1696static void wpa_cli_cleanup(void)
1697{
1698 wpa_cli_close_connection();
1699 if (pid_file)
1700 os_daemonize_terminate(pid_file);
1701
1702 os_program_deinit();
1703}
1704
1705static void wpa_cli_terminate(int sig)
1706{
1707 wpa_cli_cleanup();
1708 exit(0);
1709}
1710
1711
1712#ifndef CONFIG_NATIVE_WINDOWS
1713static void wpa_cli_alarm(int sig)
1714{
1715 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
1716 printf("Connection to wpa_supplicant lost - trying to "
1717 "reconnect\n");
1718 wpa_cli_close_connection();
1719 }
1720 if (!ctrl_conn)
1721 wpa_cli_reconnect();
1722 if (ctrl_conn)
1723 wpa_cli_recv_pending(ctrl_conn, 1, 0);
1724 alarm(1);
1725}
1726#endif /* CONFIG_NATIVE_WINDOWS */
1727
1728
1729static char * wpa_cli_get_default_ifname(void)
1730{
1731 char *ifname = NULL;
1732
1733#ifdef CONFIG_CTRL_IFACE_UNIX
1734 struct dirent *dent;
1735 DIR *dir = opendir(ctrl_iface_dir);
1736 if (!dir)
1737 return NULL;
1738 while ((dent = readdir(dir))) {
1739#ifdef _DIRENT_HAVE_D_TYPE
1740 /*
1741 * Skip the file if it is not a socket. Also accept
1742 * DT_UNKNOWN (0) in case the C library or underlying
1743 * file system does not support d_type.
1744 */
1745 if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
1746 continue;
1747#endif /* _DIRENT_HAVE_D_TYPE */
1748 if (os_strcmp(dent->d_name, ".") == 0 ||
1749 os_strcmp(dent->d_name, "..") == 0)
1750 continue;
1751 printf("Selected interface '%s'\n", dent->d_name);
1752 ifname = os_strdup(dent->d_name);
1753 break;
1754 }
1755 closedir(dir);
1756#endif /* CONFIG_CTRL_IFACE_UNIX */
1757
1758#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
1759 char buf[2048], *pos;
1760 size_t len;
1761 struct wpa_ctrl *ctrl;
1762 int ret;
1763
1764 ctrl = wpa_ctrl_open(NULL);
1765 if (ctrl == NULL)
1766 return NULL;
1767
1768 len = sizeof(buf) - 1;
1769 ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL);
1770 if (ret >= 0) {
1771 buf[len] = '\0';
1772 pos = os_strchr(buf, '\n');
1773 if (pos)
1774 *pos = '\0';
1775 ifname = os_strdup(buf);
1776 }
1777 wpa_ctrl_close(ctrl);
1778#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
1779
1780 return ifname;
1781}
1782
1783
1784int main(int argc, char *argv[])
1785{
1786 int interactive;
1787 int warning_displayed = 0;
1788 int c;
1789 int daemonize = 0;
1790 int ret = 0;
1791 const char *global = NULL;
1792
1793 if (os_program_init())
1794 return -1;
1795
1796 for (;;) {
1797 c = getopt(argc, argv, "a:Bg:hi:p:P:v");
1798 if (c < 0)
1799 break;
1800 switch (c) {
1801 case 'a':
1802 action_file = optarg;
1803 break;
1804 case 'B':
1805 daemonize = 1;
1806 break;
1807 case 'g':
1808 global = optarg;
1809 break;
1810 case 'h':
1811 usage();
1812 return 0;
1813 case 'v':
1814 printf("%s\n", wpa_cli_version);
1815 return 0;
1816 case 'i':
1817 os_free(ctrl_ifname);
1818 ctrl_ifname = os_strdup(optarg);
1819 break;
1820 case 'p':
1821 ctrl_iface_dir = optarg;
1822 break;
1823 case 'P':
1824 pid_file = optarg;
1825 break;
1826 default:
1827 usage();
1828 return -1;
1829 }
1830 }
1831
1832 interactive = (argc == optind) && (action_file == NULL);
1833
1834 if (interactive)
1835 printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license);
1836
1837 if (global) {
1838#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
1839 ctrl_conn = wpa_ctrl_open(NULL);
1840#else /* CONFIG_CTRL_IFACE_NAMED_PIPE */
1841 ctrl_conn = wpa_ctrl_open(global);
1842#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
1843 if (ctrl_conn == NULL) {
1844 perror("Failed to connect to wpa_supplicant - "
1845 "wpa_ctrl_open");
1846 return -1;
1847 }
1848 }
1849
1850 for (; !global;) {
1851 if (ctrl_ifname == NULL)
1852 ctrl_ifname = wpa_cli_get_default_ifname();
1853 ctrl_conn = wpa_cli_open_connection(ctrl_ifname);
1854 if (ctrl_conn) {
1855 if (warning_displayed)
1856 printf("Connection established.\n");
1857 break;
1858 }
1859
1860 if (!interactive) {
1861 perror("Failed to connect to wpa_supplicant - "
1862 "wpa_ctrl_open");
1863 return -1;
1864 }
1865
1866 if (!warning_displayed) {
1867 printf("Could not connect to wpa_supplicant - "
1868 "re-trying\n");
1869 warning_displayed = 1;
1870 }
1871 os_sleep(1, 0);
1872 continue;
1873 }
1874
1875#ifndef _WIN32_WCE
1876 signal(SIGINT, wpa_cli_terminate);
1877 signal(SIGTERM, wpa_cli_terminate);
1878#endif /* _WIN32_WCE */
1879#ifndef CONFIG_NATIVE_WINDOWS
1880 signal(SIGALRM, wpa_cli_alarm);
1881#endif /* CONFIG_NATIVE_WINDOWS */
1882
1883 if (interactive || action_file) {
1884 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1885 wpa_cli_attached = 1;
1886 } else {
1887 printf("Warning: Failed to attach to "
1888 "wpa_supplicant.\n");
1889 if (!interactive)
1890 return -1;
1891 }
1892 }
1893
1894 if (daemonize && os_daemonize(pid_file))
1895 return -1;
1896
1897 if (interactive)
1898 wpa_cli_interactive();
1899 else if (action_file)
1900 wpa_cli_action(ctrl_conn);
1901 else
1902 ret = wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1903
1904 os_free(ctrl_ifname);
1905 wpa_cli_cleanup();
1906
1907 return ret;
1908}
1909
1910#else /* CONFIG_CTRL_IFACE */
1911int main(int argc, char *argv[])
1912{
1913 printf("CONFIG_CTRL_IFACE not defined - wpa_cli disabled\n");
1914 return -1;
1915}
1916#endif /* CONFIG_CTRL_IFACE */