blob: 3f00cbbf0cc7a9b1604a698866df0b9c39d66514 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * hostapd - command line interface for hostapd daemon
Dmitry Shmidt807291d2015-01-27 13:40:23 -08003 * Copyright (c) 2004-2015, 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 Shmidt1f69aa52012-01-24 16:10:04 -080013#include "utils/common.h"
14#include "utils/eloop.h"
15#include "utils/edit.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070016#include "common/version.h"
17
18
19static const char *hostapd_cli_version =
20"hostapd_cli v" VERSION_STR "\n"
Dmitry Shmidt807291d2015-01-27 13:40:23 -080021"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070022
23
24static const char *hostapd_cli_license =
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -080025"This software may be distributed under the terms of the BSD license.\n"
26"See README for more details.\n";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070027
28static const char *hostapd_cli_full_license =
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -080029"This software may be distributed under the terms of the BSD license.\n"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070030"\n"
31"Redistribution and use in source and binary forms, with or without\n"
32"modification, are permitted provided that the following conditions are\n"
33"met:\n"
34"\n"
35"1. Redistributions of source code must retain the above copyright\n"
36" notice, this list of conditions and the following disclaimer.\n"
37"\n"
38"2. Redistributions in binary form must reproduce the above copyright\n"
39" notice, this list of conditions and the following disclaimer in the\n"
40" documentation and/or other materials provided with the distribution.\n"
41"\n"
42"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
43" names of its contributors may be used to endorse or promote products\n"
44" derived from this software without specific prior written permission.\n"
45"\n"
46"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
47"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
48"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
49"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
50"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
51"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
52"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
53"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
54"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
55"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
56"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
57"\n";
58
59static const char *commands_help =
60"Commands:\n"
61" mib get MIB variables (dot1x, dot11, radius)\n"
62" sta <addr> get MIB variables for one station\n"
63" all_sta get MIB variables for all stations\n"
64" new_sta <addr> add a new station\n"
65" deauthenticate <addr> deauthenticate a station\n"
66" disassociate <addr> disassociate a station\n"
67#ifdef CONFIG_IEEE80211W
68" sa_query <addr> send SA Query to a station\n"
69#endif /* CONFIG_IEEE80211W */
70#ifdef CONFIG_WPS
71" wps_pin <uuid> <pin> [timeout] [addr] add WPS Enrollee PIN\n"
72" wps_check_pin <PIN> verify PIN checksum\n"
73" wps_pbc indicate button pushed to initiate PBC\n"
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070074" wps_cancel cancel the pending WPS operation\n"
Dmitry Shmidt04949592012-07-19 12:16:46 -070075#ifdef CONFIG_WPS_NFC
76" wps_nfc_tag_read <hexdump> report read NFC tag with WPS data\n"
77" wps_nfc_config_token <WPS/NDEF> build NFC configuration token\n"
78" wps_nfc_token <WPS/NDEF/enable/disable> manager NFC password token\n"
79#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070080" wps_ap_pin <cmd> [params..] enable/disable AP PIN\n"
81" wps_config <SSID> <auth> <encr> <key> configure AP\n"
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070082" wps_get_status show current WPS status\n"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070083#endif /* CONFIG_WPS */
84" get_config show current configuration\n"
85" help show this usage help\n"
86" interface [ifname] show interfaces/select interface\n"
87" level <debug level> change debug level\n"
88" license show full hostapd_cli license\n"
89" quit exit hostapd_cli\n";
90
91static struct wpa_ctrl *ctrl_conn;
92static int hostapd_cli_quit = 0;
93static int hostapd_cli_attached = 0;
Jeff Johnson205f2142012-09-03 22:12:17 -070094
95#ifndef CONFIG_CTRL_IFACE_DIR
96#define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd"
97#endif /* CONFIG_CTRL_IFACE_DIR */
98static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
99
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700100static char *ctrl_ifname = NULL;
101static const char *pid_file = NULL;
102static const char *action_file = NULL;
103static int ping_interval = 5;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800104static int interactive = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700105
106
107static void usage(void)
108{
109 fprintf(stderr, "%s\n", hostapd_cli_version);
110 fprintf(stderr,
111 "\n"
112 "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
113 "[-a<path>] \\\n"
114 " [-G<ping interval>] [command..]\n"
115 "\n"
116 "Options:\n"
117 " -h help (show this usage text)\n"
118 " -v shown version information\n"
119 " -p<path> path to find control sockets (default: "
120 "/var/run/hostapd)\n"
121 " -a<file> run in daemon mode executing the action file "
122 "based on events\n"
123 " from hostapd\n"
124 " -B run a daemon in the background\n"
125 " -i<ifname> Interface to listen on (default: first "
126 "interface found in the\n"
127 " socket path)\n\n"
128 "%s",
129 commands_help);
130}
131
132
133static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
134{
135 char *cfile;
136 int flen;
137
138 if (ifname == NULL)
139 return NULL;
140
141 flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
142 cfile = malloc(flen);
143 if (cfile == NULL)
144 return NULL;
145 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
146
147 ctrl_conn = wpa_ctrl_open(cfile);
148 free(cfile);
149 return ctrl_conn;
150}
151
152
153static void hostapd_cli_close_connection(void)
154{
155 if (ctrl_conn == NULL)
156 return;
157
158 if (hostapd_cli_attached) {
159 wpa_ctrl_detach(ctrl_conn);
160 hostapd_cli_attached = 0;
161 }
162 wpa_ctrl_close(ctrl_conn);
163 ctrl_conn = NULL;
164}
165
166
167static void hostapd_cli_msg_cb(char *msg, size_t len)
168{
169 printf("%s\n", msg);
170}
171
172
173static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
174{
175 char buf[4096];
176 size_t len;
177 int ret;
178
179 if (ctrl_conn == NULL) {
180 printf("Not connected to hostapd - command dropped.\n");
181 return -1;
182 }
183 len = sizeof(buf) - 1;
184 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
185 hostapd_cli_msg_cb);
186 if (ret == -2) {
187 printf("'%s' command timed out.\n", cmd);
188 return -2;
189 } else if (ret < 0) {
190 printf("'%s' command failed.\n", cmd);
191 return -1;
192 }
193 if (print) {
194 buf[len] = '\0';
195 printf("%s", buf);
196 }
197 return 0;
198}
199
200
201static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
202{
203 return _wpa_ctrl_command(ctrl, cmd, 1);
204}
205
206
207static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
208{
209 return wpa_ctrl_command(ctrl, "PING");
210}
211
212
213static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
214{
215 return wpa_ctrl_command(ctrl, "RELOG");
216}
217
218
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800219static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
220{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800221 if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
222 return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800223 return wpa_ctrl_command(ctrl, "STATUS");
224}
225
226
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700227static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
228{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800229 if (argc > 0) {
230 char buf[100];
231 os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]);
232 return wpa_ctrl_command(ctrl, buf);
233 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700234 return wpa_ctrl_command(ctrl, "MIB");
235}
236
237
238static int hostapd_cli_exec(const char *program, const char *arg1,
239 const char *arg2)
240{
Jouni Malinen772e12c2014-10-07 10:29:35 -0700241 char *arg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700242 size_t len;
243 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700244
Jouni Malinen772e12c2014-10-07 10:29:35 -0700245 len = os_strlen(arg1) + os_strlen(arg2) + 2;
246 arg = os_malloc(len);
247 if (arg == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700248 return -1;
Jouni Malinen772e12c2014-10-07 10:29:35 -0700249 os_snprintf(arg, len, "%s %s", arg1, arg2);
250 res = os_exec(program, arg, 1);
251 os_free(arg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700252
Jouni Malinen772e12c2014-10-07 10:29:35 -0700253 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700254}
255
256
257static void hostapd_cli_action_process(char *msg, size_t len)
258{
259 const char *pos;
260
261 pos = msg;
262 if (*pos == '<') {
263 pos = os_strchr(pos, '>');
264 if (pos)
265 pos++;
266 else
267 pos = msg;
268 }
269
270 hostapd_cli_exec(action_file, ctrl_ifname, pos);
271}
272
273
274static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
275{
276 char buf[64];
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800277 if (argc < 1) {
278 printf("Invalid 'sta' command - at least one argument, STA "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700279 "address, is required.\n");
280 return -1;
281 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800282 if (argc > 1)
283 snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]);
284 else
285 snprintf(buf, sizeof(buf), "STA %s", argv[0]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700286 return wpa_ctrl_command(ctrl, buf);
287}
288
289
290static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
291 char *argv[])
292{
293 char buf[64];
294 if (argc != 1) {
295 printf("Invalid 'new_sta' command - exactly one argument, STA "
296 "address, is required.\n");
297 return -1;
298 }
299 snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
300 return wpa_ctrl_command(ctrl, buf);
301}
302
303
304static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
305 char *argv[])
306{
307 char buf[64];
308 if (argc < 1) {
309 printf("Invalid 'deauthenticate' command - exactly one "
310 "argument, STA address, is required.\n");
311 return -1;
312 }
313 if (argc > 1)
314 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
315 argv[0], argv[1]);
316 else
317 os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
318 return wpa_ctrl_command(ctrl, buf);
319}
320
321
322static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
323 char *argv[])
324{
325 char buf[64];
326 if (argc < 1) {
327 printf("Invalid 'disassociate' command - exactly one "
328 "argument, STA address, is required.\n");
329 return -1;
330 }
331 if (argc > 1)
332 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
333 argv[0], argv[1]);
334 else
335 os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
336 return wpa_ctrl_command(ctrl, buf);
337}
338
339
340#ifdef CONFIG_IEEE80211W
341static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
342 char *argv[])
343{
344 char buf[64];
345 if (argc != 1) {
346 printf("Invalid 'sa_query' command - exactly one argument, "
347 "STA address, is required.\n");
348 return -1;
349 }
350 snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
351 return wpa_ctrl_command(ctrl, buf);
352}
353#endif /* CONFIG_IEEE80211W */
354
355
356#ifdef CONFIG_WPS
357static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
358 char *argv[])
359{
360 char buf[256];
361 if (argc < 2) {
362 printf("Invalid 'wps_pin' command - at least two arguments, "
363 "UUID and PIN, are required.\n");
364 return -1;
365 }
366 if (argc > 3)
367 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
368 argv[0], argv[1], argv[2], argv[3]);
369 else if (argc > 2)
370 snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
371 argv[0], argv[1], argv[2]);
372 else
373 snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
374 return wpa_ctrl_command(ctrl, buf);
375}
376
377
378static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
379 char *argv[])
380{
381 char cmd[256];
382 int res;
383
384 if (argc != 1 && argc != 2) {
385 printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
386 "- PIN to be verified\n");
387 return -1;
388 }
389
390 if (argc == 2)
391 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
392 argv[0], argv[1]);
393 else
394 res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
395 argv[0]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800396 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700397 printf("Too long WPS_CHECK_PIN command.\n");
398 return -1;
399 }
400 return wpa_ctrl_command(ctrl, cmd);
401}
402
403
404static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
405 char *argv[])
406{
407 return wpa_ctrl_command(ctrl, "WPS_PBC");
408}
409
410
Dmitry Shmidt04949592012-07-19 12:16:46 -0700411static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
412 char *argv[])
413{
414 return wpa_ctrl_command(ctrl, "WPS_CANCEL");
415}
416
417
Dmitry Shmidt04949592012-07-19 12:16:46 -0700418#ifdef CONFIG_WPS_NFC
419static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
420 char *argv[])
421{
422 int ret;
423 char *buf;
424 size_t buflen;
425
426 if (argc != 1) {
427 printf("Invalid 'wps_nfc_tag_read' command - one argument "
428 "is required.\n");
429 return -1;
430 }
431
432 buflen = 18 + os_strlen(argv[0]);
433 buf = os_malloc(buflen);
434 if (buf == NULL)
435 return -1;
436 os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
437
438 ret = wpa_ctrl_command(ctrl, buf);
439 os_free(buf);
440
441 return ret;
442}
443
444
445static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
446 int argc, char *argv[])
447{
448 char cmd[64];
449 int res;
450
451 if (argc != 1) {
452 printf("Invalid 'wps_nfc_config_token' command - one argument "
453 "is required.\n");
454 return -1;
455 }
456
457 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
458 argv[0]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800459 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700460 printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
461 return -1;
462 }
463 return wpa_ctrl_command(ctrl, cmd);
464}
465
466
467static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
468 int argc, char *argv[])
469{
470 char cmd[64];
471 int res;
472
473 if (argc != 1) {
474 printf("Invalid 'wps_nfc_token' command - one argument is "
475 "required.\n");
476 return -1;
477 }
478
479 res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800480 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700481 printf("Too long WPS_NFC_TOKEN command.\n");
482 return -1;
483 }
484 return wpa_ctrl_command(ctrl, cmd);
485}
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800486
487
488static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
489 int argc, char *argv[])
490{
491 char cmd[64];
492 int res;
493
494 if (argc != 2) {
495 printf("Invalid 'nfc_get_handover_sel' command - two arguments "
496 "are required.\n");
497 return -1;
498 }
499
500 res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
501 argv[0], argv[1]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800502 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800503 printf("Too long NFC_GET_HANDOVER_SEL command.\n");
504 return -1;
505 }
506 return wpa_ctrl_command(ctrl, cmd);
507}
508
Dmitry Shmidt04949592012-07-19 12:16:46 -0700509#endif /* CONFIG_WPS_NFC */
510
511
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700512static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
513 char *argv[])
514{
515 char buf[64];
516 if (argc < 1) {
517 printf("Invalid 'wps_ap_pin' command - at least one argument "
518 "is required.\n");
519 return -1;
520 }
521 if (argc > 2)
522 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
523 argv[0], argv[1], argv[2]);
524 else if (argc > 1)
525 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
526 argv[0], argv[1]);
527 else
528 snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
529 return wpa_ctrl_command(ctrl, buf);
530}
531
532
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700533static int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc,
534 char *argv[])
535{
536 return wpa_ctrl_command(ctrl, "WPS_GET_STATUS");
537}
538
539
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700540static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
541 char *argv[])
542{
543 char buf[256];
544 char ssid_hex[2 * 32 + 1];
545 char key_hex[2 * 64 + 1];
546 int i;
547
548 if (argc < 1) {
549 printf("Invalid 'wps_config' command - at least two arguments "
550 "are required.\n");
551 return -1;
552 }
553
554 ssid_hex[0] = '\0';
555 for (i = 0; i < 32; i++) {
556 if (argv[0][i] == '\0')
557 break;
558 os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
559 }
560
561 key_hex[0] = '\0';
562 if (argc > 3) {
563 for (i = 0; i < 64; i++) {
564 if (argv[3][i] == '\0')
565 break;
566 os_snprintf(&key_hex[i * 2], 3, "%02x",
567 argv[3][i]);
568 }
569 }
570
571 if (argc > 3)
572 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
573 ssid_hex, argv[1], argv[2], key_hex);
574 else if (argc > 2)
575 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
576 ssid_hex, argv[1], argv[2]);
577 else
578 snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
579 ssid_hex, argv[1]);
580 return wpa_ctrl_command(ctrl, buf);
581}
582#endif /* CONFIG_WPS */
583
584
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800585static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
586 char *argv[])
587{
588 char buf[300];
589 int res;
590
591 if (argc < 2) {
592 printf("Invalid 'disassoc_imminent' command - two arguments "
593 "(STA addr and Disassociation Timer) are needed\n");
594 return -1;
595 }
596
597 res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
598 argv[0], argv[1]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800599 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800600 return -1;
601 return wpa_ctrl_command(ctrl, buf);
602}
603
604
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800605static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
606 char *argv[])
607{
608 char buf[300];
609 int res;
610
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700611 if (argc < 3) {
612 printf("Invalid 'ess_disassoc' command - three arguments (STA "
613 "addr, disassoc timer, and URL) are needed\n");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800614 return -1;
615 }
616
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700617 res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
618 argv[0], argv[1], argv[2]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800619 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800620 return -1;
621 return wpa_ctrl_command(ctrl, buf);
622}
623
624
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800625static int hostapd_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc,
626 char *argv[])
627{
628 char buf[2000], *tmp;
629 int res, i, total;
630
631 if (argc < 1) {
632 printf("Invalid 'bss_tm_req' command - at least one argument (STA addr) is needed\n");
633 return -1;
634 }
635
636 res = os_snprintf(buf, sizeof(buf), "BSS_TM_REQ %s", argv[0]);
637 if (os_snprintf_error(sizeof(buf), res))
638 return -1;
639
640 total = res;
641 for (i = 1; i < argc; i++) {
642 tmp = &buf[total];
643 res = os_snprintf(tmp, sizeof(buf) - total, " %s", argv[i]);
644 if (os_snprintf_error(sizeof(buf) - total, res))
645 return -1;
646 total += res;
647 }
648 return wpa_ctrl_command(ctrl, buf);
649}
650
651
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700652static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
653 char *argv[])
654{
655 return wpa_ctrl_command(ctrl, "GET_CONFIG");
656}
657
658
659static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
660 char *addr, size_t addr_len)
661{
662 char buf[4096], *pos;
663 size_t len;
664 int ret;
665
666 if (ctrl_conn == NULL) {
667 printf("Not connected to hostapd - command dropped.\n");
668 return -1;
669 }
670 len = sizeof(buf) - 1;
671 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
672 hostapd_cli_msg_cb);
673 if (ret == -2) {
674 printf("'%s' command timed out.\n", cmd);
675 return -2;
676 } else if (ret < 0) {
677 printf("'%s' command failed.\n", cmd);
678 return -1;
679 }
680
681 buf[len] = '\0';
682 if (memcmp(buf, "FAIL", 4) == 0)
683 return -1;
684 printf("%s", buf);
685
686 pos = buf;
687 while (*pos != '\0' && *pos != '\n')
688 pos++;
689 *pos = '\0';
690 os_strlcpy(addr, buf, addr_len);
691 return 0;
692}
693
694
695static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
696 char *argv[])
697{
698 char addr[32], cmd[64];
699
700 if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
701 return 0;
702 do {
703 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
704 } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
705
706 return -1;
707}
708
709
710static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
711{
712 printf("%s", commands_help);
713 return 0;
714}
715
716
717static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
718 char *argv[])
719{
720 printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
721 return 0;
722}
723
724
Dmitry Shmidt051af732013-10-22 13:52:46 -0700725static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl,
726 int argc, char *argv[])
727{
728 char buf[200];
729 int res;
730
731 if (argc != 1) {
732 printf("Invalid 'set_qos_map_set' command - "
733 "one argument (comma delimited QoS map set) "
734 "is needed\n");
735 return -1;
736 }
737
738 res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800739 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidt051af732013-10-22 13:52:46 -0700740 return -1;
741 return wpa_ctrl_command(ctrl, buf);
742}
743
744
745static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
746 int argc, char *argv[])
747{
748 char buf[50];
749 int res;
750
751 if (argc != 1) {
752 printf("Invalid 'send_qos_map_conf' command - "
753 "one argument (STA addr) is needed\n");
754 return -1;
755 }
756
757 res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800758 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidt051af732013-10-22 13:52:46 -0700759 return -1;
760 return wpa_ctrl_command(ctrl, buf);
761}
762
763
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800764static int hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc,
765 char *argv[])
766{
767 char buf[300];
768 int res;
769
770 if (argc < 2) {
771 printf("Invalid 'hs20_wnm_notif' command - two arguments (STA "
772 "addr and URL) are needed\n");
773 return -1;
774 }
775
776 res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s",
777 argv[0], argv[1]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800778 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800779 return -1;
780 return wpa_ctrl_command(ctrl, buf);
781}
782
783
784static int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc,
785 char *argv[])
786{
787 char buf[300];
788 int res;
789
790 if (argc < 3) {
791 printf("Invalid 'hs20_deauth_req' command - at least three arguments (STA addr, Code, Re-auth Delay) are needed\n");
792 return -1;
793 }
794
795 if (argc > 3)
796 res = os_snprintf(buf, sizeof(buf),
797 "HS20_DEAUTH_REQ %s %s %s %s",
798 argv[0], argv[1], argv[2], argv[3]);
799 else
800 res = os_snprintf(buf, sizeof(buf),
801 "HS20_DEAUTH_REQ %s %s %s",
802 argv[0], argv[1], argv[2]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800803 if (os_snprintf_error(sizeof(buf), res))
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800804 return -1;
805 return wpa_ctrl_command(ctrl, buf);
806}
807
808
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700809static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
810{
811 hostapd_cli_quit = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800812 if (interactive)
813 eloop_terminate();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700814 return 0;
815}
816
817
818static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
819{
820 char cmd[256];
821 if (argc != 1) {
822 printf("Invalid LEVEL command: needs one argument (debug "
823 "level)\n");
824 return 0;
825 }
826 snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
827 return wpa_ctrl_command(ctrl, cmd);
828}
829
830
831static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
832{
833 struct dirent *dent;
834 DIR *dir;
835
836 dir = opendir(ctrl_iface_dir);
837 if (dir == NULL) {
838 printf("Control interface directory '%s' could not be "
839 "openned.\n", ctrl_iface_dir);
840 return;
841 }
842
843 printf("Available interfaces:\n");
844 while ((dent = readdir(dir))) {
845 if (strcmp(dent->d_name, ".") == 0 ||
846 strcmp(dent->d_name, "..") == 0)
847 continue;
848 printf("%s\n", dent->d_name);
849 }
850 closedir(dir);
851}
852
853
854static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
855 char *argv[])
856{
857 if (argc < 1) {
858 hostapd_cli_list_interfaces(ctrl);
859 return 0;
860 }
861
862 hostapd_cli_close_connection();
Dmitry Shmidt71757432014-06-02 13:50:35 -0700863 os_free(ctrl_ifname);
864 ctrl_ifname = os_strdup(argv[0]);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -0700865 if (ctrl_ifname == NULL)
866 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700867
868 if (hostapd_cli_open_connection(ctrl_ifname)) {
869 printf("Connected to interface '%s.\n", ctrl_ifname);
870 if (wpa_ctrl_attach(ctrl_conn) == 0) {
871 hostapd_cli_attached = 1;
872 } else {
873 printf("Warning: Failed to attach to "
874 "hostapd.\n");
875 }
876 } else {
877 printf("Could not connect to interface '%s' - re-trying\n",
878 ctrl_ifname);
879 }
880 return 0;
881}
882
883
884static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
885{
886 char cmd[256];
887 int res;
888
889 if (argc != 2) {
890 printf("Invalid SET command: needs two arguments (variable "
891 "name and value)\n");
892 return -1;
893 }
894
895 res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800896 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700897 printf("Too long SET command.\n");
898 return -1;
899 }
900 return wpa_ctrl_command(ctrl, cmd);
901}
902
903
904static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
905{
906 char cmd[256];
907 int res;
908
909 if (argc != 1) {
910 printf("Invalid GET command: needs one argument (variable "
911 "name)\n");
912 return -1;
913 }
914
915 res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800916 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700917 printf("Too long GET command.\n");
918 return -1;
919 }
920 return wpa_ctrl_command(ctrl, cmd);
921}
922
923
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800924static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
925 int argc, char *argv[])
926{
927 char cmd[256];
928 int res;
929 int i;
930 char *tmp;
931 int total;
932
933 if (argc < 2) {
934 printf("Invalid chan_switch command: needs at least two "
935 "arguments (count and freq)\n"
936 "usage: <cs_count> <freq> [sec_channel_offset=] "
937 "[center_freq1=] [center_freq2=] [bandwidth=] "
938 "[blocktx] [ht|vht]\n");
939 return -1;
940 }
941
942 res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
943 argv[0], argv[1]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800944 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800945 printf("Too long CHAN_SWITCH command.\n");
946 return -1;
947 }
948
949 total = res;
950 for (i = 2; i < argc; i++) {
951 tmp = cmd + total;
952 res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800953 if (os_snprintf_error(sizeof(cmd) - total, res)) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800954 printf("Too long CHAN_SWITCH command.\n");
955 return -1;
956 }
957 total += res;
958 }
959 return wpa_ctrl_command(ctrl, cmd);
960}
961
962
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800963static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc,
964 char *argv[])
965{
966 return wpa_ctrl_command(ctrl, "ENABLE");
967}
968
969
970static int hostapd_cli_cmd_reload(struct wpa_ctrl *ctrl, int argc,
971 char *argv[])
972{
973 return wpa_ctrl_command(ctrl, "RELOAD");
974}
975
976
977static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc,
978 char *argv[])
979{
980 return wpa_ctrl_command(ctrl, "DISABLE");
981}
982
983
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -0700984static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
985{
986 char cmd[256];
987 int res;
988
989 if (argc < 2 || argc > 3) {
990 printf("Invalid vendor command\n"
991 "usage: <vendor id> <command id> [<hex formatted command argument>]\n");
992 return -1;
993 }
994
995 res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
996 argc == 3 ? argv[2] : "");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800997 if (os_snprintf_error(sizeof(cmd), res)) {
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -0700998 printf("Too long VENDOR command.\n");
999 return -1;
1000 }
1001 return wpa_ctrl_command(ctrl, cmd);
1002}
1003
1004
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001005static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc,
1006 char *argv[])
1007{
1008 return wpa_ctrl_command(ctrl, "ERP_FLUSH");
1009}
1010
1011
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001012struct hostapd_cli_cmd {
1013 const char *cmd;
1014 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
1015};
1016
1017static struct hostapd_cli_cmd hostapd_cli_commands[] = {
1018 { "ping", hostapd_cli_cmd_ping },
1019 { "mib", hostapd_cli_cmd_mib },
1020 { "relog", hostapd_cli_cmd_relog },
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001021 { "status", hostapd_cli_cmd_status },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001022 { "sta", hostapd_cli_cmd_sta },
1023 { "all_sta", hostapd_cli_cmd_all_sta },
1024 { "new_sta", hostapd_cli_cmd_new_sta },
1025 { "deauthenticate", hostapd_cli_cmd_deauthenticate },
1026 { "disassociate", hostapd_cli_cmd_disassociate },
1027#ifdef CONFIG_IEEE80211W
1028 { "sa_query", hostapd_cli_cmd_sa_query },
1029#endif /* CONFIG_IEEE80211W */
1030#ifdef CONFIG_WPS
1031 { "wps_pin", hostapd_cli_cmd_wps_pin },
1032 { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
1033 { "wps_pbc", hostapd_cli_cmd_wps_pbc },
Dmitry Shmidt04949592012-07-19 12:16:46 -07001034 { "wps_cancel", hostapd_cli_cmd_wps_cancel },
Dmitry Shmidt04949592012-07-19 12:16:46 -07001035#ifdef CONFIG_WPS_NFC
1036 { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
1037 { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
1038 { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001039 { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
Dmitry Shmidt04949592012-07-19 12:16:46 -07001040#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001041 { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
1042 { "wps_config", hostapd_cli_cmd_wps_config },
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07001043 { "wps_get_status", hostapd_cli_cmd_wps_get_status },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001044#endif /* CONFIG_WPS */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001045 { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001046 { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001047 { "bss_tm_req", hostapd_cli_cmd_bss_tm_req },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001048 { "get_config", hostapd_cli_cmd_get_config },
1049 { "help", hostapd_cli_cmd_help },
1050 { "interface", hostapd_cli_cmd_interface },
1051 { "level", hostapd_cli_cmd_level },
1052 { "license", hostapd_cli_cmd_license },
1053 { "quit", hostapd_cli_cmd_quit },
1054 { "set", hostapd_cli_cmd_set },
1055 { "get", hostapd_cli_cmd_get },
Dmitry Shmidt051af732013-10-22 13:52:46 -07001056 { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
1057 { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001058 { "chan_switch", hostapd_cli_cmd_chan_switch },
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001059 { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif },
1060 { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req },
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001061 { "vendor", hostapd_cli_cmd_vendor },
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001062 { "enable", hostapd_cli_cmd_enable },
1063 { "reload", hostapd_cli_cmd_reload },
1064 { "disable", hostapd_cli_cmd_disable },
1065 { "erp_flush", hostapd_cli_cmd_erp_flush },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001066 { NULL, NULL }
1067};
1068
1069
1070static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
1071{
1072 struct hostapd_cli_cmd *cmd, *match = NULL;
1073 int count;
1074
1075 count = 0;
1076 cmd = hostapd_cli_commands;
1077 while (cmd->cmd) {
1078 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
1079 match = cmd;
1080 if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1081 /* we have an exact match */
1082 count = 1;
1083 break;
1084 }
1085 count++;
1086 }
1087 cmd++;
1088 }
1089
1090 if (count > 1) {
1091 printf("Ambiguous command '%s'; possible commands:", argv[0]);
1092 cmd = hostapd_cli_commands;
1093 while (cmd->cmd) {
1094 if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
1095 0) {
1096 printf(" %s", cmd->cmd);
1097 }
1098 cmd++;
1099 }
1100 printf("\n");
1101 } else if (count == 0) {
1102 printf("Unknown command '%s'\n", argv[0]);
1103 } else {
1104 match->handler(ctrl, argc - 1, &argv[1]);
1105 }
1106}
1107
1108
1109static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
1110 int action_monitor)
1111{
1112 int first = 1;
1113 if (ctrl_conn == NULL)
1114 return;
1115 while (wpa_ctrl_pending(ctrl)) {
1116 char buf[256];
1117 size_t len = sizeof(buf) - 1;
1118 if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
1119 buf[len] = '\0';
1120 if (action_monitor)
1121 hostapd_cli_action_process(buf, len);
1122 else {
1123 if (in_read && first)
1124 printf("\n");
1125 first = 0;
1126 printf("%s\n", buf);
1127 }
1128 } else {
1129 printf("Could not read pending message.\n");
1130 break;
1131 }
1132 }
1133}
1134
1135
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001136#define max_args 10
1137
1138static int tokenize_cmd(char *cmd, char *argv[])
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001139{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001140 char *pos;
1141 int argc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001142
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001143 pos = cmd;
1144 for (;;) {
1145 while (*pos == ' ')
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001146 pos++;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001147 if (*pos == '\0')
1148 break;
1149 argv[argc] = pos;
1150 argc++;
1151 if (argc == max_args)
1152 break;
1153 if (*pos == '"') {
1154 char *pos2 = os_strrchr(pos, '"');
1155 if (pos2)
1156 pos = pos2 + 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001157 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001158 while (*pos != '\0' && *pos != ' ')
1159 pos++;
1160 if (*pos == ' ')
1161 *pos++ = '\0';
1162 }
1163
1164 return argc;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001165}
1166
1167
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001168static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001169{
1170 if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
1171 printf("Connection to hostapd lost - trying to reconnect\n");
1172 hostapd_cli_close_connection();
1173 }
1174 if (!ctrl_conn) {
1175 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1176 if (ctrl_conn) {
1177 printf("Connection to hostapd re-established\n");
1178 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1179 hostapd_cli_attached = 1;
1180 } else {
1181 printf("Warning: Failed to attach to "
1182 "hostapd.\n");
1183 }
1184 }
1185 }
1186 if (ctrl_conn)
1187 hostapd_cli_recv_pending(ctrl_conn, 1, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001188 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1189}
1190
1191
1192static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
1193{
1194 eloop_terminate();
1195}
1196
1197
1198static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
1199{
1200 char *argv[max_args];
1201 int argc;
1202 argc = tokenize_cmd(cmd, argv);
1203 if (argc)
1204 wpa_request(ctrl_conn, argc, argv);
1205}
1206
1207
1208static void hostapd_cli_edit_eof_cb(void *ctx)
1209{
1210 eloop_terminate();
1211}
1212
1213
1214static void hostapd_cli_interactive(void)
1215{
1216 printf("\nInteractive mode\n\n");
1217
1218 eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
1219 edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001220 NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001221 eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
1222
1223 eloop_run();
1224
1225 edit_deinit(NULL, NULL);
1226 eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
1227}
1228
1229
1230static void hostapd_cli_cleanup(void)
1231{
1232 hostapd_cli_close_connection();
1233 if (pid_file)
1234 os_daemonize_terminate(pid_file);
1235
1236 os_program_deinit();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001237}
1238
1239
1240static void hostapd_cli_action(struct wpa_ctrl *ctrl)
1241{
1242 fd_set rfds;
1243 int fd, res;
1244 struct timeval tv;
1245 char buf[256];
1246 size_t len;
1247
1248 fd = wpa_ctrl_get_fd(ctrl);
1249
1250 while (!hostapd_cli_quit) {
1251 FD_ZERO(&rfds);
1252 FD_SET(fd, &rfds);
1253 tv.tv_sec = ping_interval;
1254 tv.tv_usec = 0;
1255 res = select(fd + 1, &rfds, NULL, NULL, &tv);
1256 if (res < 0 && errno != EINTR) {
1257 perror("select");
1258 break;
1259 }
1260
1261 if (FD_ISSET(fd, &rfds))
1262 hostapd_cli_recv_pending(ctrl, 0, 1);
1263 else {
1264 len = sizeof(buf) - 1;
1265 if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
1266 hostapd_cli_action_process) < 0 ||
1267 len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
1268 printf("hostapd did not reply to PING "
1269 "command - exiting\n");
1270 break;
1271 }
1272 }
1273 }
1274}
1275
1276
1277int main(int argc, char *argv[])
1278{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001279 int warning_displayed = 0;
1280 int c;
1281 int daemonize = 0;
1282
1283 if (os_program_init())
1284 return -1;
1285
1286 for (;;) {
1287 c = getopt(argc, argv, "a:BhG:i:p:v");
1288 if (c < 0)
1289 break;
1290 switch (c) {
1291 case 'a':
1292 action_file = optarg;
1293 break;
1294 case 'B':
1295 daemonize = 1;
1296 break;
1297 case 'G':
1298 ping_interval = atoi(optarg);
1299 break;
1300 case 'h':
1301 usage();
1302 return 0;
1303 case 'v':
1304 printf("%s\n", hostapd_cli_version);
1305 return 0;
1306 case 'i':
1307 os_free(ctrl_ifname);
1308 ctrl_ifname = os_strdup(optarg);
1309 break;
1310 case 'p':
1311 ctrl_iface_dir = optarg;
1312 break;
1313 default:
1314 usage();
1315 return -1;
1316 }
1317 }
1318
1319 interactive = (argc == optind) && (action_file == NULL);
1320
1321 if (interactive) {
1322 printf("%s\n\n%s\n\n", hostapd_cli_version,
1323 hostapd_cli_license);
1324 }
1325
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001326 if (eloop_init())
1327 return -1;
1328
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001329 for (;;) {
1330 if (ctrl_ifname == NULL) {
1331 struct dirent *dent;
1332 DIR *dir = opendir(ctrl_iface_dir);
1333 if (dir) {
1334 while ((dent = readdir(dir))) {
1335 if (os_strcmp(dent->d_name, ".") == 0
1336 ||
1337 os_strcmp(dent->d_name, "..") == 0)
1338 continue;
1339 printf("Selected interface '%s'\n",
1340 dent->d_name);
1341 ctrl_ifname = os_strdup(dent->d_name);
1342 break;
1343 }
1344 closedir(dir);
1345 }
1346 }
1347 ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
1348 if (ctrl_conn) {
1349 if (warning_displayed)
1350 printf("Connection established.\n");
1351 break;
1352 }
1353
1354 if (!interactive) {
1355 perror("Failed to connect to hostapd - "
1356 "wpa_ctrl_open");
1357 return -1;
1358 }
1359
1360 if (!warning_displayed) {
1361 printf("Could not connect to hostapd - re-trying\n");
1362 warning_displayed = 1;
1363 }
1364 os_sleep(1, 0);
1365 continue;
1366 }
1367
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001368 if (interactive || action_file) {
1369 if (wpa_ctrl_attach(ctrl_conn) == 0) {
1370 hostapd_cli_attached = 1;
1371 } else {
1372 printf("Warning: Failed to attach to hostapd.\n");
1373 if (action_file)
1374 return -1;
1375 }
1376 }
1377
1378 if (daemonize && os_daemonize(pid_file))
1379 return -1;
1380
1381 if (interactive)
1382 hostapd_cli_interactive();
1383 else if (action_file)
1384 hostapd_cli_action(ctrl_conn);
1385 else
1386 wpa_request(ctrl_conn, argc - optind, &argv[optind]);
1387
1388 os_free(ctrl_ifname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001389 eloop_destroy();
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001390 hostapd_cli_cleanup();
1391 return 0;
1392}