blob: fc8a72e385e90eba977d85a99273fefe9c553e39 [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
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -080019#ifndef CONFIG_NO_CTRL_IFACE
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070020
Dmitry Shmidt1d755d02015-04-28 10:34:29 -070021static const char *const hostapd_cli_version =
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070022"hostapd_cli v" VERSION_STR "\n"
Dmitry Shmidtde47be72016-01-07 12:52:55 -080023"Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070024
25
Dmitry Shmidt1d755d02015-04-28 10:34:29 -070026static const char *const hostapd_cli_license =
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -080027"This software may be distributed under the terms of the BSD license.\n"
28"See README for more details.\n";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070029
Dmitry Shmidt1d755d02015-04-28 10:34:29 -070030static const char *const hostapd_cli_full_license =
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -080031"This software may be distributed under the terms of the BSD license.\n"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070032"\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
Dmitry Shmidt1d755d02015-04-28 10:34:29 -070061static const char *const commands_help =
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070062"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"
67" deauthenticate <addr> deauthenticate a station\n"
68" disassociate <addr> disassociate a station\n"
69#ifdef CONFIG_IEEE80211W
70" sa_query <addr> send SA Query to a station\n"
71#endif /* CONFIG_IEEE80211W */
72#ifdef CONFIG_WPS
73" wps_pin <uuid> <pin> [timeout] [addr] add WPS Enrollee PIN\n"
74" wps_check_pin <PIN> verify PIN checksum\n"
75" wps_pbc indicate button pushed to initiate PBC\n"
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070076" wps_cancel cancel the pending WPS operation\n"
Dmitry Shmidt04949592012-07-19 12:16:46 -070077#ifdef CONFIG_WPS_NFC
78" wps_nfc_tag_read <hexdump> report read NFC tag with WPS data\n"
79" wps_nfc_config_token <WPS/NDEF> build NFC configuration token\n"
80" wps_nfc_token <WPS/NDEF/enable/disable> manager NFC password token\n"
81#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070082" wps_ap_pin <cmd> [params..] enable/disable AP PIN\n"
83" wps_config <SSID> <auth> <encr> <key> configure AP\n"
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070084" wps_get_status show current WPS status\n"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070085#endif /* CONFIG_WPS */
86" get_config show current configuration\n"
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;
Jeff Johnson205f2142012-09-03 22:12:17 -070096
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;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800101static const char *client_socket_dir = NULL;
Jeff Johnson205f2142012-09-03 22:12:17 -0700102
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700103static char *ctrl_ifname = NULL;
104static const char *pid_file = NULL;
105static const char *action_file = NULL;
106static int ping_interval = 5;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800107static int interactive = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700108
109
110static void usage(void)
111{
112 fprintf(stderr, "%s\n", hostapd_cli_version);
113 fprintf(stderr,
114 "\n"
115 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
116 "[-a<path>] \\\n"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800117 " [-P<pid file>] [-G<ping interval>] [command..]\n"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700118 "\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"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800124 " -s<dir_path> dir path to open client sockets (default: "
125 CONFIG_CTRL_IFACE_DIR ")\n"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700126 " -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"
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{
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -0800140#ifndef CONFIG_CTRL_IFACE_UDP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700141 char *cfile;
142 int flen;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -0800143#endif /* !CONFIG_CTRL_IFACE_UDP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700144
145 if (ifname == NULL)
146 return NULL;
147
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -0800148#ifdef CONFIG_CTRL_IFACE_UDP
149 ctrl_conn = wpa_ctrl_open(ifname);
150 return ctrl_conn;
151#else /* CONFIG_CTRL_IFACE_UDP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700152 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
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800158 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);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700166 free(cfile);
167 return ctrl_conn;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -0800168#endif /* CONFIG_CTRL_IFACE_UDP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700169}
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
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800226static 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
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700272static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
273{
274 return wpa_ctrl_command(ctrl, "PING");
275}
276
277
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
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800284static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
285{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800286 if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
287 return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800288 return wpa_ctrl_command(ctrl, "STATUS");
289}
290
291
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700292static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
293{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800294 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 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700299 return wpa_ctrl_command(ctrl, "MIB");
300}
301
302
303static int hostapd_cli_exec(const char *program, const char *arg1,
304 const char *arg2)
305{
Jouni Malinen772e12c2014-10-07 10:29:35 -0700306 char *arg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700307 size_t len;
308 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700309
Jouni Malinen772e12c2014-10-07 10:29:35 -0700310 len = os_strlen(arg1) + os_strlen(arg2) + 2;
311 arg = os_malloc(len);
312 if (arg == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700313 return -1;
Jouni Malinen772e12c2014-10-07 10:29:35 -0700314 os_snprintf(arg, len, "%s %s", arg1, arg2);
315 res = os_exec(program, arg, 1);
316 os_free(arg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700317
Jouni Malinen772e12c2014-10-07 10:29:35 -0700318 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700319}
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
339static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
340{
341 char buf[64];
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800342 if (argc < 1) {
343 printf("Invalid 'sta' command - at least one argument, STA "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700344 "address, is required.\n");
345 return -1;
346 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800347 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]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700351 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
369static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
370 char *argv[])
371{
372 char buf[64];
373 if (argc < 1) {
374 printf("Invalid 'deauthenticate' command - exactly one "
375 "argument, STA address, is required.\n");
376 return -1;
377 }
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]);
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];
391 if (argc < 1) {
392 printf("Invalid 'disassociate' command - exactly one "
393 "argument, STA address, is required.\n");
394 return -1;
395 }
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]);
401 return wpa_ctrl_command(ctrl, buf);
402}
403
404
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
421#ifdef CONFIG_WPS
422static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
423 char *argv[])
424{
425 char buf[256];
426 if (argc < 2) {
427 printf("Invalid 'wps_pin' command - at least two arguments, "
428 "UUID and PIN, are required.\n");
429 return -1;
430 }
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)
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]);
439 return wpa_ctrl_command(ctrl, buf);
440}
441
442
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]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800461 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700462 printf("Too long WPS_CHECK_PIN command.\n");
463 return -1;
464 }
465 return wpa_ctrl_command(ctrl, cmd);
466}
467
468
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}
474
475
Dmitry Shmidt04949592012-07-19 12:16:46 -0700476static 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
Dmitry Shmidt04949592012-07-19 12:16:46 -0700483#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}
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]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800524 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700525 printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
526 return -1;
527 }
528 return wpa_ctrl_command(ctrl, cmd);
529}
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]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800545 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700546 printf("Too long WPS_NFC_TOKEN command.\n");
547 return -1;
548 }
549 return wpa_ctrl_command(ctrl, cmd);
550}
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800551
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]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800567 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800568 printf("Too long NFC_GET_HANDOVER_SEL command.\n");
569 return -1;
570 }
571 return wpa_ctrl_command(ctrl, cmd);
572}
573
Dmitry Shmidt04949592012-07-19 12:16:46 -0700574#endif /* CONFIG_WPS_NFC */
575
576
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700577static 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}
596
597
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700598static 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
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700605static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
606 char *argv[])
607{
608 char buf[256];
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700609 char ssid_hex[2 * SSID_MAX_LEN + 1];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700610 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';
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700620 for (i = 0; i < SSID_MAX_LEN; i++) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700621 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}
647#endif /* CONFIG_WPS */
648
649
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800650static 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]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800664 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800665 return -1;
666 return wpa_ctrl_command(ctrl, buf);
667}
668
669
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800670static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
671 char *argv[])
672{
673 char buf[300];
674 int res;
675
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700676 if (argc < 3) {
677 printf("Invalid 'ess_disassoc' command - three arguments (STA "
678 "addr, disassoc timer, and URL) are needed\n");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800679 return -1;
680 }
681
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700682 res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
683 argv[0], argv[1], argv[2]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800684 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800685 return -1;
686 return wpa_ctrl_command(ctrl, buf);
687}
688
689
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800690static 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]);
702 if (os_snprintf_error(sizeof(buf), res))
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]);
709 if (os_snprintf_error(sizeof(buf) - total, res))
710 return -1;
711 total += res;
712 }
713 return wpa_ctrl_command(ctrl, buf);
714}
715
716
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700717static 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
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
Dmitry Shmidt051af732013-10-22 13:52:46 -0700790static 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]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800804 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidt051af732013-10-22 13:52:46 -0700805 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]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800823 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidt051af732013-10-22 13:52:46 -0700824 return -1;
825 return wpa_ctrl_command(ctrl, buf);
826}
827
828
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800829static 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]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800843 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800844 return -1;
845 return wpa_ctrl_command(ctrl, buf);
846}
847
848
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]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800868 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800869 return -1;
870 return wpa_ctrl_command(ctrl, buf);
871}
872
873
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700874static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
875{
876 hostapd_cli_quit = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800877 if (interactive)
878 eloop_terminate();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700879 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();
Dmitry Shmidt71757432014-06-02 13:50:35 -0700928 os_free(ctrl_ifname);
929 ctrl_ifname = os_strdup(argv[0]);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -0700930 if (ctrl_ifname == NULL)
931 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700932
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
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]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800961 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700962 printf("Too long SET command.\n");
963 return -1;
964 }
965 return wpa_ctrl_command(ctrl, cmd);
966}
967
968
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]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800981 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700982 printf("Too long GET command.\n");
983 return -1;
984 }
985 return wpa_ctrl_command(ctrl, cmd);
986}
987
988
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800989#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
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001018static 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]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001038 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001039 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]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001047 if (os_snprintf_error(sizeof(cmd) - total, res)) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001048 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
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001057static 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
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001078static 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] : "");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001091 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001092 printf("Too long VENDOR command.\n");
1093 return -1;
1094 }
1095 return wpa_ctrl_command(ctrl, cmd);
1096}
1097
1098
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001099static 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
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001106static 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
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001125static 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
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001133struct hostapd_cli_cmd {
1134 const char *cmd;
1135 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
1136};
1137
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07001138static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001139 { "ping", hostapd_cli_cmd_ping },
1140 { "mib", hostapd_cli_cmd_mib },
1141 { "relog", hostapd_cli_cmd_relog },
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001142 { "status", hostapd_cli_cmd_status },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001143 { "sta", hostapd_cli_cmd_sta },
1144 { "all_sta", hostapd_cli_cmd_all_sta },
1145 { "new_sta", hostapd_cli_cmd_new_sta },
1146 { "deauthenticate", hostapd_cli_cmd_deauthenticate },
1147 { "disassociate", hostapd_cli_cmd_disassociate },
1148#ifdef CONFIG_IEEE80211W
1149 { "sa_query", hostapd_cli_cmd_sa_query },
1150#endif /* CONFIG_IEEE80211W */
1151#ifdef CONFIG_WPS
1152 { "wps_pin", hostapd_cli_cmd_wps_pin },
1153 { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
1154 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
Dmitry Shmidt04949592012-07-19 12:16:46 -07001155 { "wps_cancel", hostapd_cli_cmd_wps_cancel },
Dmitry Shmidt04949592012-07-19 12:16:46 -07001156#ifdef CONFIG_WPS_NFC
1157 { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
1158 { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
1159 { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001160 { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
Dmitry Shmidt04949592012-07-19 12:16:46 -07001161#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001162 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
1163 { "wps_config", hostapd_cli_cmd_wps_config },
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07001164 { "wps_get_status", hostapd_cli_cmd_wps_get_status },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001165#endif /* CONFIG_WPS */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001166 { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001167 { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001168 { "bss_tm_req", hostapd_cli_cmd_bss_tm_req },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001169 { "get_config", hostapd_cli_cmd_get_config },
1170 { "help", hostapd_cli_cmd_help },
1171 { "interface", hostapd_cli_cmd_interface },
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001172#ifdef CONFIG_FST
1173 { "fst", hostapd_cli_cmd_fst },
1174#endif /* CONFIG_FST */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001175 { "raw", hostapd_cli_cmd_raw },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001176 { "level", hostapd_cli_cmd_level },
1177 { "license", hostapd_cli_cmd_license },
1178 { "quit", hostapd_cli_cmd_quit },
1179 { "set", hostapd_cli_cmd_set },
1180 { "get", hostapd_cli_cmd_get },
Dmitry Shmidt051af732013-10-22 13:52:46 -07001181 { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
1182 { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001183 { "chan_switch", hostapd_cli_cmd_chan_switch },
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001184 { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif },
1185 { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req },
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001186 { "vendor", hostapd_cli_cmd_vendor },
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001187 { "enable", hostapd_cli_cmd_enable },
1188 { "reload", hostapd_cli_cmd_reload },
1189 { "disable", hostapd_cli_cmd_disable },
1190 { "erp_flush", hostapd_cli_cmd_erp_flush },
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001191 { "log_level", hostapd_cli_cmd_log_level },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001192 { NULL, NULL }
1193};
1194
1195
1196static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
1197{
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07001198 const struct hostapd_cli_cmd *cmd, *match = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001199 int count;
1200
1201 count = 0;
1202 cmd = hostapd_cli_commands;
1203 while (cmd->cmd) {
1204 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
1205 match = cmd;
1206 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1207 /* we have an exact match */
1208 count = 1;
1209 break;
1210 }
1211 count++;
1212 }
1213 cmd++;
1214 }
1215
1216 if (count > 1) {
1217 printf("Ambiguous command '%s'; possible commands:", argv[0]);
1218 cmd = hostapd_cli_commands;
1219 while (cmd->cmd) {
1220 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
1221 0) {
1222 printf(" %s", cmd->cmd);
1223 }
1224 cmd++;
1225 }
1226 printf("\n");
1227 } else if (count == 0) {
1228 printf("Unknown command '%s'\n", argv[0]);
1229 } else {
1230 match->handler(ctrl, argc - 1, &argv[1]);
1231 }
1232}
1233
1234
1235static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
1236 int action_monitor)
1237{
1238 int first = 1;
1239 if (ctrl_conn == NULL)
1240 return;
1241 while (wpa_ctrl_pending(ctrl)) {
1242 char buf[256];
1243 size_t len = sizeof(buf) - 1;
1244 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
1245 buf[len] = '\0';
1246 if (action_monitor)
1247 hostapd_cli_action_process(buf, len);
1248 else {
1249 if (in_read && first)
1250 printf("\n");
1251 first = 0;
1252 printf("%s\n", buf);
1253 }
1254 } else {
1255 printf("Could not read pending message.\n");
1256 break;
1257 }
1258 }
1259}
1260
1261
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001262#define max_args 10
1263
1264static int tokenize_cmd(char *cmd, char *argv[])
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001265{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001266 char *pos;
1267 int argc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001268
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001269 pos = cmd;
1270 for (;;) {
1271 while (*pos == ' ')
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001272 pos++;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001273 if (*pos == '\0')
1274 break;
1275 argv[argc] = pos;
1276 argc++;
1277 if (argc == max_args)
1278 break;
1279 if (*pos == '"') {
1280 char *pos2 = os_strrchr(pos, '"');
1281 if (pos2)
1282 pos = pos2 + 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001283 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001284 while (*pos != '\0' && *pos != ' ')
1285 pos++;
1286 if (*pos == ' ')
1287 *pos++ = '\0';
1288 }
1289
1290 return argc;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001291}
1292
1293
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001294static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001295{
1296 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
1297 printf("Connection to hostapd lost - trying to reconnect\n");
1298 hostapd_cli_close_connection();
1299 }
1300 if (!ctrl_conn) {
1301 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1302 if (ctrl_conn) {
1303 printf("Connection to hostapd re-established\n");
1304 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1305 hostapd_cli_attached = 1;
1306 } else {
1307 printf("Warning: Failed to attach to "
1308 "hostapd.\n");
1309 }
1310 }
1311 }
1312 if (ctrl_conn)
1313 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001314 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1315}
1316
1317
1318static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
1319{
1320 eloop_terminate();
1321}
1322
1323
1324static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
1325{
1326 char *argv[max_args];
1327 int argc;
1328 argc = tokenize_cmd(cmd, argv);
1329 if (argc)
1330 wpa_request(ctrl_conn, argc, argv);
1331}
1332
1333
1334static void hostapd_cli_edit_eof_cb(void *ctx)
1335{
1336 eloop_terminate();
1337}
1338
1339
1340static void hostapd_cli_interactive(void)
1341{
1342 printf("\nInteractive mode\n\n");
1343
1344 eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
1345 edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001346 NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001347 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1348
1349 eloop_run();
1350
1351 edit_deinit(NULL, NULL);
1352 eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
1353}
1354
1355
1356static void hostapd_cli_cleanup(void)
1357{
1358 hostapd_cli_close_connection();
1359 if (pid_file)
1360 os_daemonize_terminate(pid_file);
1361
1362 os_program_deinit();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001363}
1364
1365
1366static void hostapd_cli_action(struct wpa_ctrl *ctrl)
1367{
1368 fd_set rfds;
1369 int fd, res;
1370 struct timeval tv;
1371 char buf[256];
1372 size_t len;
1373
1374 fd = wpa_ctrl_get_fd(ctrl);
1375
1376 while (!hostapd_cli_quit) {
1377 FD_ZERO(&rfds);
1378 FD_SET(fd, &rfds);
1379 tv.tv_sec = ping_interval;
1380 tv.tv_usec = 0;
1381 res = select(fd + 1, &rfds, NULL, NULL, &tv);
1382 if (res < 0 && errno != EINTR) {
1383 perror("select");
1384 break;
1385 }
1386
1387 if (FD_ISSET(fd, &rfds))
1388 hostapd_cli_recv_pending(ctrl, 0, 1);
1389 else {
1390 len = sizeof(buf) - 1;
1391 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1392 hostapd_cli_action_process) < 0 ||
1393 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
1394 printf("hostapd did not reply to PING "
1395 "command - exiting\n");
1396 break;
1397 }
1398 }
1399 }
1400}
1401
1402
1403int main(int argc, char *argv[])
1404{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001405 int warning_displayed = 0;
1406 int c;
1407 int daemonize = 0;
1408
1409 if (os_program_init())
1410 return -1;
1411
1412 for (;;) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001413 c = getopt(argc, argv, "a:BhG:i:p:P:s:v");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001414 if (c < 0)
1415 break;
1416 switch (c) {
1417 case 'a':
1418 action_file = optarg;
1419 break;
1420 case 'B':
1421 daemonize = 1;
1422 break;
1423 case 'G':
1424 ping_interval = atoi(optarg);
1425 break;
1426 case 'h':
1427 usage();
1428 return 0;
1429 case 'v':
1430 printf("%s\n", hostapd_cli_version);
1431 return 0;
1432 case 'i':
1433 os_free(ctrl_ifname);
1434 ctrl_ifname = os_strdup(optarg);
1435 break;
1436 case 'p':
1437 ctrl_iface_dir = optarg;
1438 break;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001439 case 'P':
1440 pid_file = optarg;
1441 break;
1442 case 's':
1443 client_socket_dir = optarg;
1444 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001445 default:
1446 usage();
1447 return -1;
1448 }
1449 }
1450
1451 interactive = (argc == optind) && (action_file == NULL);
1452
1453 if (interactive) {
1454 printf("%s\n\n%s\n\n", hostapd_cli_version,
1455 hostapd_cli_license);
1456 }
1457
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001458 if (eloop_init())
1459 return -1;
1460
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001461 for (;;) {
1462 if (ctrl_ifname == NULL) {
1463 struct dirent *dent;
1464 DIR *dir = opendir(ctrl_iface_dir);
1465 if (dir) {
1466 while ((dent = readdir(dir))) {
1467 if (os_strcmp(dent->d_name, ".") == 0
1468 ||
1469 os_strcmp(dent->d_name, "..") == 0)
1470 continue;
1471 printf("Selected interface '%s'\n",
1472 dent->d_name);
1473 ctrl_ifname = os_strdup(dent->d_name);
1474 break;
1475 }
1476 closedir(dir);
1477 }
1478 }
1479 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1480 if (ctrl_conn) {
1481 if (warning_displayed)
1482 printf("Connection established.\n");
1483 break;
1484 }
1485
1486 if (!interactive) {
1487 perror("Failed to connect to hostapd - "
1488 "wpa_ctrl_open");
1489 return -1;
1490 }
1491
1492 if (!warning_displayed) {
1493 printf("Could not connect to hostapd - re-trying\n");
1494 warning_displayed = 1;
1495 }
1496 os_sleep(1, 0);
1497 continue;
1498 }
1499
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001500 if (interactive || action_file) {
1501 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1502 hostapd_cli_attached = 1;
1503 } else {
1504 printf("Warning: Failed to attach to hostapd.\n");
1505 if (action_file)
1506 return -1;
1507 }
1508 }
1509
Dmitry Shmidtb97e4282016-02-08 10:16:07 -08001510 if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001511 return -1;
1512
1513 if (interactive)
1514 hostapd_cli_interactive();
1515 else if (action_file)
1516 hostapd_cli_action(ctrl_conn);
1517 else
1518 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1519
1520 os_free(ctrl_ifname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001521 eloop_destroy();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001522 hostapd_cli_cleanup();
1523 return 0;
1524}
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08001525
1526#else /* CONFIG_NO_CTRL_IFACE */
1527
1528int main(int argc, char *argv[])
1529{
1530 return -1;
1531}
1532
1533#endif /* CONFIG_NO_CTRL_IFACE */