]> git.ipfire.org Git - thirdparty/hostap.git/blame - hostapd/hostapd_cli.c
hostapd: Add LCI request
[thirdparty/hostap.git] / hostapd / hostapd_cli.c
CommitLineData
6fc6879b
JM
1/*
2 * hostapd - command line interface for hostapd daemon
15c56067 3 * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
6fc6879b 4 *
0f3d578e
JM
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
6fc6879b
JM
7 */
8
9#include "includes.h"
10#include <dirent.h>
11
90973fb2 12#include "common/wpa_ctrl.h"
d9d1b952 13#include "common/ieee802_11_defs.h"
42838059
JM
14#include "utils/common.h"
15#include "utils/eloop.h"
16#include "utils/edit.h"
90973fb2 17#include "common/version.h"
6fc6879b 18
56885eec 19#ifndef CONFIG_NO_CTRL_IFACE
6fc6879b 20
8b423edb 21static const char *const hostapd_cli_version =
6fc6879b 22"hostapd_cli v" VERSION_STR "\n"
15c56067 23"Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors";
6fc6879b
JM
24
25
8b423edb 26static const char *const hostapd_cli_license =
331f89ff
JM
27"This software may be distributed under the terms of the BSD license.\n"
28"See README for more details.\n";
6fc6879b 29
8b423edb 30static const char *const hostapd_cli_full_license =
331f89ff 31"This software may be distributed under the terms of the BSD license.\n"
6fc6879b
JM
32"\n"
33"Redistribution and use in source and binary forms, with or without\n"
34"modification, are permitted provided that the following conditions are\n"
35"met:\n"
36"\n"
37"1. Redistributions of source code must retain the above copyright\n"
38" notice, this list of conditions and the following disclaimer.\n"
39"\n"
40"2. Redistributions in binary form must reproduce the above copyright\n"
41" notice, this list of conditions and the following disclaimer in the\n"
42" documentation and/or other materials provided with the distribution.\n"
43"\n"
44"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
45" names of its contributors may be used to endorse or promote products\n"
46" derived from this software without specific prior written permission.\n"
47"\n"
48"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
49"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
50"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
51"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
52"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
53"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
54"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
55"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
56"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
57"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
58"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
59"\n";
60
8b423edb 61static const char *const commands_help =
6fc6879b
JM
62"Commands:\n"
63" mib get MIB variables (dot1x, dot11, radius)\n"
64" sta <addr> get MIB variables for one station\n"
65" all_sta get MIB variables for all stations\n"
66" new_sta <addr> add a new station\n"
488d0934
JM
67" deauthenticate <addr> deauthenticate a station\n"
68" disassociate <addr> disassociate a station\n"
88b4b424
JM
69#ifdef CONFIG_IEEE80211W
70" sa_query <addr> send SA Query to a station\n"
71#endif /* CONFIG_IEEE80211W */
ad08c363 72#ifdef CONFIG_WPS
31fcea93 73" wps_pin <uuid> <pin> [timeout] [addr] add WPS Enrollee PIN\n"
3981cb3c 74" wps_check_pin <PIN> verify PIN checksum\n"
ad08c363 75" wps_pbc indicate button pushed to initiate PBC\n"
1c79cdff 76" wps_cancel cancel the pending WPS operation\n"
bb45b6d7
JM
77#ifdef CONFIG_WPS_NFC
78" wps_nfc_tag_read <hexdump> report read NFC tag with WPS data\n"
3cf7a59d 79" wps_nfc_config_token <WPS/NDEF> build NFC configuration token\n"
ffdaa05a 80" wps_nfc_token <WPS/NDEF/enable/disable> manager NFC password token\n"
bb45b6d7 81#endif /* CONFIG_WPS_NFC */
5a1cc30f 82" wps_ap_pin <cmd> [params..] enable/disable AP PIN\n"
450eddcf 83" wps_config <SSID> <auth> <encr> <key> configure AP\n"
3351a384 84" wps_get_status show current WPS status\n"
ad08c363 85#endif /* CONFIG_WPS */
403b96fe 86" get_config show current configuration\n"
6fc6879b
JM
87" help show this usage help\n"
88" interface [ifname] show interfaces/select interface\n"
89" level <debug level> change debug level\n"
90" license show full hostapd_cli license\n"
91" quit exit hostapd_cli\n";
92
93static struct wpa_ctrl *ctrl_conn;
94static int hostapd_cli_quit = 0;
95static int hostapd_cli_attached = 0;
2d39a4d8
JJ
96
97#ifndef CONFIG_CTRL_IFACE_DIR
98#define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd"
99#endif /* CONFIG_CTRL_IFACE_DIR */
100static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
4ae71209 101static const char *client_socket_dir = NULL;
2d39a4d8 102
6fc6879b 103static char *ctrl_ifname = NULL;
bae92174
GD
104static const char *pid_file = NULL;
105static const char *action_file = NULL;
1cc84c1c 106static int ping_interval = 5;
42838059 107static int interactive = 0;
6fc6879b
JM
108
109
110static void usage(void)
111{
112 fprintf(stderr, "%s\n", hostapd_cli_version);
bae92174
GD
113 fprintf(stderr,
114 "\n"
115 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
116 "[-a<path>] \\\n"
b8e5426d 117 " [-P<pid file>] [-G<ping interval>] [command..]\n"
6fc6879b
JM
118 "\n"
119 "Options:\n"
120 " -h help (show this usage text)\n"
121 " -v shown version information\n"
122 " -p<path> path to find control sockets (default: "
123 "/var/run/hostapd)\n"
4ae71209
MM
124 " -s<dir_path> dir path to open client sockets (default: "
125 CONFIG_CTRL_IFACE_DIR ")\n"
bae92174
GD
126 " -a<file> run in daemon mode executing the action file "
127 "based on events\n"
128 " from hostapd\n"
129 " -B run a daemon in the background\n"
6fc6879b
JM
130 " -i<ifname> Interface to listen on (default: first "
131 "interface found in the\n"
132 " socket path)\n\n"
133 "%s",
134 commands_help);
135}
136
137
138static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
139{
56885eec 140#ifndef CONFIG_CTRL_IFACE_UDP
6fc6879b
JM
141 char *cfile;
142 int flen;
56885eec 143#endif /* !CONFIG_CTRL_IFACE_UDP */
6fc6879b
JM
144
145 if (ifname == NULL)
146 return NULL;
147
56885eec
JD
148#ifdef CONFIG_CTRL_IFACE_UDP
149 ctrl_conn = wpa_ctrl_open(ifname);
150 return ctrl_conn;
151#else /* CONFIG_CTRL_IFACE_UDP */
6fc6879b
JM
152 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
153 cfile = malloc(flen);
154 if (cfile == NULL)
155 return NULL;
156 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
157
4ae71209
MM
158 if (client_socket_dir && client_socket_dir[0] &&
159 access(client_socket_dir, F_OK) < 0) {
160 perror(client_socket_dir);
161 free(cfile);
162 return NULL;
163 }
164
165 ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir);
6fc6879b
JM
166 free(cfile);
167 return ctrl_conn;
56885eec 168#endif /* CONFIG_CTRL_IFACE_UDP */
6fc6879b
JM
169}
170
171
172static void hostapd_cli_close_connection(void)
173{
174 if (ctrl_conn == NULL)
175 return;
176
177 if (hostapd_cli_attached) {
178 wpa_ctrl_detach(ctrl_conn);
179 hostapd_cli_attached = 0;
180 }
181 wpa_ctrl_close(ctrl_conn);
182 ctrl_conn = NULL;
183}
184
185
186static void hostapd_cli_msg_cb(char *msg, size_t len)
187{
188 printf("%s\n", msg);
189}
190
191
192static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
193{
194 char buf[4096];
195 size_t len;
196 int ret;
197
198 if (ctrl_conn == NULL) {
199 printf("Not connected to hostapd - command dropped.\n");
200 return -1;
201 }
202 len = sizeof(buf) - 1;
203 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
204 hostapd_cli_msg_cb);
205 if (ret == -2) {
206 printf("'%s' command timed out.\n", cmd);
207 return -2;
208 } else if (ret < 0) {
209 printf("'%s' command failed.\n", cmd);
210 return -1;
211 }
212 if (print) {
213 buf[len] = '\0';
214 printf("%s", buf);
215 }
216 return 0;
217}
218
219
220static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
221{
222 return _wpa_ctrl_command(ctrl, cmd, 1);
223}
224
225
12605642
DL
226static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
227 char *argv[])
228{
229 int i, res;
230 char *pos, *end;
231
232 pos = buf;
233 end = buf + buflen;
234
235 res = os_snprintf(pos, end - pos, "%s", cmd);
236 if (os_snprintf_error(end - pos, res))
237 goto fail;
238 pos += res;
239
240 for (i = 0; i < argc; i++) {
241 res = os_snprintf(pos, end - pos, " %s", argv[i]);
242 if (os_snprintf_error(end - pos, res))
243 goto fail;
244 pos += res;
245 }
246
247 buf[buflen - 1] = '\0';
248 return 0;
249
250fail:
251 printf("Too long command\n");
252 return -1;
253}
254
255
256static int hostapd_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd,
257 int min_args, int argc, char *argv[])
258{
259 char buf[4096];
260
261 if (argc < min_args) {
262 printf("Invalid %s command - at least %d argument%s required.\n",
263 cmd, min_args, min_args > 1 ? "s are" : " is");
264 return -1;
265 }
266 if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0)
267 return -1;
268 return wpa_ctrl_command(ctrl, buf);
269}
270
271
6fc6879b
JM
272static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
273{
274 return wpa_ctrl_command(ctrl, "PING");
275}
276
277
b41a47c0
BG
278static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
279{
280 return wpa_ctrl_command(ctrl, "RELOG");
281}
282
283
5ae6449c
JM
284static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
285{
f0cbb986
JM
286 if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
287 return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
5ae6449c
JM
288 return wpa_ctrl_command(ctrl, "STATUS");
289}
290
291
6fc6879b
JM
292static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
293{
4c03a2b3
JM
294 if (argc > 0) {
295 char buf[100];
296 os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]);
297 return wpa_ctrl_command(ctrl, buf);
298 }
6fc6879b
JM
299 return wpa_ctrl_command(ctrl, "MIB");
300}
301
302
bae92174
GD
303static int hostapd_cli_exec(const char *program, const char *arg1,
304 const char *arg2)
305{
5d4fa2a2 306 char *arg;
bae92174
GD
307 size_t len;
308 int res;
bae92174 309
5d4fa2a2
JM
310 len = os_strlen(arg1) + os_strlen(arg2) + 2;
311 arg = os_malloc(len);
312 if (arg == NULL)
bae92174 313 return -1;
5d4fa2a2
JM
314 os_snprintf(arg, len, "%s %s", arg1, arg2);
315 res = os_exec(program, arg, 1);
316 os_free(arg);
317
318 return res;
bae92174
GD
319}
320
321
322static void hostapd_cli_action_process(char *msg, size_t len)
323{
324 const char *pos;
325
326 pos = msg;
327 if (*pos == '<') {
328 pos = os_strchr(pos, '>');
329 if (pos)
330 pos++;
331 else
332 pos = msg;
333 }
334
335 hostapd_cli_exec(action_file, ctrl_ifname, pos);
336}
337
338
6fc6879b
JM
339static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
340{
341 char buf[64];
ea23df65
JM
342 if (argc < 1) {
343 printf("Invalid 'sta' command - at least one argument, STA "
6fc6879b
JM
344 "address, is required.\n");
345 return -1;
346 }
ea23df65
JM
347 if (argc > 1)
348 snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]);
349 else
350 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
6fc6879b
JM
351 return wpa_ctrl_command(ctrl, buf);
352}
353
354
355static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
356 char *argv[])
357{
358 char buf[64];
359 if (argc != 1) {
360 printf("Invalid 'new_sta' command - exactly one argument, STA "
361 "address, is required.\n");
362 return -1;
363 }
364 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
365 return wpa_ctrl_command(ctrl, buf);
366}
367
368
90a3206a
JM
369static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
370 char *argv[])
371{
372 char buf[64];
b91ab76e 373 if (argc < 1) {
90a3206a
JM
374 printf("Invalid 'deauthenticate' command - exactly one "
375 "argument, STA address, is required.\n");
376 return -1;
377 }
b91ab76e
JM
378 if (argc > 1)
379 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
380 argv[0], argv[1]);
381 else
382 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
90a3206a
JM
383 return wpa_ctrl_command(ctrl, buf);
384}
385
386
387static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
388 char *argv[])
389{
390 char buf[64];
b91ab76e 391 if (argc < 1) {
90a3206a
JM
392 printf("Invalid 'disassociate' command - exactly one "
393 "argument, STA address, is required.\n");
394 return -1;
395 }
b91ab76e
JM
396 if (argc > 1)
397 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
398 argv[0], argv[1]);
399 else
400 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
90a3206a
JM
401 return wpa_ctrl_command(ctrl, buf);
402}
403
404
88b4b424
JM
405#ifdef CONFIG_IEEE80211W
406static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
407 char *argv[])
408{
409 char buf[64];
410 if (argc != 1) {
411 printf("Invalid 'sa_query' command - exactly one argument, "
412 "STA address, is required.\n");
413 return -1;
414 }
415 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
416 return wpa_ctrl_command(ctrl, buf);
417}
418#endif /* CONFIG_IEEE80211W */
419
420
ad08c363
JM
421#ifdef CONFIG_WPS
422static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
423 char *argv[])
424{
31fcea93 425 char buf[256];
077a781f
JM
426 if (argc < 2) {
427 printf("Invalid 'wps_pin' command - at least two arguments, "
ad08c363
JM
428 "UUID and PIN, are required.\n");
429 return -1;
430 }
31fcea93
JM
431 if (argc > 3)
432 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
433 argv[0], argv[1], argv[2], argv[3]);
434 else if (argc > 2)
077a781f
JM
435 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
436 argv[0], argv[1], argv[2]);
437 else
438 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
ad08c363
JM
439 return wpa_ctrl_command(ctrl, buf);
440}
441
442
3981cb3c
JM
443static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
444 char *argv[])
445{
446 char cmd[256];
447 int res;
448
449 if (argc != 1 && argc != 2) {
450 printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
451 "- PIN to be verified\n");
452 return -1;
453 }
454
455 if (argc == 2)
456 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
457 argv[0], argv[1]);
458 else
459 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
460 argv[0]);
eeab4f2f 461 if (os_snprintf_error(sizeof(cmd), res)) {
3981cb3c
JM
462 printf("Too long WPS_CHECK_PIN command.\n");
463 return -1;
464 }
465 return wpa_ctrl_command(ctrl, cmd);
466}
467
468
ad08c363
JM
469static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
470 char *argv[])
471{
472 return wpa_ctrl_command(ctrl, "WPS_PBC");
473}
46bdb83a
MH
474
475
4c374cde
AS
476static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
477 char *argv[])
478{
479 return wpa_ctrl_command(ctrl, "WPS_CANCEL");
480}
481
482
bb45b6d7
JM
483#ifdef CONFIG_WPS_NFC
484static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
485 char *argv[])
486{
487 int ret;
488 char *buf;
489 size_t buflen;
490
491 if (argc != 1) {
492 printf("Invalid 'wps_nfc_tag_read' command - one argument "
493 "is required.\n");
494 return -1;
495 }
496
497 buflen = 18 + os_strlen(argv[0]);
498 buf = os_malloc(buflen);
499 if (buf == NULL)
500 return -1;
501 os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
502
503 ret = wpa_ctrl_command(ctrl, buf);
504 os_free(buf);
505
506 return ret;
507}
3cf7a59d
JM
508
509
510static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
511 int argc, char *argv[])
512{
513 char cmd[64];
514 int res;
515
516 if (argc != 1) {
517 printf("Invalid 'wps_nfc_config_token' command - one argument "
518 "is required.\n");
519 return -1;
520 }
521
522 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
523 argv[0]);
eeab4f2f 524 if (os_snprintf_error(sizeof(cmd), res)) {
3cf7a59d
JM
525 printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
526 return -1;
527 }
528 return wpa_ctrl_command(ctrl, cmd);
529}
ffdaa05a
JM
530
531
532static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
533 int argc, char *argv[])
534{
535 char cmd[64];
536 int res;
537
538 if (argc != 1) {
539 printf("Invalid 'wps_nfc_token' command - one argument is "
540 "required.\n");
541 return -1;
542 }
543
544 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
eeab4f2f 545 if (os_snprintf_error(sizeof(cmd), res)) {
ffdaa05a
JM
546 printf("Too long WPS_NFC_TOKEN command.\n");
547 return -1;
548 }
549 return wpa_ctrl_command(ctrl, cmd);
550}
6772a90a
JM
551
552
553static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
554 int argc, char *argv[])
555{
556 char cmd[64];
557 int res;
558
559 if (argc != 2) {
560 printf("Invalid 'nfc_get_handover_sel' command - two arguments "
561 "are required.\n");
562 return -1;
563 }
564
565 res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
566 argv[0], argv[1]);
eeab4f2f 567 if (os_snprintf_error(sizeof(cmd), res)) {
6772a90a
JM
568 printf("Too long NFC_GET_HANDOVER_SEL command.\n");
569 return -1;
570 }
571 return wpa_ctrl_command(ctrl, cmd);
572}
573
bb45b6d7
JM
574#endif /* CONFIG_WPS_NFC */
575
576
5a1cc30f
JM
577static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
578 char *argv[])
579{
580 char buf[64];
581 if (argc < 1) {
582 printf("Invalid 'wps_ap_pin' command - at least one argument "
583 "is required.\n");
584 return -1;
585 }
586 if (argc > 2)
587 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
588 argv[0], argv[1], argv[2]);
589 else if (argc > 1)
590 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
591 argv[0], argv[1]);
592 else
593 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
594 return wpa_ctrl_command(ctrl, buf);
595}
450eddcf
JM
596
597
3351a384
JM
598static int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc,
599 char *argv[])
600{
601 return wpa_ctrl_command(ctrl, "WPS_GET_STATUS");
602}
603
604
450eddcf
JM
605static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
606 char *argv[])
607{
608 char buf[256];
d9d1b952 609 char ssid_hex[2 * SSID_MAX_LEN + 1];
450eddcf
JM
610 char key_hex[2 * 64 + 1];
611 int i;
612
613 if (argc < 1) {
614 printf("Invalid 'wps_config' command - at least two arguments "
615 "are required.\n");
616 return -1;
617 }
618
619 ssid_hex[0] = '\0';
d9d1b952 620 for (i = 0; i < SSID_MAX_LEN; i++) {
450eddcf
JM
621 if (argv[0][i] == '\0')
622 break;
623 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
624 }
625
626 key_hex[0] = '\0';
627 if (argc > 3) {
628 for (i = 0; i < 64; i++) {
629 if (argv[3][i] == '\0')
630 break;
631 os_snprintf(&key_hex[i * 2], 3, "%02x",
632 argv[3][i]);
633 }
634 }
635
636 if (argc > 3)
637 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
638 ssid_hex, argv[1], argv[2], key_hex);
639 else if (argc > 2)
640 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
641 ssid_hex, argv[1], argv[2]);
642 else
643 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
644 ssid_hex, argv[1]);
645 return wpa_ctrl_command(ctrl, buf);
646}
ad08c363
JM
647#endif /* CONFIG_WPS */
648
649
2049a875
JM
650static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
651 char *argv[])
652{
653 char buf[300];
654 int res;
655
656 if (argc < 2) {
657 printf("Invalid 'disassoc_imminent' command - two arguments "
658 "(STA addr and Disassociation Timer) are needed\n");
659 return -1;
660 }
661
662 res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
663 argv[0], argv[1]);
d85e1fc8 664 if (os_snprintf_error(sizeof(buf), res))
2049a875
JM
665 return -1;
666 return wpa_ctrl_command(ctrl, buf);
667}
668
669
71269b37
JM
670static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
671 char *argv[])
672{
673 char buf[300];
674 int res;
675
d5b559b6
KP
676 if (argc < 3) {
677 printf("Invalid 'ess_disassoc' command - three arguments (STA "
678 "addr, disassoc timer, and URL) are needed\n");
71269b37
JM
679 return -1;
680 }
681
d5b559b6
KP
682 res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
683 argv[0], argv[1], argv[2]);
d85e1fc8 684 if (os_snprintf_error(sizeof(buf), res))
71269b37
JM
685 return -1;
686 return wpa_ctrl_command(ctrl, buf);
687}
688
689
a30dff07
JM
690static int hostapd_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc,
691 char *argv[])
692{
693 char buf[2000], *tmp;
694 int res, i, total;
695
696 if (argc < 1) {
697 printf("Invalid 'bss_tm_req' command - at least one argument (STA addr) is needed\n");
698 return -1;
699 }
700
701 res = os_snprintf(buf, sizeof(buf), "BSS_TM_REQ %s", argv[0]);
d85e1fc8 702 if (os_snprintf_error(sizeof(buf), res))
a30dff07
JM
703 return -1;
704
705 total = res;
706 for (i = 1; i < argc; i++) {
707 tmp = &buf[total];
708 res = os_snprintf(tmp, sizeof(buf) - total, " %s", argv[i]);
eeab4f2f 709 if (os_snprintf_error(sizeof(buf) - total, res))
a30dff07
JM
710 return -1;
711 total += res;
712 }
713 return wpa_ctrl_command(ctrl, buf);
714}
715
716
403b96fe
JM
717static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
718 char *argv[])
719{
720 return wpa_ctrl_command(ctrl, "GET_CONFIG");
721}
722
723
6fc6879b
JM
724static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
725 char *addr, size_t addr_len)
726{
727 char buf[4096], *pos;
728 size_t len;
729 int ret;
730
731 if (ctrl_conn == NULL) {
732 printf("Not connected to hostapd - command dropped.\n");
733 return -1;
734 }
735 len = sizeof(buf) - 1;
736 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
737 hostapd_cli_msg_cb);
738 if (ret == -2) {
739 printf("'%s' command timed out.\n", cmd);
740 return -2;
741 } else if (ret < 0) {
742 printf("'%s' command failed.\n", cmd);
743 return -1;
744 }
745
746 buf[len] = '\0';
747 if (memcmp(buf, "FAIL", 4) == 0)
748 return -1;
749 printf("%s", buf);
750
751 pos = buf;
752 while (*pos != '\0' && *pos != '\n')
753 pos++;
754 *pos = '\0';
755 os_strlcpy(addr, buf, addr_len);
756 return 0;
757}
758
759
760static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
761 char *argv[])
762{
763 char addr[32], cmd[64];
764
765 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
766 return 0;
767 do {
768 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
769 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
770
771 return -1;
772}
773
774
775static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
776{
777 printf("%s", commands_help);
778 return 0;
779}
780
781
782static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
783 char *argv[])
784{
785 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
786 return 0;
787}
788
789
c551700f
KP
790static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl,
791 int argc, char *argv[])
792{
793 char buf[200];
794 int res;
795
796 if (argc != 1) {
797 printf("Invalid 'set_qos_map_set' command - "
798 "one argument (comma delimited QoS map set) "
799 "is needed\n");
800 return -1;
801 }
802
803 res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
d85e1fc8 804 if (os_snprintf_error(sizeof(buf), res))
c551700f
KP
805 return -1;
806 return wpa_ctrl_command(ctrl, buf);
807}
808
809
810static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
811 int argc, char *argv[])
812{
813 char buf[50];
814 int res;
815
816 if (argc != 1) {
817 printf("Invalid 'send_qos_map_conf' command - "
818 "one argument (STA addr) is needed\n");
819 return -1;
820 }
821
822 res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
d85e1fc8 823 if (os_snprintf_error(sizeof(buf), res))
c551700f
KP
824 return -1;
825 return wpa_ctrl_command(ctrl, buf);
826}
827
828
3fb17a95
JM
829static int hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc,
830 char *argv[])
831{
832 char buf[300];
833 int res;
834
835 if (argc < 2) {
836 printf("Invalid 'hs20_wnm_notif' command - two arguments (STA "
837 "addr and URL) are needed\n");
838 return -1;
839 }
840
841 res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s",
842 argv[0], argv[1]);
d85e1fc8 843 if (os_snprintf_error(sizeof(buf), res))
3fb17a95
JM
844 return -1;
845 return wpa_ctrl_command(ctrl, buf);
846}
847
848
8e1146d9
JM
849static int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc,
850 char *argv[])
851{
852 char buf[300];
853 int res;
854
855 if (argc < 3) {
856 printf("Invalid 'hs20_deauth_req' command - at least three arguments (STA addr, Code, Re-auth Delay) are needed\n");
857 return -1;
858 }
859
860 if (argc > 3)
861 res = os_snprintf(buf, sizeof(buf),
862 "HS20_DEAUTH_REQ %s %s %s %s",
863 argv[0], argv[1], argv[2], argv[3]);
864 else
865 res = os_snprintf(buf, sizeof(buf),
866 "HS20_DEAUTH_REQ %s %s %s",
867 argv[0], argv[1], argv[2]);
d85e1fc8 868 if (os_snprintf_error(sizeof(buf), res))
8e1146d9
JM
869 return -1;
870 return wpa_ctrl_command(ctrl, buf);
871}
872
873
6fc6879b
JM
874static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
875{
876 hostapd_cli_quit = 1;
42838059
JM
877 if (interactive)
878 eloop_terminate();
6fc6879b
JM
879 return 0;
880}
881
882
883static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
884{
885 char cmd[256];
886 if (argc != 1) {
887 printf("Invalid LEVEL command: needs one argument (debug "
888 "level)\n");
889 return 0;
890 }
891 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
892 return wpa_ctrl_command(ctrl, cmd);
893}
894
895
896static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
897{
898 struct dirent *dent;
899 DIR *dir;
900
901 dir = opendir(ctrl_iface_dir);
902 if (dir == NULL) {
903 printf("Control interface directory '%s' could not be "
904 "openned.\n", ctrl_iface_dir);
905 return;
906 }
907
908 printf("Available interfaces:\n");
909 while ((dent = readdir(dir))) {
910 if (strcmp(dent->d_name, ".") == 0 ||
911 strcmp(dent->d_name, "..") == 0)
912 continue;
913 printf("%s\n", dent->d_name);
914 }
915 closedir(dir);
916}
917
918
919static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
920 char *argv[])
921{
922 if (argc < 1) {
923 hostapd_cli_list_interfaces(ctrl);
924 return 0;
925 }
926
927 hostapd_cli_close_connection();
cc0b7cb1
EA
928 os_free(ctrl_ifname);
929 ctrl_ifname = os_strdup(argv[0]);
db9418bb
SG
930 if (ctrl_ifname == NULL)
931 return -1;
6fc6879b
JM
932
933 if (hostapd_cli_open_connection(ctrl_ifname)) {
934 printf("Connected to interface '%s.\n", ctrl_ifname);
935 if (wpa_ctrl_attach(ctrl_conn) == 0) {
936 hostapd_cli_attached = 1;
937 } else {
938 printf("Warning: Failed to attach to "
939 "hostapd.\n");
940 }
941 } else {
942 printf("Could not connect to interface '%s' - re-trying\n",
943 ctrl_ifname);
944 }
945 return 0;
946}
947
948
b4e34f2f
JM
949static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
950{
951 char cmd[256];
952 int res;
953
954 if (argc != 2) {
955 printf("Invalid SET command: needs two arguments (variable "
956 "name and value)\n");
957 return -1;
958 }
959
960 res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
eeab4f2f 961 if (os_snprintf_error(sizeof(cmd), res)) {
b4e34f2f
JM
962 printf("Too long SET command.\n");
963 return -1;
964 }
965 return wpa_ctrl_command(ctrl, cmd);
966}
967
968
acec8d32
JM
969static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
970{
971 char cmd[256];
972 int res;
973
974 if (argc != 1) {
975 printf("Invalid GET command: needs one argument (variable "
976 "name)\n");
977 return -1;
978 }
979
980 res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
eeab4f2f 981 if (os_snprintf_error(sizeof(cmd), res)) {
acec8d32
JM
982 printf("Too long GET command.\n");
983 return -1;
984 }
985 return wpa_ctrl_command(ctrl, cmd);
986}
987
988
ee039107
AN
989#ifdef CONFIG_FST
990static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[])
991{
992 char cmd[256];
993 int res;
994 int i;
995 int total;
996
997 if (argc <= 0) {
998 printf("FST command: parameters are required.\n");
999 return -1;
1000 }
1001
1002 total = os_snprintf(cmd, sizeof(cmd), "FST-MANAGER");
1003
1004 for (i = 0; i < argc; i++) {
1005 res = os_snprintf(cmd + total, sizeof(cmd) - total, " %s",
1006 argv[i]);
1007 if (os_snprintf_error(sizeof(cmd) - total, res)) {
1008 printf("Too long fst command.\n");
1009 return -1;
1010 }
1011 total += res;
1012 }
1013 return wpa_ctrl_command(ctrl, cmd);
1014}
1015#endif /* CONFIG_FST */
1016
1017
334bf36a
AO
1018static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
1019 int argc, char *argv[])
1020{
1021 char cmd[256];
1022 int res;
1023 int i;
1024 char *tmp;
1025 int total;
1026
1027 if (argc < 2) {
1028 printf("Invalid chan_switch command: needs at least two "
1029 "arguments (count and freq)\n"
1030 "usage: <cs_count> <freq> [sec_channel_offset=] "
1031 "[center_freq1=] [center_freq2=] [bandwidth=] "
1032 "[blocktx] [ht|vht]\n");
1033 return -1;
1034 }
1035
1036 res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
1037 argv[0], argv[1]);
eeab4f2f 1038 if (os_snprintf_error(sizeof(cmd), res)) {
334bf36a
AO
1039 printf("Too long CHAN_SWITCH command.\n");
1040 return -1;
1041 }
1042
1043 total = res;
1044 for (i = 2; i < argc; i++) {
1045 tmp = cmd + total;
1046 res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
eeab4f2f 1047 if (os_snprintf_error(sizeof(cmd) - total, res)) {
334bf36a
AO
1048 printf("Too long CHAN_SWITCH command.\n");
1049 return -1;
1050 }
1051 total += res;
1052 }
1053 return wpa_ctrl_command(ctrl, cmd);
1054}
1055
1056
a6938b79
CB
1057static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc,
1058 char *argv[])
1059{
1060 return wpa_ctrl_command(ctrl, "ENABLE");
1061}
1062
1063
1064static int hostapd_cli_cmd_reload(struct wpa_ctrl *ctrl, int argc,
1065 char *argv[])
1066{
1067 return wpa_ctrl_command(ctrl, "RELOAD");
1068}
1069
1070
1071static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc,
1072 char *argv[])
1073{
1074 return wpa_ctrl_command(ctrl, "DISABLE");
1075}
1076
1077
3ae8b7b7
AS
1078static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
1079{
1080 char cmd[256];
1081 int res;
1082
1083 if (argc < 2 || argc > 3) {
1084 printf("Invalid vendor command\n"
1085 "usage: <vendor id> <command id> [<hex formatted command argument>]\n");
1086 return -1;
1087 }
1088
1089 res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
1090 argc == 3 ? argv[2] : "");
eeab4f2f 1091 if (os_snprintf_error(sizeof(cmd), res)) {
3ae8b7b7
AS
1092 printf("Too long VENDOR command.\n");
1093 return -1;
1094 }
1095 return wpa_ctrl_command(ctrl, cmd);
1096}
1097
1098
2c6411ed
JM
1099static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc,
1100 char *argv[])
1101{
1102 return wpa_ctrl_command(ctrl, "ERP_FLUSH");
1103}
1104
1105
5c4f0511
SD
1106static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc,
1107 char *argv[])
1108{
1109 char cmd[256];
1110 int res;
1111
1112 res = os_snprintf(cmd, sizeof(cmd), "LOG_LEVEL%s%s%s%s",
1113 argc >= 1 ? " " : "",
1114 argc >= 1 ? argv[0] : "",
1115 argc == 2 ? " " : "",
1116 argc == 2 ? argv[1] : "");
1117 if (os_snprintf_error(sizeof(cmd), res)) {
1118 printf("Too long option\n");
1119 return -1;
1120 }
1121 return wpa_ctrl_command(ctrl, cmd);
1122}
1123
1124
12605642
DL
1125static int hostapd_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
1126{
1127 if (argc == 0)
1128 return -1;
1129 return hostapd_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]);
1130}
1131
1132
b8daac18
MH
1133static int hostapd_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
1134{
1135 return wpa_ctrl_command(ctrl, "PMKSA");
1136}
1137
1138
4c522c77
MH
1139static int hostapd_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc,
1140 char *argv[])
1141{
1142 return wpa_ctrl_command(ctrl, "PMKSA_FLUSH");
1143}
1144
1145
9b4b2264
DS
1146static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc,
1147 char *argv[])
1148{
1149 char cmd[2048];
1150 int res;
1151
1152 if (argc < 3 || argc > 5) {
1153 printf("Invalid set_neighbor command: needs 3-5 arguments\n");
1154 return -1;
1155 }
1156
1157 res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s",
1158 argv[0], argv[1], argv[2], argc >= 4 ? argv[3] : "",
1159 argc == 5 ? argv[4] : "");
1160 if (os_snprintf_error(sizeof(cmd), res)) {
1161 printf("Too long SET_NEIGHBOR command.\n");
1162 return -1;
1163 }
1164 return wpa_ctrl_command(ctrl, cmd);
1165}
1166
1167
1168static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc,
1169 char *argv[])
1170{
1171 char cmd[400];
1172 int res;
1173
1174 if (argc != 2) {
1175 printf("Invalid remove_neighbor command: needs 2 arguments\n");
1176 return -1;
1177 }
1178
1179 res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NEIGHBOR %s %s",
1180 argv[0], argv[1]);
1181 if (os_snprintf_error(sizeof(cmd), res)) {
1182 printf("Too long REMOVE_NEIGHBOR command.\n");
1183 return -1;
1184 }
1185 return wpa_ctrl_command(ctrl, cmd);
1186}
1187
1188
f4f185a2
DS
1189static int hostapd_cli_cmd_req_lci(struct wpa_ctrl *ctrl, int argc,
1190 char *argv[])
1191{
1192 char cmd[256];
1193 int res;
1194
1195 if (argc != 1) {
1196 printf("Invalid req_lci command - requires destination address\n");
1197 return -1;
1198 }
1199
1200 res = os_snprintf(cmd, sizeof(cmd), "REQ_LCI %s", argv[0]);
1201 if (os_snprintf_error(sizeof(cmd), res)) {
1202 printf("Too long REQ_LCI command.\n");
1203 return -1;
1204 }
1205 return wpa_ctrl_command(ctrl, cmd);
1206}
1207
1208
6fc6879b
JM
1209struct hostapd_cli_cmd {
1210 const char *cmd;
1211 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
1212};
1213
8b423edb 1214static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
6fc6879b
JM
1215 { "ping", hostapd_cli_cmd_ping },
1216 { "mib", hostapd_cli_cmd_mib },
b41a47c0 1217 { "relog", hostapd_cli_cmd_relog },
5ae6449c 1218 { "status", hostapd_cli_cmd_status },
6fc6879b
JM
1219 { "sta", hostapd_cli_cmd_sta },
1220 { "all_sta", hostapd_cli_cmd_all_sta },
1221 { "new_sta", hostapd_cli_cmd_new_sta },
90a3206a
JM
1222 { "deauthenticate", hostapd_cli_cmd_deauthenticate },
1223 { "disassociate", hostapd_cli_cmd_disassociate },
88b4b424
JM
1224#ifdef CONFIG_IEEE80211W
1225 { "sa_query", hostapd_cli_cmd_sa_query },
1226#endif /* CONFIG_IEEE80211W */
ad08c363
JM
1227#ifdef CONFIG_WPS
1228 { "wps_pin", hostapd_cli_cmd_wps_pin },
3981cb3c 1229 { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
ad08c363 1230 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
4c374cde 1231 { "wps_cancel", hostapd_cli_cmd_wps_cancel },
bb45b6d7
JM
1232#ifdef CONFIG_WPS_NFC
1233 { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
3cf7a59d 1234 { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
ffdaa05a 1235 { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
6772a90a 1236 { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
bb45b6d7 1237#endif /* CONFIG_WPS_NFC */
5a1cc30f 1238 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
450eddcf 1239 { "wps_config", hostapd_cli_cmd_wps_config },
3351a384 1240 { "wps_get_status", hostapd_cli_cmd_wps_get_status },
ad08c363 1241#endif /* CONFIG_WPS */
2049a875 1242 { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
71269b37 1243 { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
a30dff07 1244 { "bss_tm_req", hostapd_cli_cmd_bss_tm_req },
403b96fe 1245 { "get_config", hostapd_cli_cmd_get_config },
6fc6879b
JM
1246 { "help", hostapd_cli_cmd_help },
1247 { "interface", hostapd_cli_cmd_interface },
ee039107
AN
1248#ifdef CONFIG_FST
1249 { "fst", hostapd_cli_cmd_fst },
1250#endif /* CONFIG_FST */
12605642 1251 { "raw", hostapd_cli_cmd_raw },
6fc6879b
JM
1252 { "level", hostapd_cli_cmd_level },
1253 { "license", hostapd_cli_cmd_license },
1254 { "quit", hostapd_cli_cmd_quit },
b4e34f2f 1255 { "set", hostapd_cli_cmd_set },
acec8d32 1256 { "get", hostapd_cli_cmd_get },
c551700f
KP
1257 { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
1258 { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
334bf36a 1259 { "chan_switch", hostapd_cli_cmd_chan_switch },
3fb17a95 1260 { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif },
8e1146d9 1261 { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req },
3ae8b7b7 1262 { "vendor", hostapd_cli_cmd_vendor },
a6938b79
CB
1263 { "enable", hostapd_cli_cmd_enable },
1264 { "reload", hostapd_cli_cmd_reload },
1265 { "disable", hostapd_cli_cmd_disable },
2c6411ed 1266 { "erp_flush", hostapd_cli_cmd_erp_flush },
5c4f0511 1267 { "log_level", hostapd_cli_cmd_log_level },
b8daac18 1268 { "pmksa", hostapd_cli_cmd_pmksa },
4c522c77 1269 { "pmksa_flush", hostapd_cli_cmd_pmksa_flush },
9b4b2264
DS
1270 { "set_neighbor", hostapd_cli_cmd_set_neighbor },
1271 { "remove_neighbor", hostapd_cli_cmd_remove_neighbor },
f4f185a2 1272 { "req_lci", hostapd_cli_cmd_req_lci },
6fc6879b
JM
1273 { NULL, NULL }
1274};
1275
1276
1277static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
1278{
8b423edb 1279 const struct hostapd_cli_cmd *cmd, *match = NULL;
6fc6879b
JM
1280 int count;
1281
1282 count = 0;
1283 cmd = hostapd_cli_commands;
1284 while (cmd->cmd) {
1285 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
1286 match = cmd;
acec8d32
JM
1287 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1288 /* we have an exact match */
1289 count = 1;
1290 break;
1291 }
6fc6879b
JM
1292 count++;
1293 }
1294 cmd++;
1295 }
1296
1297 if (count > 1) {
1298 printf("Ambiguous command '%s'; possible commands:", argv[0]);
1299 cmd = hostapd_cli_commands;
1300 while (cmd->cmd) {
1301 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
1302 0) {
1303 printf(" %s", cmd->cmd);
1304 }
1305 cmd++;
1306 }
1307 printf("\n");
1308 } else if (count == 0) {
1309 printf("Unknown command '%s'\n", argv[0]);
1310 } else {
1311 match->handler(ctrl, argc - 1, &argv[1]);
1312 }
1313}
1314
1315
bae92174
GD
1316static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
1317 int action_monitor)
6fc6879b
JM
1318{
1319 int first = 1;
1320 if (ctrl_conn == NULL)
1321 return;
1322 while (wpa_ctrl_pending(ctrl)) {
1323 char buf[256];
1324 size_t len = sizeof(buf) - 1;
1325 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
1326 buf[len] = '\0';
bae92174
GD
1327 if (action_monitor)
1328 hostapd_cli_action_process(buf, len);
1329 else {
1330 if (in_read && first)
1331 printf("\n");
1332 first = 0;
1333 printf("%s\n", buf);
1334 }
6fc6879b
JM
1335 } else {
1336 printf("Could not read pending message.\n");
1337 break;
1338 }
1339 }
1340}
1341
1342
42838059 1343#define max_args 10
6fc6879b 1344
42838059
JM
1345static int tokenize_cmd(char *cmd, char *argv[])
1346{
1347 char *pos;
1348 int argc = 0;
6fc6879b 1349
42838059
JM
1350 pos = cmd;
1351 for (;;) {
1352 while (*pos == ' ')
6fc6879b 1353 pos++;
42838059
JM
1354 if (*pos == '\0')
1355 break;
1356 argv[argc] = pos;
1357 argc++;
1358 if (argc == max_args)
1359 break;
1360 if (*pos == '"') {
1361 char *pos2 = os_strrchr(pos, '"');
1362 if (pos2)
1363 pos = pos2 + 1;
6fc6879b 1364 }
42838059
JM
1365 while (*pos != '\0' && *pos != ' ')
1366 pos++;
1367 if (*pos == ' ')
1368 *pos++ = '\0';
1369 }
bae92174 1370
42838059 1371 return argc;
6fc6879b
JM
1372}
1373
1374
42838059 1375static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
6fc6879b
JM
1376{
1377 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
1378 printf("Connection to hostapd lost - trying to reconnect\n");
1379 hostapd_cli_close_connection();
1380 }
1381 if (!ctrl_conn) {
1382 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1383 if (ctrl_conn) {
1384 printf("Connection to hostapd re-established\n");
1385 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1386 hostapd_cli_attached = 1;
1387 } else {
1388 printf("Warning: Failed to attach to "
1389 "hostapd.\n");
1390 }
1391 }
1392 }
1393 if (ctrl_conn)
bae92174 1394 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
42838059
JM
1395 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1396}
1397
1398
1399static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
1400{
1401 eloop_terminate();
1402}
1403
1404
1405static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
1406{
1407 char *argv[max_args];
1408 int argc;
1409 argc = tokenize_cmd(cmd, argv);
1410 if (argc)
1411 wpa_request(ctrl_conn, argc, argv);
1412}
1413
1414
1415static void hostapd_cli_edit_eof_cb(void *ctx)
1416{
1417 eloop_terminate();
1418}
1419
1420
1421static void hostapd_cli_interactive(void)
1422{
1423 printf("\nInteractive mode\n\n");
1424
1425 eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
1426 edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
2d2398a1 1427 NULL, NULL, NULL, NULL);
42838059
JM
1428 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1429
1430 eloop_run();
1431
1432 edit_deinit(NULL, NULL);
1433 eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
1434}
1435
1436
1437static void hostapd_cli_cleanup(void)
1438{
1439 hostapd_cli_close_connection();
1440 if (pid_file)
1441 os_daemonize_terminate(pid_file);
1442
1443 os_program_deinit();
6fc6879b
JM
1444}
1445
1446
bae92174
GD
1447static void hostapd_cli_action(struct wpa_ctrl *ctrl)
1448{
1449 fd_set rfds;
1450 int fd, res;
1451 struct timeval tv;
1452 char buf[256];
1453 size_t len;
1454
1455 fd = wpa_ctrl_get_fd(ctrl);
1456
1457 while (!hostapd_cli_quit) {
1458 FD_ZERO(&rfds);
1459 FD_SET(fd, &rfds);
1460 tv.tv_sec = ping_interval;
1461 tv.tv_usec = 0;
1462 res = select(fd + 1, &rfds, NULL, NULL, &tv);
1463 if (res < 0 && errno != EINTR) {
1464 perror("select");
1465 break;
1466 }
1467
1468 if (FD_ISSET(fd, &rfds))
1469 hostapd_cli_recv_pending(ctrl, 0, 1);
1470 else {
1471 len = sizeof(buf) - 1;
1472 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1473 hostapd_cli_action_process) < 0 ||
1474 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
1475 printf("hostapd did not reply to PING "
1476 "command - exiting\n");
1477 break;
1478 }
1479 }
1480 }
1481}
1482
1483
6fc6879b
JM
1484int main(int argc, char *argv[])
1485{
6fc6879b
JM
1486 int warning_displayed = 0;
1487 int c;
bae92174 1488 int daemonize = 0;
6fc6879b 1489
3433ed8c
JM
1490 if (os_program_init())
1491 return -1;
1492
6fc6879b 1493 for (;;) {
4ae71209 1494 c = getopt(argc, argv, "a:BhG:i:p:P:s:v");
6fc6879b
JM
1495 if (c < 0)
1496 break;
1497 switch (c) {
bae92174
GD
1498 case 'a':
1499 action_file = optarg;
1500 break;
1501 case 'B':
1502 daemonize = 1;
1503 break;
1cc84c1c
JM
1504 case 'G':
1505 ping_interval = atoi(optarg);
1506 break;
6fc6879b
JM
1507 case 'h':
1508 usage();
1509 return 0;
1510 case 'v':
1511 printf("%s\n", hostapd_cli_version);
1512 return 0;
1513 case 'i':
b242d398
JM
1514 os_free(ctrl_ifname);
1515 ctrl_ifname = os_strdup(optarg);
6fc6879b
JM
1516 break;
1517 case 'p':
1518 ctrl_iface_dir = optarg;
1519 break;
b8e5426d
MSS
1520 case 'P':
1521 pid_file = optarg;
1522 break;
4ae71209
MM
1523 case 's':
1524 client_socket_dir = optarg;
1525 break;
6fc6879b
JM
1526 default:
1527 usage();
1528 return -1;
1529 }
1530 }
1531
bae92174 1532 interactive = (argc == optind) && (action_file == NULL);
6fc6879b
JM
1533
1534 if (interactive) {
1535 printf("%s\n\n%s\n\n", hostapd_cli_version,
1536 hostapd_cli_license);
1537 }
1538
42838059
JM
1539 if (eloop_init())
1540 return -1;
1541
6fc6879b
JM
1542 for (;;) {
1543 if (ctrl_ifname == NULL) {
1544 struct dirent *dent;
1545 DIR *dir = opendir(ctrl_iface_dir);
1546 if (dir) {
1547 while ((dent = readdir(dir))) {
b242d398
JM
1548 if (os_strcmp(dent->d_name, ".") == 0
1549 ||
1550 os_strcmp(dent->d_name, "..") == 0)
6fc6879b
JM
1551 continue;
1552 printf("Selected interface '%s'\n",
1553 dent->d_name);
b242d398 1554 ctrl_ifname = os_strdup(dent->d_name);
6fc6879b
JM
1555 break;
1556 }
1557 closedir(dir);
1558 }
1559 }
1560 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1561 if (ctrl_conn) {
1562 if (warning_displayed)
1563 printf("Connection established.\n");
1564 break;
1565 }
1566
1567 if (!interactive) {
1568 perror("Failed to connect to hostapd - "
1569 "wpa_ctrl_open");
1570 return -1;
1571 }
1572
1573 if (!warning_displayed) {
1574 printf("Could not connect to hostapd - re-trying\n");
1575 warning_displayed = 1;
1576 }
b242d398 1577 os_sleep(1, 0);
6fc6879b
JM
1578 continue;
1579 }
1580
bae92174 1581 if (interactive || action_file) {
6fc6879b
JM
1582 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1583 hostapd_cli_attached = 1;
1584 } else {
1585 printf("Warning: Failed to attach to hostapd.\n");
bae92174
GD
1586 if (action_file)
1587 return -1;
6fc6879b 1588 }
bae92174
GD
1589 }
1590
2e69bdd1 1591 if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
bae92174
GD
1592 return -1;
1593
1594 if (interactive)
6fc6879b 1595 hostapd_cli_interactive();
bae92174
GD
1596 else if (action_file)
1597 hostapd_cli_action(ctrl_conn);
1598 else
6fc6879b
JM
1599 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1600
bae92174 1601 os_free(ctrl_ifname);
42838059 1602 eloop_destroy();
bae92174 1603 hostapd_cli_cleanup();
6fc6879b
JM
1604 return 0;
1605}
56885eec
JD
1606
1607#else /* CONFIG_NO_CTRL_IFACE */
1608
1609int main(int argc, char *argv[])
1610{
1611 return -1;
1612}
1613
1614#endif /* CONFIG_NO_CTRL_IFACE */