blob: 1787ab38fffb991f6311f3a5cd1b7bd195631ff4 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * hostapd - command line interface for hostapd daemon
Dmitry Shmidtde47be72016-01-07 12:52:55 -08003 * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "includes.h"
10#include <dirent.h>
11
12#include "common/wpa_ctrl.h"
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -070013#include "common/ieee802_11_defs.h"
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080014#include "utils/common.h"
15#include "utils/eloop.h"
16#include "utils/edit.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070017#include "common/version.h"
18
19
Dmitry Shmidt1d755d02015-04-28 10:34:29 -070020static const char *const hostapd_cli_version =
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070021"hostapd_cli v" VERSION_STR "\n"
Dmitry Shmidtde47be72016-01-07 12:52:55 -080022"Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070023
24
Dmitry Shmidt1d755d02015-04-28 10:34:29 -070025static const char *const hostapd_cli_license =
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -080026"This software may be distributed under the terms of the BSD license.\n"
27"See README for more details.\n";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070028
Dmitry Shmidt1d755d02015-04-28 10:34:29 -070029static const char *const hostapd_cli_full_license =
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -080030"This software may be distributed under the terms of the BSD license.\n"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070031"\n"
32"Redistribution and use in source and binary forms, with or without\n"
33"modification, are permitted provided that the following conditions are\n"
34"met:\n"
35"\n"
36"1. Redistributions of source code must retain the above copyright\n"
37" notice, this list of conditions and the following disclaimer.\n"
38"\n"
39"2. Redistributions in binary form must reproduce the above copyright\n"
40" notice, this list of conditions and the following disclaimer in the\n"
41" documentation and/or other materials provided with the distribution.\n"
42"\n"
43"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
44" names of its contributors may be used to endorse or promote products\n"
45" derived from this software without specific prior written permission.\n"
46"\n"
47"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
48"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
49"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
50"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
51"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
52"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
53"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
54"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
55"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
56"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
57"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
58"\n";
59
Dmitry Shmidt1d755d02015-04-28 10:34:29 -070060static const char *const commands_help =
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070061"Commands:\n"
62" mib get MIB variables (dot1x, dot11, radius)\n"
63" sta <addr> get MIB variables for one station\n"
64" all_sta get MIB variables for all stations\n"
65" new_sta <addr> add a new station\n"
66" deauthenticate <addr> deauthenticate a station\n"
67" disassociate <addr> disassociate a station\n"
68#ifdef CONFIG_IEEE80211W
69" sa_query <addr> send SA Query to a station\n"
70#endif /* CONFIG_IEEE80211W */
71#ifdef CONFIG_WPS
72" wps_pin <uuid> <pin> [timeout] [addr] add WPS Enrollee PIN\n"
73" wps_check_pin <PIN> verify PIN checksum\n"
74" wps_pbc indicate button pushed to initiate PBC\n"
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070075" wps_cancel cancel the pending WPS operation\n"
Dmitry Shmidt04949592012-07-19 12:16:46 -070076#ifdef CONFIG_WPS_NFC
77" wps_nfc_tag_read <hexdump> report read NFC tag with WPS data\n"
78" wps_nfc_config_token <WPS/NDEF> build NFC configuration token\n"
79" wps_nfc_token <WPS/NDEF/enable/disable> manager NFC password token\n"
80#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070081" wps_ap_pin <cmd> [params..] enable/disable AP PIN\n"
82" wps_config <SSID> <auth> <encr> <key> configure AP\n"
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070083" wps_get_status show current WPS status\n"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070084#endif /* CONFIG_WPS */
85" get_config show current configuration\n"
86" help show this usage help\n"
87" interface [ifname] show interfaces/select interface\n"
88" level <debug level> change debug level\n"
89" license show full hostapd_cli license\n"
90" quit exit hostapd_cli\n";
91
92static struct wpa_ctrl *ctrl_conn;
93static int hostapd_cli_quit = 0;
94static int hostapd_cli_attached = 0;
Jeff Johnson205f2142012-09-03 22:12:17 -070095
96#ifndef CONFIG_CTRL_IFACE_DIR
97#define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd"
98#endif /* CONFIG_CTRL_IFACE_DIR */
99static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800100static const char *client_socket_dir = NULL;
Jeff Johnson205f2142012-09-03 22:12:17 -0700101
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700102static char *ctrl_ifname = NULL;
103static const char *pid_file = NULL;
104static const char *action_file = NULL;
105static int ping_interval = 5;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800106static int interactive = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700107
108
109static void usage(void)
110{
111 fprintf(stderr, "%s\n", hostapd_cli_version);
112 fprintf(stderr,
113 "\n"
114 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
115 "[-a<path>] \\\n"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800116 " [-P<pid file>] [-G<ping interval>] [command..]\n"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700117 "\n"
118 "Options:\n"
119 " -h help (show this usage text)\n"
120 " -v shown version information\n"
121 " -p<path> path to find control sockets (default: "
122 "/var/run/hostapd)\n"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800123 " -s<dir_path> dir path to open client sockets (default: "
124 CONFIG_CTRL_IFACE_DIR ")\n"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700125 " -a<file> run in daemon mode executing the action file "
126 "based on events\n"
127 " from hostapd\n"
128 " -B run a daemon in the background\n"
129 " -i<ifname> Interface to listen on (default: first "
130 "interface found in the\n"
131 " socket path)\n\n"
132 "%s",
133 commands_help);
134}
135
136
137static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
138{
139 char *cfile;
140 int flen;
141
142 if (ifname == NULL)
143 return NULL;
144
145 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
146 cfile = malloc(flen);
147 if (cfile == NULL)
148 return NULL;
149 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
150
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800151 if (client_socket_dir && client_socket_dir[0] &&
152 access(client_socket_dir, F_OK) < 0) {
153 perror(client_socket_dir);
154 free(cfile);
155 return NULL;
156 }
157
158 ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700159 free(cfile);
160 return ctrl_conn;
161}
162
163
164static void hostapd_cli_close_connection(void)
165{
166 if (ctrl_conn == NULL)
167 return;
168
169 if (hostapd_cli_attached) {
170 wpa_ctrl_detach(ctrl_conn);
171 hostapd_cli_attached = 0;
172 }
173 wpa_ctrl_close(ctrl_conn);
174 ctrl_conn = NULL;
175}
176
177
178static void hostapd_cli_msg_cb(char *msg, size_t len)
179{
180 printf("%s\n", msg);
181}
182
183
184static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
185{
186 char buf[4096];
187 size_t len;
188 int ret;
189
190 if (ctrl_conn == NULL) {
191 printf("Not connected to hostapd - command dropped.\n");
192 return -1;
193 }
194 len = sizeof(buf) - 1;
195 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
196 hostapd_cli_msg_cb);
197 if (ret == -2) {
198 printf("'%s' command timed out.\n", cmd);
199 return -2;
200 } else if (ret < 0) {
201 printf("'%s' command failed.\n", cmd);
202 return -1;
203 }
204 if (print) {
205 buf[len] = '\0';
206 printf("%s", buf);
207 }
208 return 0;
209}
210
211
212static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
213{
214 return _wpa_ctrl_command(ctrl, cmd, 1);
215}
216
217
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800218static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
219 char *argv[])
220{
221 int i, res;
222 char *pos, *end;
223
224 pos = buf;
225 end = buf + buflen;
226
227 res = os_snprintf(pos, end - pos, "%s", cmd);
228 if (os_snprintf_error(end - pos, res))
229 goto fail;
230 pos += res;
231
232 for (i = 0; i < argc; i++) {
233 res = os_snprintf(pos, end - pos, " %s", argv[i]);
234 if (os_snprintf_error(end - pos, res))
235 goto fail;
236 pos += res;
237 }
238
239 buf[buflen - 1] = '\0';
240 return 0;
241
242fail:
243 printf("Too long command\n");
244 return -1;
245}
246
247
248static int hostapd_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd,
249 int min_args, int argc, char *argv[])
250{
251 char buf[4096];
252
253 if (argc < min_args) {
254 printf("Invalid %s command - at least %d argument%s required.\n",
255 cmd, min_args, min_args > 1 ? "s are" : " is");
256 return -1;
257 }
258 if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0)
259 return -1;
260 return wpa_ctrl_command(ctrl, buf);
261}
262
263
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700264static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
265{
266 return wpa_ctrl_command(ctrl, "PING");
267}
268
269
270static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
271{
272 return wpa_ctrl_command(ctrl, "RELOG");
273}
274
275
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800276static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
277{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800278 if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
279 return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800280 return wpa_ctrl_command(ctrl, "STATUS");
281}
282
283
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700284static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
285{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800286 if (argc > 0) {
287 char buf[100];
288 os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]);
289 return wpa_ctrl_command(ctrl, buf);
290 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700291 return wpa_ctrl_command(ctrl, "MIB");
292}
293
294
295static int hostapd_cli_exec(const char *program, const char *arg1,
296 const char *arg2)
297{
Jouni Malinen772e12c2014-10-07 10:29:35 -0700298 char *arg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700299 size_t len;
300 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700301
Jouni Malinen772e12c2014-10-07 10:29:35 -0700302 len = os_strlen(arg1) + os_strlen(arg2) + 2;
303 arg = os_malloc(len);
304 if (arg == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700305 return -1;
Jouni Malinen772e12c2014-10-07 10:29:35 -0700306 os_snprintf(arg, len, "%s %s", arg1, arg2);
307 res = os_exec(program, arg, 1);
308 os_free(arg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700309
Jouni Malinen772e12c2014-10-07 10:29:35 -0700310 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700311}
312
313
314static void hostapd_cli_action_process(char *msg, size_t len)
315{
316 const char *pos;
317
318 pos = msg;
319 if (*pos == '<') {
320 pos = os_strchr(pos, '>');
321 if (pos)
322 pos++;
323 else
324 pos = msg;
325 }
326
327 hostapd_cli_exec(action_file, ctrl_ifname, pos);
328}
329
330
331static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
332{
333 char buf[64];
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800334 if (argc < 1) {
335 printf("Invalid 'sta' command - at least one argument, STA "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700336 "address, is required.\n");
337 return -1;
338 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800339 if (argc > 1)
340 snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]);
341 else
342 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700343 return wpa_ctrl_command(ctrl, buf);
344}
345
346
347static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
348 char *argv[])
349{
350 char buf[64];
351 if (argc != 1) {
352 printf("Invalid 'new_sta' command - exactly one argument, STA "
353 "address, is required.\n");
354 return -1;
355 }
356 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
357 return wpa_ctrl_command(ctrl, buf);
358}
359
360
361static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
362 char *argv[])
363{
364 char buf[64];
365 if (argc < 1) {
366 printf("Invalid 'deauthenticate' command - exactly one "
367 "argument, STA address, is required.\n");
368 return -1;
369 }
370 if (argc > 1)
371 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
372 argv[0], argv[1]);
373 else
374 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
375 return wpa_ctrl_command(ctrl, buf);
376}
377
378
379static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
380 char *argv[])
381{
382 char buf[64];
383 if (argc < 1) {
384 printf("Invalid 'disassociate' command - exactly one "
385 "argument, STA address, is required.\n");
386 return -1;
387 }
388 if (argc > 1)
389 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
390 argv[0], argv[1]);
391 else
392 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
393 return wpa_ctrl_command(ctrl, buf);
394}
395
396
397#ifdef CONFIG_IEEE80211W
398static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
399 char *argv[])
400{
401 char buf[64];
402 if (argc != 1) {
403 printf("Invalid 'sa_query' command - exactly one argument, "
404 "STA address, is required.\n");
405 return -1;
406 }
407 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
408 return wpa_ctrl_command(ctrl, buf);
409}
410#endif /* CONFIG_IEEE80211W */
411
412
413#ifdef CONFIG_WPS
414static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
415 char *argv[])
416{
417 char buf[256];
418 if (argc < 2) {
419 printf("Invalid 'wps_pin' command - at least two arguments, "
420 "UUID and PIN, are required.\n");
421 return -1;
422 }
423 if (argc > 3)
424 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
425 argv[0], argv[1], argv[2], argv[3]);
426 else if (argc > 2)
427 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
428 argv[0], argv[1], argv[2]);
429 else
430 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
431 return wpa_ctrl_command(ctrl, buf);
432}
433
434
435static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
436 char *argv[])
437{
438 char cmd[256];
439 int res;
440
441 if (argc != 1 && argc != 2) {
442 printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
443 "- PIN to be verified\n");
444 return -1;
445 }
446
447 if (argc == 2)
448 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
449 argv[0], argv[1]);
450 else
451 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
452 argv[0]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800453 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700454 printf("Too long WPS_CHECK_PIN command.\n");
455 return -1;
456 }
457 return wpa_ctrl_command(ctrl, cmd);
458}
459
460
461static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
462 char *argv[])
463{
464 return wpa_ctrl_command(ctrl, "WPS_PBC");
465}
466
467
Dmitry Shmidt04949592012-07-19 12:16:46 -0700468static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
469 char *argv[])
470{
471 return wpa_ctrl_command(ctrl, "WPS_CANCEL");
472}
473
474
Dmitry Shmidt04949592012-07-19 12:16:46 -0700475#ifdef CONFIG_WPS_NFC
476static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
477 char *argv[])
478{
479 int ret;
480 char *buf;
481 size_t buflen;
482
483 if (argc != 1) {
484 printf("Invalid 'wps_nfc_tag_read' command - one argument "
485 "is required.\n");
486 return -1;
487 }
488
489 buflen = 18 + os_strlen(argv[0]);
490 buf = os_malloc(buflen);
491 if (buf == NULL)
492 return -1;
493 os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
494
495 ret = wpa_ctrl_command(ctrl, buf);
496 os_free(buf);
497
498 return ret;
499}
500
501
502static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
503 int argc, char *argv[])
504{
505 char cmd[64];
506 int res;
507
508 if (argc != 1) {
509 printf("Invalid 'wps_nfc_config_token' command - one argument "
510 "is required.\n");
511 return -1;
512 }
513
514 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
515 argv[0]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800516 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700517 printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
518 return -1;
519 }
520 return wpa_ctrl_command(ctrl, cmd);
521}
522
523
524static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
525 int argc, char *argv[])
526{
527 char cmd[64];
528 int res;
529
530 if (argc != 1) {
531 printf("Invalid 'wps_nfc_token' command - one argument is "
532 "required.\n");
533 return -1;
534 }
535
536 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800537 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700538 printf("Too long WPS_NFC_TOKEN command.\n");
539 return -1;
540 }
541 return wpa_ctrl_command(ctrl, cmd);
542}
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800543
544
545static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
546 int argc, char *argv[])
547{
548 char cmd[64];
549 int res;
550
551 if (argc != 2) {
552 printf("Invalid 'nfc_get_handover_sel' command - two arguments "
553 "are required.\n");
554 return -1;
555 }
556
557 res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
558 argv[0], argv[1]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800559 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800560 printf("Too long NFC_GET_HANDOVER_SEL command.\n");
561 return -1;
562 }
563 return wpa_ctrl_command(ctrl, cmd);
564}
565
Dmitry Shmidt04949592012-07-19 12:16:46 -0700566#endif /* CONFIG_WPS_NFC */
567
568
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700569static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
570 char *argv[])
571{
572 char buf[64];
573 if (argc < 1) {
574 printf("Invalid 'wps_ap_pin' command - at least one argument "
575 "is required.\n");
576 return -1;
577 }
578 if (argc > 2)
579 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
580 argv[0], argv[1], argv[2]);
581 else if (argc > 1)
582 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
583 argv[0], argv[1]);
584 else
585 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
586 return wpa_ctrl_command(ctrl, buf);
587}
588
589
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700590static int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc,
591 char *argv[])
592{
593 return wpa_ctrl_command(ctrl, "WPS_GET_STATUS");
594}
595
596
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700597static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
598 char *argv[])
599{
600 char buf[256];
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700601 char ssid_hex[2 * SSID_MAX_LEN + 1];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700602 char key_hex[2 * 64 + 1];
603 int i;
604
605 if (argc < 1) {
606 printf("Invalid 'wps_config' command - at least two arguments "
607 "are required.\n");
608 return -1;
609 }
610
611 ssid_hex[0] = '\0';
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700612 for (i = 0; i < SSID_MAX_LEN; i++) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700613 if (argv[0][i] == '\0')
614 break;
615 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
616 }
617
618 key_hex[0] = '\0';
619 if (argc > 3) {
620 for (i = 0; i < 64; i++) {
621 if (argv[3][i] == '\0')
622 break;
623 os_snprintf(&key_hex[i * 2], 3, "%02x",
624 argv[3][i]);
625 }
626 }
627
628 if (argc > 3)
629 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
630 ssid_hex, argv[1], argv[2], key_hex);
631 else if (argc > 2)
632 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
633 ssid_hex, argv[1], argv[2]);
634 else
635 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
636 ssid_hex, argv[1]);
637 return wpa_ctrl_command(ctrl, buf);
638}
639#endif /* CONFIG_WPS */
640
641
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800642static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
643 char *argv[])
644{
645 char buf[300];
646 int res;
647
648 if (argc < 2) {
649 printf("Invalid 'disassoc_imminent' command - two arguments "
650 "(STA addr and Disassociation Timer) are needed\n");
651 return -1;
652 }
653
654 res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
655 argv[0], argv[1]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800656 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800657 return -1;
658 return wpa_ctrl_command(ctrl, buf);
659}
660
661
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800662static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
663 char *argv[])
664{
665 char buf[300];
666 int res;
667
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700668 if (argc < 3) {
669 printf("Invalid 'ess_disassoc' command - three arguments (STA "
670 "addr, disassoc timer, and URL) are needed\n");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800671 return -1;
672 }
673
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700674 res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
675 argv[0], argv[1], argv[2]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800676 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800677 return -1;
678 return wpa_ctrl_command(ctrl, buf);
679}
680
681
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800682static int hostapd_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc,
683 char *argv[])
684{
685 char buf[2000], *tmp;
686 int res, i, total;
687
688 if (argc < 1) {
689 printf("Invalid 'bss_tm_req' command - at least one argument (STA addr) is needed\n");
690 return -1;
691 }
692
693 res = os_snprintf(buf, sizeof(buf), "BSS_TM_REQ %s", argv[0]);
694 if (os_snprintf_error(sizeof(buf), res))
695 return -1;
696
697 total = res;
698 for (i = 1; i < argc; i++) {
699 tmp = &buf[total];
700 res = os_snprintf(tmp, sizeof(buf) - total, " %s", argv[i]);
701 if (os_snprintf_error(sizeof(buf) - total, res))
702 return -1;
703 total += res;
704 }
705 return wpa_ctrl_command(ctrl, buf);
706}
707
708
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700709static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
710 char *argv[])
711{
712 return wpa_ctrl_command(ctrl, "GET_CONFIG");
713}
714
715
716static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
717 char *addr, size_t addr_len)
718{
719 char buf[4096], *pos;
720 size_t len;
721 int ret;
722
723 if (ctrl_conn == NULL) {
724 printf("Not connected to hostapd - command dropped.\n");
725 return -1;
726 }
727 len = sizeof(buf) - 1;
728 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
729 hostapd_cli_msg_cb);
730 if (ret == -2) {
731 printf("'%s' command timed out.\n", cmd);
732 return -2;
733 } else if (ret < 0) {
734 printf("'%s' command failed.\n", cmd);
735 return -1;
736 }
737
738 buf[len] = '\0';
739 if (memcmp(buf, "FAIL", 4) == 0)
740 return -1;
741 printf("%s", buf);
742
743 pos = buf;
744 while (*pos != '\0' && *pos != '\n')
745 pos++;
746 *pos = '\0';
747 os_strlcpy(addr, buf, addr_len);
748 return 0;
749}
750
751
752static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
753 char *argv[])
754{
755 char addr[32], cmd[64];
756
757 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
758 return 0;
759 do {
760 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
761 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
762
763 return -1;
764}
765
766
767static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
768{
769 printf("%s", commands_help);
770 return 0;
771}
772
773
774static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
775 char *argv[])
776{
777 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
778 return 0;
779}
780
781
Dmitry Shmidt051af732013-10-22 13:52:46 -0700782static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl,
783 int argc, char *argv[])
784{
785 char buf[200];
786 int res;
787
788 if (argc != 1) {
789 printf("Invalid 'set_qos_map_set' command - "
790 "one argument (comma delimited QoS map set) "
791 "is needed\n");
792 return -1;
793 }
794
795 res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800796 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidt051af732013-10-22 13:52:46 -0700797 return -1;
798 return wpa_ctrl_command(ctrl, buf);
799}
800
801
802static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
803 int argc, char *argv[])
804{
805 char buf[50];
806 int res;
807
808 if (argc != 1) {
809 printf("Invalid 'send_qos_map_conf' command - "
810 "one argument (STA addr) is needed\n");
811 return -1;
812 }
813
814 res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800815 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidt051af732013-10-22 13:52:46 -0700816 return -1;
817 return wpa_ctrl_command(ctrl, buf);
818}
819
820
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800821static int hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc,
822 char *argv[])
823{
824 char buf[300];
825 int res;
826
827 if (argc < 2) {
828 printf("Invalid 'hs20_wnm_notif' command - two arguments (STA "
829 "addr and URL) are needed\n");
830 return -1;
831 }
832
833 res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s",
834 argv[0], argv[1]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800835 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800836 return -1;
837 return wpa_ctrl_command(ctrl, buf);
838}
839
840
841static int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc,
842 char *argv[])
843{
844 char buf[300];
845 int res;
846
847 if (argc < 3) {
848 printf("Invalid 'hs20_deauth_req' command - at least three arguments (STA addr, Code, Re-auth Delay) are needed\n");
849 return -1;
850 }
851
852 if (argc > 3)
853 res = os_snprintf(buf, sizeof(buf),
854 "HS20_DEAUTH_REQ %s %s %s %s",
855 argv[0], argv[1], argv[2], argv[3]);
856 else
857 res = os_snprintf(buf, sizeof(buf),
858 "HS20_DEAUTH_REQ %s %s %s",
859 argv[0], argv[1], argv[2]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800860 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800861 return -1;
862 return wpa_ctrl_command(ctrl, buf);
863}
864
865
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700866static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
867{
868 hostapd_cli_quit = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800869 if (interactive)
870 eloop_terminate();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700871 return 0;
872}
873
874
875static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
876{
877 char cmd[256];
878 if (argc != 1) {
879 printf("Invalid LEVEL command: needs one argument (debug "
880 "level)\n");
881 return 0;
882 }
883 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
884 return wpa_ctrl_command(ctrl, cmd);
885}
886
887
888static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
889{
890 struct dirent *dent;
891 DIR *dir;
892
893 dir = opendir(ctrl_iface_dir);
894 if (dir == NULL) {
895 printf("Control interface directory '%s' could not be "
896 "openned.\n", ctrl_iface_dir);
897 return;
898 }
899
900 printf("Available interfaces:\n");
901 while ((dent = readdir(dir))) {
902 if (strcmp(dent->d_name, ".") == 0 ||
903 strcmp(dent->d_name, "..") == 0)
904 continue;
905 printf("%s\n", dent->d_name);
906 }
907 closedir(dir);
908}
909
910
911static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
912 char *argv[])
913{
914 if (argc < 1) {
915 hostapd_cli_list_interfaces(ctrl);
916 return 0;
917 }
918
919 hostapd_cli_close_connection();
Dmitry Shmidt71757432014-06-02 13:50:35 -0700920 os_free(ctrl_ifname);
921 ctrl_ifname = os_strdup(argv[0]);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -0700922 if (ctrl_ifname == NULL)
923 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700924
925 if (hostapd_cli_open_connection(ctrl_ifname)) {
926 printf("Connected to interface '%s.\n", ctrl_ifname);
927 if (wpa_ctrl_attach(ctrl_conn) == 0) {
928 hostapd_cli_attached = 1;
929 } else {
930 printf("Warning: Failed to attach to "
931 "hostapd.\n");
932 }
933 } else {
934 printf("Could not connect to interface '%s' - re-trying\n",
935 ctrl_ifname);
936 }
937 return 0;
938}
939
940
941static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
942{
943 char cmd[256];
944 int res;
945
946 if (argc != 2) {
947 printf("Invalid SET command: needs two arguments (variable "
948 "name and value)\n");
949 return -1;
950 }
951
952 res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800953 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700954 printf("Too long SET command.\n");
955 return -1;
956 }
957 return wpa_ctrl_command(ctrl, cmd);
958}
959
960
961static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
962{
963 char cmd[256];
964 int res;
965
966 if (argc != 1) {
967 printf("Invalid GET command: needs one argument (variable "
968 "name)\n");
969 return -1;
970 }
971
972 res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800973 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700974 printf("Too long GET command.\n");
975 return -1;
976 }
977 return wpa_ctrl_command(ctrl, cmd);
978}
979
980
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800981#ifdef CONFIG_FST
982static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[])
983{
984 char cmd[256];
985 int res;
986 int i;
987 int total;
988
989 if (argc <= 0) {
990 printf("FST command: parameters are required.\n");
991 return -1;
992 }
993
994 total = os_snprintf(cmd, sizeof(cmd), "FST-MANAGER");
995
996 for (i = 0; i < argc; i++) {
997 res = os_snprintf(cmd + total, sizeof(cmd) - total, " %s",
998 argv[i]);
999 if (os_snprintf_error(sizeof(cmd) - total, res)) {
1000 printf("Too long fst command.\n");
1001 return -1;
1002 }
1003 total += res;
1004 }
1005 return wpa_ctrl_command(ctrl, cmd);
1006}
1007#endif /* CONFIG_FST */
1008
1009
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001010static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
1011 int argc, char *argv[])
1012{
1013 char cmd[256];
1014 int res;
1015 int i;
1016 char *tmp;
1017 int total;
1018
1019 if (argc < 2) {
1020 printf("Invalid chan_switch command: needs at least two "
1021 "arguments (count and freq)\n"
1022 "usage: <cs_count> <freq> [sec_channel_offset=] "
1023 "[center_freq1=] [center_freq2=] [bandwidth=] "
1024 "[blocktx] [ht|vht]\n");
1025 return -1;
1026 }
1027
1028 res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
1029 argv[0], argv[1]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001030 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001031 printf("Too long CHAN_SWITCH command.\n");
1032 return -1;
1033 }
1034
1035 total = res;
1036 for (i = 2; i < argc; i++) {
1037 tmp = cmd + total;
1038 res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001039 if (os_snprintf_error(sizeof(cmd) - total, res)) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001040 printf("Too long CHAN_SWITCH command.\n");
1041 return -1;
1042 }
1043 total += res;
1044 }
1045 return wpa_ctrl_command(ctrl, cmd);
1046}
1047
1048
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001049static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc,
1050 char *argv[])
1051{
1052 return wpa_ctrl_command(ctrl, "ENABLE");
1053}
1054
1055
1056static int hostapd_cli_cmd_reload(struct wpa_ctrl *ctrl, int argc,
1057 char *argv[])
1058{
1059 return wpa_ctrl_command(ctrl, "RELOAD");
1060}
1061
1062
1063static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc,
1064 char *argv[])
1065{
1066 return wpa_ctrl_command(ctrl, "DISABLE");
1067}
1068
1069
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001070static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
1071{
1072 char cmd[256];
1073 int res;
1074
1075 if (argc < 2 || argc > 3) {
1076 printf("Invalid vendor command\n"
1077 "usage: <vendor id> <command id> [<hex formatted command argument>]\n");
1078 return -1;
1079 }
1080
1081 res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
1082 argc == 3 ? argv[2] : "");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001083 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001084 printf("Too long VENDOR command.\n");
1085 return -1;
1086 }
1087 return wpa_ctrl_command(ctrl, cmd);
1088}
1089
1090
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001091static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc,
1092 char *argv[])
1093{
1094 return wpa_ctrl_command(ctrl, "ERP_FLUSH");
1095}
1096
1097
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001098static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc,
1099 char *argv[])
1100{
1101 char cmd[256];
1102 int res;
1103
1104 res = os_snprintf(cmd, sizeof(cmd), "LOG_LEVEL%s%s%s%s",
1105 argc >= 1 ? " " : "",
1106 argc >= 1 ? argv[0] : "",
1107 argc == 2 ? " " : "",
1108 argc == 2 ? argv[1] : "");
1109 if (os_snprintf_error(sizeof(cmd), res)) {
1110 printf("Too long option\n");
1111 return -1;
1112 }
1113 return wpa_ctrl_command(ctrl, cmd);
1114}
1115
1116
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001117static int hostapd_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
1118{
1119 if (argc == 0)
1120 return -1;
1121 return hostapd_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]);
1122}
1123
1124
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001125struct hostapd_cli_cmd {
1126 const char *cmd;
1127 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
1128};
1129
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07001130static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001131 { "ping", hostapd_cli_cmd_ping },
1132 { "mib", hostapd_cli_cmd_mib },
1133 { "relog", hostapd_cli_cmd_relog },
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001134 { "status", hostapd_cli_cmd_status },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001135 { "sta", hostapd_cli_cmd_sta },
1136 { "all_sta", hostapd_cli_cmd_all_sta },
1137 { "new_sta", hostapd_cli_cmd_new_sta },
1138 { "deauthenticate", hostapd_cli_cmd_deauthenticate },
1139 { "disassociate", hostapd_cli_cmd_disassociate },
1140#ifdef CONFIG_IEEE80211W
1141 { "sa_query", hostapd_cli_cmd_sa_query },
1142#endif /* CONFIG_IEEE80211W */
1143#ifdef CONFIG_WPS
1144 { "wps_pin", hostapd_cli_cmd_wps_pin },
1145 { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
1146 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
Dmitry Shmidt04949592012-07-19 12:16:46 -07001147 { "wps_cancel", hostapd_cli_cmd_wps_cancel },
Dmitry Shmidt04949592012-07-19 12:16:46 -07001148#ifdef CONFIG_WPS_NFC
1149 { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
1150 { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
1151 { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001152 { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
Dmitry Shmidt04949592012-07-19 12:16:46 -07001153#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001154 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
1155 { "wps_config", hostapd_cli_cmd_wps_config },
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07001156 { "wps_get_status", hostapd_cli_cmd_wps_get_status },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001157#endif /* CONFIG_WPS */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001158 { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001159 { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001160 { "bss_tm_req", hostapd_cli_cmd_bss_tm_req },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001161 { "get_config", hostapd_cli_cmd_get_config },
1162 { "help", hostapd_cli_cmd_help },
1163 { "interface", hostapd_cli_cmd_interface },
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001164#ifdef CONFIG_FST
1165 { "fst", hostapd_cli_cmd_fst },
1166#endif /* CONFIG_FST */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001167 { "raw", hostapd_cli_cmd_raw },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001168 { "level", hostapd_cli_cmd_level },
1169 { "license", hostapd_cli_cmd_license },
1170 { "quit", hostapd_cli_cmd_quit },
1171 { "set", hostapd_cli_cmd_set },
1172 { "get", hostapd_cli_cmd_get },
Dmitry Shmidt051af732013-10-22 13:52:46 -07001173 { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
1174 { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001175 { "chan_switch", hostapd_cli_cmd_chan_switch },
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001176 { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif },
1177 { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req },
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001178 { "vendor", hostapd_cli_cmd_vendor },
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001179 { "enable", hostapd_cli_cmd_enable },
1180 { "reload", hostapd_cli_cmd_reload },
1181 { "disable", hostapd_cli_cmd_disable },
1182 { "erp_flush", hostapd_cli_cmd_erp_flush },
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001183 { "log_level", hostapd_cli_cmd_log_level },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001184 { NULL, NULL }
1185};
1186
1187
1188static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
1189{
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07001190 const struct hostapd_cli_cmd *cmd, *match = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001191 int count;
1192
1193 count = 0;
1194 cmd = hostapd_cli_commands;
1195 while (cmd->cmd) {
1196 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
1197 match = cmd;
1198 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1199 /* we have an exact match */
1200 count = 1;
1201 break;
1202 }
1203 count++;
1204 }
1205 cmd++;
1206 }
1207
1208 if (count > 1) {
1209 printf("Ambiguous command '%s'; possible commands:", argv[0]);
1210 cmd = hostapd_cli_commands;
1211 while (cmd->cmd) {
1212 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
1213 0) {
1214 printf(" %s", cmd->cmd);
1215 }
1216 cmd++;
1217 }
1218 printf("\n");
1219 } else if (count == 0) {
1220 printf("Unknown command '%s'\n", argv[0]);
1221 } else {
1222 match->handler(ctrl, argc - 1, &argv[1]);
1223 }
1224}
1225
1226
1227static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
1228 int action_monitor)
1229{
1230 int first = 1;
1231 if (ctrl_conn == NULL)
1232 return;
1233 while (wpa_ctrl_pending(ctrl)) {
1234 char buf[256];
1235 size_t len = sizeof(buf) - 1;
1236 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
1237 buf[len] = '\0';
1238 if (action_monitor)
1239 hostapd_cli_action_process(buf, len);
1240 else {
1241 if (in_read && first)
1242 printf("\n");
1243 first = 0;
1244 printf("%s\n", buf);
1245 }
1246 } else {
1247 printf("Could not read pending message.\n");
1248 break;
1249 }
1250 }
1251}
1252
1253
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001254#define max_args 10
1255
1256static int tokenize_cmd(char *cmd, char *argv[])
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001257{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001258 char *pos;
1259 int argc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001260
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001261 pos = cmd;
1262 for (;;) {
1263 while (*pos == ' ')
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001264 pos++;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001265 if (*pos == '\0')
1266 break;
1267 argv[argc] = pos;
1268 argc++;
1269 if (argc == max_args)
1270 break;
1271 if (*pos == '"') {
1272 char *pos2 = os_strrchr(pos, '"');
1273 if (pos2)
1274 pos = pos2 + 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001275 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001276 while (*pos != '\0' && *pos != ' ')
1277 pos++;
1278 if (*pos == ' ')
1279 *pos++ = '\0';
1280 }
1281
1282 return argc;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001283}
1284
1285
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001286static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001287{
1288 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
1289 printf("Connection to hostapd lost - trying to reconnect\n");
1290 hostapd_cli_close_connection();
1291 }
1292 if (!ctrl_conn) {
1293 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1294 if (ctrl_conn) {
1295 printf("Connection to hostapd re-established\n");
1296 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1297 hostapd_cli_attached = 1;
1298 } else {
1299 printf("Warning: Failed to attach to "
1300 "hostapd.\n");
1301 }
1302 }
1303 }
1304 if (ctrl_conn)
1305 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001306 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1307}
1308
1309
1310static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
1311{
1312 eloop_terminate();
1313}
1314
1315
1316static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
1317{
1318 char *argv[max_args];
1319 int argc;
1320 argc = tokenize_cmd(cmd, argv);
1321 if (argc)
1322 wpa_request(ctrl_conn, argc, argv);
1323}
1324
1325
1326static void hostapd_cli_edit_eof_cb(void *ctx)
1327{
1328 eloop_terminate();
1329}
1330
1331
1332static void hostapd_cli_interactive(void)
1333{
1334 printf("\nInteractive mode\n\n");
1335
1336 eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
1337 edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001338 NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001339 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1340
1341 eloop_run();
1342
1343 edit_deinit(NULL, NULL);
1344 eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
1345}
1346
1347
1348static void hostapd_cli_cleanup(void)
1349{
1350 hostapd_cli_close_connection();
1351 if (pid_file)
1352 os_daemonize_terminate(pid_file);
1353
1354 os_program_deinit();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001355}
1356
1357
1358static void hostapd_cli_action(struct wpa_ctrl *ctrl)
1359{
1360 fd_set rfds;
1361 int fd, res;
1362 struct timeval tv;
1363 char buf[256];
1364 size_t len;
1365
1366 fd = wpa_ctrl_get_fd(ctrl);
1367
1368 while (!hostapd_cli_quit) {
1369 FD_ZERO(&rfds);
1370 FD_SET(fd, &rfds);
1371 tv.tv_sec = ping_interval;
1372 tv.tv_usec = 0;
1373 res = select(fd + 1, &rfds, NULL, NULL, &tv);
1374 if (res < 0 && errno != EINTR) {
1375 perror("select");
1376 break;
1377 }
1378
1379 if (FD_ISSET(fd, &rfds))
1380 hostapd_cli_recv_pending(ctrl, 0, 1);
1381 else {
1382 len = sizeof(buf) - 1;
1383 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1384 hostapd_cli_action_process) < 0 ||
1385 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
1386 printf("hostapd did not reply to PING "
1387 "command - exiting\n");
1388 break;
1389 }
1390 }
1391 }
1392}
1393
1394
1395int main(int argc, char *argv[])
1396{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001397 int warning_displayed = 0;
1398 int c;
1399 int daemonize = 0;
1400
1401 if (os_program_init())
1402 return -1;
1403
1404 for (;;) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001405 c = getopt(argc, argv, "a:BhG:i:p:P:s:v");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001406 if (c < 0)
1407 break;
1408 switch (c) {
1409 case 'a':
1410 action_file = optarg;
1411 break;
1412 case 'B':
1413 daemonize = 1;
1414 break;
1415 case 'G':
1416 ping_interval = atoi(optarg);
1417 break;
1418 case 'h':
1419 usage();
1420 return 0;
1421 case 'v':
1422 printf("%s\n", hostapd_cli_version);
1423 return 0;
1424 case 'i':
1425 os_free(ctrl_ifname);
1426 ctrl_ifname = os_strdup(optarg);
1427 break;
1428 case 'p':
1429 ctrl_iface_dir = optarg;
1430 break;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001431 case 'P':
1432 pid_file = optarg;
1433 break;
1434 case 's':
1435 client_socket_dir = optarg;
1436 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001437 default:
1438 usage();
1439 return -1;
1440 }
1441 }
1442
1443 interactive = (argc == optind) && (action_file == NULL);
1444
1445 if (interactive) {
1446 printf("%s\n\n%s\n\n", hostapd_cli_version,
1447 hostapd_cli_license);
1448 }
1449
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001450 if (eloop_init())
1451 return -1;
1452
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001453 for (;;) {
1454 if (ctrl_ifname == NULL) {
1455 struct dirent *dent;
1456 DIR *dir = opendir(ctrl_iface_dir);
1457 if (dir) {
1458 while ((dent = readdir(dir))) {
1459 if (os_strcmp(dent->d_name, ".") == 0
1460 ||
1461 os_strcmp(dent->d_name, "..") == 0)
1462 continue;
1463 printf("Selected interface '%s'\n",
1464 dent->d_name);
1465 ctrl_ifname = os_strdup(dent->d_name);
1466 break;
1467 }
1468 closedir(dir);
1469 }
1470 }
1471 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1472 if (ctrl_conn) {
1473 if (warning_displayed)
1474 printf("Connection established.\n");
1475 break;
1476 }
1477
1478 if (!interactive) {
1479 perror("Failed to connect to hostapd - "
1480 "wpa_ctrl_open");
1481 return -1;
1482 }
1483
1484 if (!warning_displayed) {
1485 printf("Could not connect to hostapd - re-trying\n");
1486 warning_displayed = 1;
1487 }
1488 os_sleep(1, 0);
1489 continue;
1490 }
1491
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001492 if (interactive || action_file) {
1493 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1494 hostapd_cli_attached = 1;
1495 } else {
1496 printf("Warning: Failed to attach to hostapd.\n");
1497 if (action_file)
1498 return -1;
1499 }
1500 }
1501
Dmitry Shmidtb97e4282016-02-08 10:16:07 -08001502 if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001503 return -1;
1504
1505 if (interactive)
1506 hostapd_cli_interactive();
1507 else if (action_file)
1508 hostapd_cli_action(ctrl_conn);
1509 else
1510 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1511
1512 os_free(ctrl_ifname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001513 eloop_destroy();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001514 hostapd_cli_cleanup();
1515 return 0;
1516}