Add trunc and truncf.
[dragonfly.git] / contrib / wpa_supplicant-0.4.9 / wpa_cli.c
1 /*
2  * WPA Supplicant - command line interface for wpa_supplicant daemon
3  * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
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 <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <signal.h>
19 #include <unistd.h>
20 #include <dirent.h>
21 #include <errno.h>
22 #include <sys/time.h>
23 #ifdef CONFIG_READLINE
24 #include <readline/readline.h>
25 #include <readline/history.h>
26 #endif /* CONFIG_READLINE */
27
28 #include "wpa_ctrl.h"
29 #ifdef CONFIG_NATIVE_WINDOWS
30 #include "common.h"
31 #endif /* CONFIG_NATIVE_WINDOWS */
32 #include "version.h"
33
34
35 static const char *wpa_cli_version =
36 "wpa_cli v" VERSION_STR "\n"
37 "Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi> and contributors";
38
39
40 static 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
47 static 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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
92 static const char *commands_help =
93 "commands:\n"
94 "  status [verbose] = get current WPA/EAPOL/EAP status\n"
95 "  mib = get MIB variables (dot1x, dot11)\n"
96 "  help = show this usage help\n"
97 "  interface [ifname] = show interfaces/select interface\n"
98 "  level <debug level> = change debug level\n"
99 "  license = show full wpa_cli license\n"
100 "  logoff = IEEE 802.1X EAPOL state machine logoff\n"
101 "  logon = IEEE 802.1X EAPOL state machine logon\n"
102 "  set = set variables (shows list of variables when run without arguments)\n"
103 "  pmksa = show PMKSA cache\n"
104 "  reassociate = force reassociation\n"
105 "  reconfigure = force wpa_supplicant to re-read its configuration file\n"
106 "  preauthenticate <BSSID> = force preauthentication\n"
107 "  identity <network id> <identity> = configure identity for an SSID\n"
108 "  password <network id> <password> = configure password for an SSID\n"
109 "  new_password <network id> <password> = change password for an SSID\n"
110 "  pin <network id> <pin> = configure pin for an SSID\n"
111 "  otp <network id> <password> = configure one-time-password for an SSID\n"
112 "  passphrase <network id> <passphrase> = configure private key passphrase\n"
113 "    for an SSID\n"
114 "  bssid <network id> <BSSID> = set preferred BSSID for an SSID\n"
115 "  list_networks = list configured networks\n"
116 "  select_network <network id> = select a network (disable others)\n"
117 "  enable_network <network id> = enable a network\n"
118 "  disable_network <network id> = disable a network\n"
119 "  add_network = add a network\n"
120 "  remove_network <network id> = remove a network\n"
121 "  set_network <network id> <variable> <value> = set network variables "
122 "(shows\n"
123 "    list of variables when run without arguments)\n"
124 "  get_network <network id> <variable> = get network variables\n"
125 "  save_config = save the current configuration\n"
126 "  disconnect = disconnect and wait for reassociate command before "
127 "connecting\n"
128 "  scan = request new BSS scan\n"
129 "  scan_results = get latest scan results\n"
130 "  get_capability <eap/pairwise/group/key_mgmt/proto/auth_alg> = "
131 "get capabilies\n"
132 "  terminate = terminate wpa_supplicant\n"
133 "  quit = exit wpa_cli\n";
134
135 static struct wpa_ctrl *ctrl_conn;
136 static int wpa_cli_quit = 0;
137 static int wpa_cli_attached = 0;
138 static const char *ctrl_iface_dir = "/var/run/wpa_supplicant";
139 static char *ctrl_ifname = NULL;
140 static const char *pid_file = NULL;
141 static const char *action_file = NULL;
142
143
144 static void usage(void)
145 {
146         printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] "
147                "[-a<action file>] \\\n"
148                "        [-P<pid file>] [-g<global ctrl>]  [command..]\n"
149                "  -h = help (show this usage text)\n"
150                "  -v = shown version information\n"
151                "  -a = run in daemon mode executing the action file based on "
152                "events from\n"
153                "       wpa_supplicant\n"
154                "  -B = run a daemon in the background\n"
155                "  default path: /var/run/wpa_supplicant\n"
156                "  default interface: first interface found in socket path\n"
157                "%s",
158                commands_help);
159 }
160
161
162 static struct wpa_ctrl * wpa_cli_open_connection(const char *ifname)
163 {
164 #ifdef CONFIG_CTRL_IFACE_UDP
165         ctrl_conn = wpa_ctrl_open("");
166         return ctrl_conn;
167 #else /* CONFIG_CTRL_IFACE_UDP */
168         char *cfile;
169         int flen;
170
171         if (ifname == NULL)
172                 return NULL;
173
174         flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
175         cfile = malloc(flen);
176         if (cfile == NULL)
177                 return NULL;
178         snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
179
180         ctrl_conn = wpa_ctrl_open(cfile);
181         free(cfile);
182         return ctrl_conn;
183 #endif /* CONFIG_CTRL_IFACE_UDP */
184 }
185
186
187 static void wpa_cli_close_connection(void)
188 {
189         if (ctrl_conn == NULL)
190                 return;
191
192         if (wpa_cli_attached) {
193                 wpa_ctrl_detach(ctrl_conn);
194                 wpa_cli_attached = 0;
195         }
196         wpa_ctrl_close(ctrl_conn);
197         ctrl_conn = NULL;
198 }
199
200
201 static void wpa_cli_msg_cb(char *msg, size_t len)
202 {
203         printf("%s\n", msg);
204 }
205
206
207 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
208 {
209         char buf[2048];
210         size_t len;
211         int ret;
212
213         if (ctrl_conn == NULL) {
214                 printf("Not connected to wpa_supplicant - command dropped.\n");
215                 return -1;
216         }
217         len = sizeof(buf) - 1;
218         ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
219                                wpa_cli_msg_cb);
220         if (ret == -2) {
221                 printf("'%s' command timed out.\n", cmd);
222                 return -2;
223         } else if (ret < 0) {
224                 printf("'%s' command failed.\n", cmd);
225                 return -1;
226         }
227         if (print) {
228                 buf[len] = '\0';
229                 printf("%s", buf);
230         }
231         return 0;
232 }
233
234
235 static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
236 {
237         return _wpa_ctrl_command(ctrl, cmd, 1);
238 }
239
240
241 static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
242 {
243         int verbose = argc > 0 && strcmp(argv[0], "verbose") == 0;
244         return wpa_ctrl_command(ctrl, verbose ? "STATUS-VERBOSE" : "STATUS");
245 }
246
247
248 static int wpa_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
249 {
250         return wpa_ctrl_command(ctrl, "PING");
251 }
252
253
254 static int wpa_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
255 {
256         return wpa_ctrl_command(ctrl, "MIB");
257 }
258
259
260 static int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
261 {
262         return wpa_ctrl_command(ctrl, "PMKSA");
263 }
264
265
266 static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
267 {
268         printf("%s", commands_help);
269         return 0;
270 }
271
272
273 static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[])
274 {
275         printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license);
276         return 0;
277 }
278
279
280 static int wpa_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
281 {
282         wpa_cli_quit = 1;
283         return 0;
284 }
285
286
287 static void wpa_cli_show_variables(void)
288 {
289         printf("set variables:\n"
290                "  EAPOL::heldPeriod (EAPOL state machine held period, "
291                "in seconds)\n"
292                "  EAPOL::authPeriod (EAPOL state machine authentication "
293                "period, in seconds)\n"
294                "  EAPOL::startPeriod (EAPOL state machine start period, in "
295                "seconds)\n"
296                "  EAPOL::maxStart (EAPOL state machine maximum start "
297                "attempts)\n");
298         printf("  dot11RSNAConfigPMKLifetime (WPA/WPA2 PMK lifetime in "
299                "seconds)\n"
300                "  dot11RSNAConfigPMKReauthThreshold (WPA/WPA2 reauthentication"
301                " threshold\n\tpercentage)\n"
302                "  dot11RSNAConfigSATimeout (WPA/WPA2 timeout for completing "
303                "security\n\tassociation in seconds)\n");
304 }
305
306
307 static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
308 {
309         char cmd[256];
310
311         if (argc == 0) {
312                 wpa_cli_show_variables();
313                 return 0;
314         }
315
316         if (argc != 2) {
317                 printf("Invalid SET command: needs two arguments (variable "
318                        "name and value)\n");
319                 return 0;
320         }
321
322         if (snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]) >=
323             sizeof(cmd) - 1) {
324                 printf("Too long SET command.\n");
325                 return 0;
326         }
327         return wpa_ctrl_command(ctrl, cmd);
328 }
329
330
331 static int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[])
332 {
333         return wpa_ctrl_command(ctrl, "LOGOFF");
334 }
335
336
337 static int wpa_cli_cmd_logon(struct wpa_ctrl *ctrl, int argc, char *argv[])
338 {
339         return wpa_ctrl_command(ctrl, "LOGON");
340 }
341
342
343 static int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc,
344                                    char *argv[])
345 {
346         return wpa_ctrl_command(ctrl, "REASSOCIATE");
347 }
348
349
350 static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc,
351                                        char *argv[])
352 {
353         char cmd[256];
354
355         if (argc != 1) {
356                 printf("Invalid PREAUTH command: needs one argument "
357                        "(BSSID)\n");
358                 return 0;
359         }
360
361         if (snprintf(cmd, sizeof(cmd), "PREAUTH %s", argv[0]) >=
362             sizeof(cmd) - 1) {
363                 printf("Too long PREAUTH command.\n");
364                 return 0;
365         }
366         return wpa_ctrl_command(ctrl, cmd);
367 }
368
369
370 static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
371 {
372         char cmd[256];
373         if (argc != 1) {
374                 printf("Invalid LEVEL command: needs one argument (debug "
375                        "level)\n");
376                 return 0;
377         }
378         snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
379         return wpa_ctrl_command(ctrl, cmd);
380 }
381
382
383 static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[])
384 {
385         char cmd[256], *pos, *end;
386         int i;
387
388         if (argc < 2) {
389                 printf("Invalid IDENTITY command: needs two arguments "
390                        "(network id and identity)\n");
391                 return 0;
392         }
393
394         end = cmd + sizeof(cmd);
395         pos = cmd;
396         pos += snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s",
397                        argv[0], argv[1]);
398         for (i = 2; i < argc; i++)
399                 pos += snprintf(pos, end - pos, " %s", argv[i]);
400
401         return wpa_ctrl_command(ctrl, cmd);
402 }
403
404
405 static int wpa_cli_cmd_password(struct wpa_ctrl *ctrl, int argc, char *argv[])
406 {
407         char cmd[256], *pos, *end;
408         int i;
409
410         if (argc < 2) {
411                 printf("Invalid PASSWORD command: needs two arguments "
412                        "(network id and password)\n");
413                 return 0;
414         }
415
416         end = cmd + sizeof(cmd);
417         pos = cmd;
418         pos += snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s",
419                        argv[0], argv[1]);
420         for (i = 2; i < argc; i++)
421                 pos += snprintf(pos, end - pos, " %s", argv[i]);
422
423         return wpa_ctrl_command(ctrl, cmd);
424 }
425
426
427 static int wpa_cli_cmd_new_password(struct wpa_ctrl *ctrl, int argc,
428                                     char *argv[])
429 {
430         char cmd[256], *pos, *end;
431         int i;
432
433         if (argc < 2) {
434                 printf("Invalid NEW_PASSWORD command: needs two arguments "
435                        "(network id and password)\n");
436                 return 0;
437         }
438
439         end = cmd + sizeof(cmd);
440         pos = cmd;
441         pos += snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s",
442                        argv[0], argv[1]);
443         for (i = 2; i < argc; i++)
444                 pos += snprintf(pos, end - pos, " %s", argv[i]);
445
446         return wpa_ctrl_command(ctrl, cmd);
447 }
448
449
450 static int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
451 {
452         char cmd[256], *pos, *end;
453         int i;
454
455         if (argc < 2) {
456                 printf("Invalid PIN command: needs two arguments "
457                        "(network id and pin)\n");
458                 return 0;
459         }
460
461         end = cmd + sizeof(cmd);
462         pos = cmd;
463         pos += snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s",
464                         argv[0], argv[1]);
465         for (i = 2; i < argc; i++)
466                 pos += snprintf(pos, end - pos, " %s", argv[i]);
467
468         return wpa_ctrl_command(ctrl, cmd);
469 }
470
471
472 static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[])
473 {
474         char cmd[256], *pos, *end;
475         int i;
476
477         if (argc < 2) {
478                 printf("Invalid OTP command: needs two arguments (network "
479                        "id and password)\n");
480                 return 0;
481         }
482
483         end = cmd + sizeof(cmd);
484         pos = cmd;
485         pos += snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s",
486                        argv[0], argv[1]);
487         for (i = 2; i < argc; i++)
488                 pos += snprintf(pos, end - pos, " %s", argv[i]);
489
490         return wpa_ctrl_command(ctrl, cmd);
491 }
492
493
494 static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
495                                   char *argv[])
496 {
497         char cmd[256], *pos, *end;
498         int i;
499
500         if (argc < 2) {
501                 printf("Invalid PASSPHRASE command: needs two arguments "
502                        "(network id and passphrase)\n");
503                 return 0;
504         }
505
506         end = cmd + sizeof(cmd);
507         pos = cmd;
508         pos += snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s",
509                        argv[0], argv[1]);
510         for (i = 2; i < argc; i++)
511                 pos += snprintf(pos, end - pos, " %s", argv[i]);
512
513         return wpa_ctrl_command(ctrl, cmd);
514 }
515
516
517 static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[])
518 {
519         char cmd[256], *pos, *end;
520         int i;
521
522         if (argc < 2) {
523                 printf("Invalid BSSID command: needs two arguments (network "
524                        "id and BSSID)\n");
525                 return 0;
526         }
527
528         end = cmd + sizeof(cmd);
529         pos = cmd;
530         pos += snprintf(pos, end - pos, "BSSID");
531         for (i = 0; i < argc; i++)
532                 pos += snprintf(pos, end - pos, " %s", argv[i]);
533
534         return wpa_ctrl_command(ctrl, cmd);
535 }
536
537
538 static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc,
539                                      char *argv[])
540 {
541         return wpa_ctrl_command(ctrl, "LIST_NETWORKS");
542 }
543
544
545 static int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc,
546                                       char *argv[])
547 {
548         char cmd[32];
549
550         if (argc < 1) {
551                 printf("Invalid SELECT_NETWORK command: needs one argument "
552                        "(network id)\n");
553                 return 0;
554         }
555
556         snprintf(cmd, sizeof(cmd), "SELECT_NETWORK %s", argv[0]);
557
558         return wpa_ctrl_command(ctrl, cmd);
559 }
560
561
562 static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc,
563                                       char *argv[])
564 {
565         char cmd[32];
566
567         if (argc < 1) {
568                 printf("Invalid ENABLE_NETWORK command: needs one argument "
569                        "(network id)\n");
570                 return 0;
571         }
572
573         snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s", argv[0]);
574
575         return wpa_ctrl_command(ctrl, cmd);
576 }
577
578
579 static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc,
580                                        char *argv[])
581 {
582         char cmd[32];
583
584         if (argc < 1) {
585                 printf("Invalid DISABLE_NETWORK command: needs one argument "
586                        "(network id)\n");
587                 return 0;
588         }
589
590         snprintf(cmd, sizeof(cmd), "DISABLE_NETWORK %s", argv[0]);
591
592         return wpa_ctrl_command(ctrl, cmd);
593 }
594
595
596 static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc,
597                                    char *argv[])
598 {
599         return wpa_ctrl_command(ctrl, "ADD_NETWORK");
600 }
601
602
603 static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc,
604                                       char *argv[])
605 {
606         char cmd[32];
607
608         if (argc < 1) {
609                 printf("Invalid REMOVE_NETWORK command: needs one argument "
610                        "(network id)\n");
611                 return 0;
612         }
613
614         snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %s", argv[0]);
615
616         return wpa_ctrl_command(ctrl, cmd);
617 }
618
619
620 static void wpa_cli_show_network_variables(void)
621 {
622         printf("set_network variables:\n"
623                "  ssid (network name, SSID)\n"
624                "  psk (WPA passphrase or pre-shared key)\n"
625                "  key_mgmt (key management protocol)\n"
626                "  identity (EAP identity)\n"
627                "  password (EAP password)\n"
628                "  ...\n"
629                "\n"
630                "Note: Values are entered in the same format as the "
631                "configuration file is using,\n"
632                "i.e., strings values need to be inside double quotation "
633                "marks.\n"
634                "For example: set_network 1 ssid \"network name\"\n"
635                "\n"
636                "Please see wpa_supplicant.conf documentation for full list "
637                "of\navailable variables.\n");
638 }
639
640
641 static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc,
642                                    char *argv[])
643 {
644         char cmd[256];
645
646         if (argc == 0) {
647                 wpa_cli_show_network_variables();
648                 return 0;
649         }
650
651         if (argc != 3) {
652                 printf("Invalid SET_NETWORK command: needs three arguments\n"
653                        "(network id, variable name, and value)\n");
654                 return 0;
655         }
656
657         if (snprintf(cmd, sizeof(cmd), "SET_NETWORK %s %s %s",
658                      argv[0], argv[1], argv[2]) >= sizeof(cmd) - 1) {
659                 printf("Too long SET_NETWORK command.\n");
660                 return 0;
661         }
662         return wpa_ctrl_command(ctrl, cmd);
663 }
664
665
666 static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
667                                    char *argv[])
668 {
669         char cmd[256];
670
671         if (argc == 0) {
672                 wpa_cli_show_network_variables();
673                 return 0;
674         }
675
676         if (argc != 2) {
677                 printf("Invalid GET_NETWORK command: needs two arguments\n"
678                        "(network id and variable name)\n");
679                 return 0;
680         }
681
682         if (snprintf(cmd, sizeof(cmd), "GET_NETWORK %s %s",
683                      argv[0], argv[1]) >= sizeof(cmd) - 1) {
684                 printf("Too long GET_NETWORK command.\n");
685                 return 0;
686         }
687         return wpa_ctrl_command(ctrl, cmd);
688 }
689
690
691 static int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc,
692                                   char *argv[])
693 {
694         return wpa_ctrl_command(ctrl, "DISCONNECT");
695 }
696
697
698 static int wpa_cli_cmd_save_config(struct wpa_ctrl *ctrl, int argc,
699                                    char *argv[])
700 {
701         return wpa_ctrl_command(ctrl, "SAVE_CONFIG");
702 }
703
704
705 static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
706 {
707         return wpa_ctrl_command(ctrl, "SCAN");
708 }
709
710
711 static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc,
712                                     char *argv[])
713 {
714         return wpa_ctrl_command(ctrl, "SCAN_RESULTS");
715 }
716
717
718 static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
719                                       char *argv[])
720 {
721         char cmd[64];
722
723         if (argc != 1) {
724                 printf("Invalid GET_CAPABILITY command: needs one argument\n");
725                 return 0;
726         }
727
728         snprintf(cmd, sizeof(cmd), "GET_CAPABILITY %s", argv[0]);
729
730         return wpa_ctrl_command(ctrl, cmd);
731 }
732
733
734 static void wpa_cli_list_interfaces(struct wpa_ctrl *ctrl)
735 {
736         struct dirent *dent;
737         DIR *dir;
738
739         dir = opendir(ctrl_iface_dir);
740         if (dir == NULL) {
741                 printf("Control interface directory '%s' could not be "
742                        "openned.\n", ctrl_iface_dir);
743                 return;
744         }
745
746         printf("Available interfaces:\n");
747         while ((dent = readdir(dir))) {
748                 if (strcmp(dent->d_name, ".") == 0 ||
749                     strcmp(dent->d_name, "..") == 0)
750                         continue;
751                 printf("%s\n", dent->d_name);
752         }
753         closedir(dir);
754 }
755
756
757 static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[])
758 {
759         if (argc < 1) {
760                 wpa_cli_list_interfaces(ctrl);
761                 return 0;
762         }
763
764         wpa_cli_close_connection();
765         free(ctrl_ifname);
766         ctrl_ifname = strdup(argv[0]);
767
768         if (wpa_cli_open_connection(ctrl_ifname)) {
769                 printf("Connected to interface '%s.\n", ctrl_ifname);
770                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
771                         wpa_cli_attached = 1;
772                 } else {
773                         printf("Warning: Failed to attach to "
774                                "wpa_supplicant.\n");
775                 }
776         } else {
777                 printf("Could not connect to interface '%s' - re-trying\n",
778                         ctrl_ifname);
779         }
780         return 0;
781 }
782
783
784 static int wpa_cli_cmd_reconfigure(struct wpa_ctrl *ctrl, int argc,
785                                    char *argv[])
786 {
787         return wpa_ctrl_command(ctrl, "RECONFIGURE");
788 }
789
790
791 static int wpa_cli_cmd_terminate(struct wpa_ctrl *ctrl, int argc,
792                                  char *argv[])
793 {
794         return wpa_ctrl_command(ctrl, "TERMINATE");
795 }
796
797
798 static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc,
799                                      char *argv[])
800 {
801         char cmd[256];
802
803         if (argc < 1) {
804                 printf("Invalid INTERFACE_ADD command: needs at least one "
805                        "argument (interface name)\n"
806                         "All arguments: ifname confname driver ctrl_interface "
807                         "driver_param\n");
808                 return 0;
809         }
810
811         /*
812          * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
813          * <driver_param>
814          */
815         snprintf(cmd, sizeof(cmd), "INTERFACE_ADD %s\t%s\t%s\t%s\t%s", argv[0],
816                  argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "",
817                  argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "");
818         return wpa_ctrl_command(ctrl, cmd);
819 }
820
821
822 static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc,
823                                         char *argv[])
824 {
825         char cmd[128];
826
827         if (argc != 1) {
828                 printf("Invalid INTERFACE_REMOVE command: needs one argument "
829                        "(interface name)\n");
830                 return 0;
831         }
832
833         snprintf(cmd, sizeof(cmd), "INTERFACE_REMOVE %s", argv[0]);
834         return wpa_ctrl_command(ctrl, cmd);
835 }
836
837
838 struct wpa_cli_cmd {
839         const char *cmd;
840         int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
841 };
842
843 static struct wpa_cli_cmd wpa_cli_commands[] = {
844         { "status", wpa_cli_cmd_status },
845         { "ping", wpa_cli_cmd_ping },
846         { "mib", wpa_cli_cmd_mib },
847         { "help", wpa_cli_cmd_help },
848         { "interface", wpa_cli_cmd_interface },
849         { "level", wpa_cli_cmd_level },
850         { "license", wpa_cli_cmd_license },
851         { "quit", wpa_cli_cmd_quit },
852         { "set", wpa_cli_cmd_set },
853         { "logon", wpa_cli_cmd_logon },
854         { "logoff", wpa_cli_cmd_logoff },
855         { "pmksa", wpa_cli_cmd_pmksa },
856         { "reassociate", wpa_cli_cmd_reassociate },
857         { "preauthenticate", wpa_cli_cmd_preauthenticate },
858         { "identity", wpa_cli_cmd_identity },
859         { "password", wpa_cli_cmd_password },
860         { "new_password", wpa_cli_cmd_new_password },
861         { "pin", wpa_cli_cmd_pin },
862         { "otp", wpa_cli_cmd_otp },
863         { "passphrase", wpa_cli_cmd_passphrase },
864         { "bssid", wpa_cli_cmd_bssid },
865         { "list_networks", wpa_cli_cmd_list_networks },
866         { "select_network", wpa_cli_cmd_select_network },
867         { "enable_network", wpa_cli_cmd_enable_network },
868         { "disable_network", wpa_cli_cmd_disable_network },
869         { "add_network", wpa_cli_cmd_add_network },
870         { "remove_network", wpa_cli_cmd_remove_network },
871         { "set_network", wpa_cli_cmd_set_network },
872         { "get_network", wpa_cli_cmd_get_network },
873         { "save_config", wpa_cli_cmd_save_config },
874         { "disconnect", wpa_cli_cmd_disconnect },
875         { "scan", wpa_cli_cmd_scan },
876         { "scan_results", wpa_cli_cmd_scan_results },
877         { "get_capability", wpa_cli_cmd_get_capability },
878         { "reconfigure", wpa_cli_cmd_reconfigure },
879         { "terminate", wpa_cli_cmd_terminate },
880         { "interface_add", wpa_cli_cmd_interface_add },
881         { "interface_remove", wpa_cli_cmd_interface_remove },
882         { NULL, NULL }
883 };
884
885
886 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
887 {
888         struct wpa_cli_cmd *cmd, *match = NULL;
889         int count;
890
891         count = 0;
892         cmd = wpa_cli_commands;
893         while (cmd->cmd) {
894                 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
895                         match = cmd;
896                         if (strcasecmp(cmd->cmd, argv[0]) == 0) {
897                                 /* we have an exact match */
898                                 count = 1;
899                                 break;
900                         }
901                         count++;
902                 }
903                 cmd++;
904         }
905
906         if (count > 1) {
907                 printf("Ambiguous command '%s'; possible commands:", argv[0]);
908                 cmd = wpa_cli_commands;
909                 while (cmd->cmd) {
910                         if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
911                             0) {
912                                 printf(" %s", cmd->cmd);
913                         }
914                         cmd++;
915                 }
916                 printf("\n");
917         } else if (count == 0) {
918                 printf("Unknown command '%s'\n", argv[0]);
919         } else {
920                 match->handler(ctrl, argc - 1, &argv[1]);
921         }
922 }
923
924
925 static int str_match(const char *a, const char *b)
926 {
927         return strncmp(a, b, strlen(b)) == 0;
928 }
929
930
931 static int wpa_cli_exec(const char *program, const char *arg1,
932                         const char *arg2)
933 {
934         char *cmd;
935         size_t len;
936
937         len = strlen(program) + strlen(arg1) + strlen(arg2) + 3;
938         cmd = malloc(len);
939         if (cmd == NULL)
940                 return -1;
941         snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
942         system(cmd);
943         free(cmd);
944
945         return 0;
946 }
947
948
949 static void wpa_cli_action_process(const char *msg)
950 {
951         const char *pos;
952
953         pos = msg;
954         if (*pos == '<') {
955                 /* skip priority */
956                 pos = strchr(pos, '>');
957                 if (pos)
958                         pos++;
959                 else
960                         pos = msg;
961         }
962
963         if (str_match(pos, WPA_EVENT_CONNECTED)) {
964                 wpa_cli_exec(action_file, ctrl_ifname, "CONNECTED");
965         } else if (str_match(pos, WPA_EVENT_DISCONNECTED)) {
966                 wpa_cli_exec(action_file, ctrl_ifname, "DISCONNECTED");
967         } else if (str_match(pos, WPA_EVENT_TERMINATING)) {
968                 printf("wpa_supplicant is terminating - stop monitoring\n");
969                 wpa_cli_quit = 1;
970         }
971 }
972
973
974 static void wpa_cli_action_cb(char *msg, size_t len)
975 {
976         wpa_cli_action_process(msg);
977 }
978
979
980 static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
981                                  int action_monitor)
982 {
983         int first = 1;
984         if (ctrl_conn == NULL)
985                 return;
986         while (wpa_ctrl_pending(ctrl)) {
987                 char buf[256];
988                 size_t len = sizeof(buf) - 1;
989                 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
990                         buf[len] = '\0';
991                         if (action_monitor)
992                                 wpa_cli_action_process(buf);
993                         else {
994                                 if (in_read && first)
995                                         printf("\n");
996                                 first = 0;
997                                 printf("%s\n", buf);
998                         }
999                 } else {
1000                         printf("Could not read pending message.\n");
1001                         break;
1002                 }
1003         }
1004 }
1005
1006
1007 #ifdef CONFIG_READLINE
1008 static char * wpa_cli_cmd_gen(const char *text, int state)
1009 {
1010         static int i, len;
1011         const char *cmd;
1012
1013         if (state == 0) {
1014                 i = 0;
1015                 len = strlen(text);
1016         }
1017
1018         while ((cmd = wpa_cli_commands[i].cmd)) {
1019                 i++;
1020                 if (strncasecmp(cmd, text, len) == 0)
1021                         return strdup(cmd);
1022         }
1023
1024         return NULL;
1025 }
1026
1027
1028 static char * wpa_cli_dummy_gen(const char *text, int state)
1029 {
1030         return NULL;
1031 }
1032
1033
1034 static char ** wpa_cli_completion(const char *text, int start, int end)
1035 {
1036         return rl_completion_matches(text, start == 0 ?
1037                                      wpa_cli_cmd_gen : wpa_cli_dummy_gen);
1038 }
1039 #endif /* CONFIG_READLINE */
1040
1041
1042 static void wpa_cli_interactive(void)
1043 {
1044 #define max_args 10
1045         char cmdbuf[256], *cmd, *argv[max_args], *pos;
1046         int argc;
1047 #ifdef CONFIG_READLINE
1048         char *home, *hfile = NULL;
1049 #endif /* CONFIG_READLINE */
1050
1051         printf("\nInteractive mode\n\n");
1052
1053 #ifdef CONFIG_READLINE
1054         rl_attempted_completion_function = wpa_cli_completion;
1055         home = getenv("HOME");
1056         if (home) {
1057                 const char *fname = ".wpa_cli_history";
1058                 int hfile_len = strlen(home) + 1 + strlen(fname) + 1;
1059                 hfile = malloc(hfile_len);
1060                 if (hfile) {
1061                         snprintf(hfile, hfile_len, "%s/%s", home, fname);
1062                         read_history(hfile);
1063                         stifle_history(100);
1064                 }
1065         }
1066 #endif /* CONFIG_READLINE */
1067
1068         do {
1069                 wpa_cli_recv_pending(ctrl_conn, 0, 0);
1070 #ifndef CONFIG_NATIVE_WINDOWS
1071                 alarm(1);
1072 #endif /* CONFIG_NATIVE_WINDOWS */
1073 #ifdef CONFIG_READLINE
1074                 cmd = readline("> ");
1075                 if (cmd && *cmd) {
1076                         HIST_ENTRY *h;
1077                         while (next_history())
1078                                 ;
1079                         h = previous_history();
1080                         if (h == NULL || strcmp(cmd, h->line) != 0)
1081                                 add_history(cmd);
1082                         next_history();
1083                 }
1084 #else /* CONFIG_READLINE */
1085                 printf("> ");
1086                 cmd = fgets(cmdbuf, sizeof(cmdbuf), stdin);
1087 #endif /* CONFIG_READLINE */
1088 #ifndef CONFIG_NATIVE_WINDOWS
1089                 alarm(0);
1090 #endif /* CONFIG_NATIVE_WINDOWS */
1091                 if (cmd == NULL)
1092                         break;
1093                 pos = cmd;
1094                 while (*pos != '\0') {
1095                         if (*pos == '\n') {
1096                                 *pos = '\0';
1097                                 break;
1098                         }
1099                         pos++;
1100                 }
1101                 argc = 0;
1102                 pos = cmd;
1103                 for (;;) {
1104                         while (*pos == ' ')
1105                                 pos++;
1106                         if (*pos == '\0')
1107                                 break;
1108                         argv[argc] = pos;
1109                         argc++;
1110                         if (argc == max_args)
1111                                 break;
1112                         if (*pos == '"') {
1113                                 char *pos2 = strrchr(pos, '"');
1114                                 if (pos2)
1115                                         pos = pos2 + 1;
1116                         }
1117                         while (*pos != '\0' && *pos != ' ')
1118                                 pos++;
1119                         if (*pos == ' ')
1120                                 *pos++ = '\0';
1121                 }
1122                 if (argc)
1123                         wpa_request(ctrl_conn, argc, argv);
1124
1125                 if (cmd != cmdbuf)
1126                         free(cmd);
1127         } while (!wpa_cli_quit);
1128
1129 #ifdef CONFIG_READLINE
1130         if (hfile) {
1131                 /* Save command history, excluding lines that may contain
1132                  * passwords. */
1133                 HIST_ENTRY *h;
1134                 history_set_pos(0);
1135                 h = next_history();
1136                 while (h) {
1137                         char *p = h->line;
1138                         while (*p == ' ' || *p == '\t')
1139                                 p++;
1140                         if (strncasecmp(p, "pa", 2) == 0 ||
1141                             strncasecmp(p, "o", 1) == 0 ||
1142                             strncasecmp(p, "n", 1)) {
1143                                 h = remove_history(where_history());
1144                                 if (h) {
1145                                         free(h->line);
1146                                         free(h->data);
1147                                         free(h);
1148                                 }
1149                                 h = current_history();
1150                         } else {
1151                                 h = next_history();
1152                         }
1153                 }
1154                 write_history(hfile);
1155                 free(hfile);
1156         }
1157 #endif /* CONFIG_READLINE */
1158 }
1159
1160
1161 static void wpa_cli_action(struct wpa_ctrl *ctrl)
1162 {
1163         fd_set rfds;
1164         int fd, res;
1165         struct timeval tv;
1166         char buf[16];
1167         size_t len;
1168
1169         fd = wpa_ctrl_get_fd(ctrl);
1170
1171         while (!wpa_cli_quit) {
1172                 FD_ZERO(&rfds);
1173                 FD_SET(fd, &rfds);
1174                 tv.tv_sec = 2;
1175                 tv.tv_usec = 0;
1176                 res = select(fd + 1, &rfds, NULL, NULL, &tv);
1177                 if (res < 0 && errno != EINTR) {
1178                         perror("select");
1179                         break;
1180                 }
1181
1182                 if (FD_ISSET(fd, &rfds))
1183                         wpa_cli_recv_pending(ctrl, 0, 1);
1184                 else {
1185                         /* verify that connection is still working */
1186                         len = sizeof(buf) - 1;
1187                         if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1188                                              wpa_cli_action_cb) < 0 ||
1189                             len < 4 || memcmp(buf, "PONG", 4) != 0) {
1190                                 printf("wpa_supplicant did not reply to PING "
1191                                        "command - exiting\n");
1192                                 break;
1193                         }
1194                 }
1195         }
1196 }
1197
1198
1199 static void wpa_cli_cleanup(void)
1200 {
1201         wpa_cli_close_connection();
1202         if (pid_file)
1203                 unlink(pid_file);
1204
1205 #ifdef CONFIG_NATIVE_WINDOWS
1206         WSACleanup();
1207 #endif /* CONFIG_NATIVE_WINDOWS */
1208 }
1209
1210 static void wpa_cli_terminate(int sig)
1211 {
1212         wpa_cli_cleanup();
1213         exit(0);
1214 }
1215
1216
1217 #ifndef CONFIG_NATIVE_WINDOWS
1218 static void wpa_cli_alarm(int sig)
1219 {
1220         if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
1221                 printf("Connection to wpa_supplicant lost - trying to "
1222                        "reconnect\n");
1223                 wpa_cli_close_connection();
1224         }
1225         if (!ctrl_conn) {
1226                 ctrl_conn = wpa_cli_open_connection(ctrl_ifname);
1227                 if (ctrl_conn) {
1228                         printf("Connection to wpa_supplicant "
1229                                "re-established\n");
1230                         if (wpa_ctrl_attach(ctrl_conn) == 0) {
1231                                 wpa_cli_attached = 1;
1232                         } else {
1233                                 printf("Warning: Failed to attach to "
1234                                        "wpa_supplicant.\n");
1235                         }
1236                 }
1237         }
1238         if (ctrl_conn)
1239                 wpa_cli_recv_pending(ctrl_conn, 1, 0);
1240         alarm(1);
1241 }
1242 #endif /* CONFIG_NATIVE_WINDOWS */
1243
1244
1245 int main(int argc, char *argv[])
1246 {
1247         int interactive;
1248         int warning_displayed = 0;
1249         int c;
1250         int daemonize = 0;
1251         FILE *f;
1252         const char *global = NULL;
1253
1254 #ifdef CONFIG_NATIVE_WINDOWS
1255         WSADATA wsaData;
1256         if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
1257                 printf("Could not find a usable WinSock.dll\n");
1258                 return -1;
1259         }
1260 #endif /* CONFIG_NATIVE_WINDOWS */
1261
1262         for (;;) {
1263                 c = getopt(argc, argv, "a:Bg:hi:p:P:v");
1264                 if (c < 0)
1265                         break;
1266                 switch (c) {
1267                 case 'a':
1268                         action_file = optarg;
1269                         break;
1270                 case 'B':
1271                         daemonize = 1;
1272                         break;
1273                 case 'g':
1274                         global = optarg;
1275                         break;
1276                 case 'h':
1277                         usage();
1278                         return 0;
1279                 case 'v':
1280                         printf("%s\n", wpa_cli_version);
1281                         return 0;
1282                 case 'i':
1283                         ctrl_ifname = strdup(optarg);
1284                         break;
1285                 case 'p':
1286                         ctrl_iface_dir = optarg;
1287                         break;
1288                 case 'P':
1289                         pid_file = optarg;
1290                         break;
1291                 default:
1292                         usage();
1293                         return -1;
1294                 }
1295         }
1296
1297         interactive = (argc == optind) && (action_file == NULL);
1298
1299         if (interactive)
1300                 printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license);
1301
1302         if (global) {
1303                 ctrl_conn = wpa_ctrl_open(global);
1304                 if (ctrl_conn == NULL) {
1305                         perror("Failed to connect to wpa_supplicant - "
1306                                "wpa_ctrl_open");
1307                         return -1;
1308                 }
1309         }
1310
1311         for (; !global;) {
1312                 if (ctrl_ifname == NULL) {
1313                         struct dirent *dent;
1314                         DIR *dir = opendir(ctrl_iface_dir);
1315                         if (dir) {
1316                                 while ((dent = readdir(dir))) {
1317                                         if (strcmp(dent->d_name, ".") == 0 ||
1318                                             strcmp(dent->d_name, "..") == 0)
1319                                                 continue;
1320                                         printf("Selected interface '%s'\n",
1321                                                dent->d_name);
1322                                         ctrl_ifname = strdup(dent->d_name);
1323                                         break;
1324                                 }
1325                                 closedir(dir);
1326                         }
1327                 }
1328                 ctrl_conn = wpa_cli_open_connection(ctrl_ifname);
1329                 if (ctrl_conn) {
1330                         if (warning_displayed)
1331                                 printf("Connection established.\n");
1332                         break;
1333                 }
1334
1335                 if (!interactive) {
1336                         perror("Failed to connect to wpa_supplicant - "
1337                                "wpa_ctrl_open");
1338                         return -1;
1339                 }
1340
1341                 if (!warning_displayed) {
1342                         printf("Could not connect to wpa_supplicant - "
1343                                "re-trying\n");
1344                         warning_displayed = 1;
1345                 }
1346                 sleep(1);
1347                 continue;
1348         }
1349
1350         signal(SIGINT, wpa_cli_terminate);
1351         signal(SIGTERM, wpa_cli_terminate);
1352 #ifndef CONFIG_NATIVE_WINDOWS
1353         signal(SIGALRM, wpa_cli_alarm);
1354 #endif /* CONFIG_NATIVE_WINDOWS */
1355
1356         if (interactive || action_file) {
1357                 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1358                         wpa_cli_attached = 1;
1359                 } else {
1360                         printf("Warning: Failed to attach to "
1361                                "wpa_supplicant.\n");
1362                         if (!interactive)
1363                                 return -1;
1364                 }
1365         }
1366
1367         if (daemonize && daemon(0, 0)) {
1368                 perror("daemon");
1369                 return -1;
1370         }
1371
1372         if (pid_file) {
1373                 f = fopen(pid_file, "w");
1374                 if (f) {
1375                         fprintf(f, "%u\n", getpid());
1376                         fclose(f);
1377                 }
1378         }
1379
1380         if (interactive)
1381                 wpa_cli_interactive();
1382         else if (action_file)
1383                 wpa_cli_action(ctrl_conn);
1384         else
1385                 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1386
1387         free(ctrl_ifname);
1388         wpa_cli_cleanup();
1389
1390         return 0;
1391 }