1  /*
2   * hostapd - command line interface for hostapd daemon
3   * Copyright (c) 2004-2022, Jouni Malinen <j@w1.fi>
4   *
5   * This software may be distributed under the terms of the BSD license.
6   * See README for more details.
7   */
8  
9  #include "includes.h"
10  #include <dirent.h>
11  
12  #include "common/wpa_ctrl.h"
13  #include "common/ieee802_11_defs.h"
14  #include "utils/common.h"
15  #include "utils/eloop.h"
16  #include "utils/edit.h"
17  #include "common/version.h"
18  #include "common/cli.h"
19  
20  #ifndef CONFIG_NO_CTRL_IFACE
21  
22  static const char *const hostapd_cli_version =
23  "hostapd_cli v" VERSION_STR "\n"
24  "Copyright (c) 2004-2024, Jouni Malinen <j@w1.fi> and contributors";
25  
26  static struct wpa_ctrl *ctrl_conn;
27  static int hostapd_cli_quit = 0;
28  static int hostapd_cli_attached = 0;
29  
30  #ifndef CONFIG_CTRL_IFACE_DIR
31  #define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd"
32  #endif /* CONFIG_CTRL_IFACE_DIR */
33  static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
34  static const char *client_socket_dir = NULL;
35  
36  static char *ctrl_ifname = NULL;
37  static const char *pid_file = NULL;
38  static const char *action_file = NULL;
39  static int ping_interval = 5;
40  static int interactive = 0;
41  static int event_handler_registered = 0;
42  
43  static DEFINE_DL_LIST(stations); /* struct cli_txt_entry */
44  
45  static void print_help(FILE *stream, const char *cmd);
46  static char ** list_cmd_list(void);
47  static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx);
48  static void update_stations(struct wpa_ctrl *ctrl);
49  static void cli_event(const char *str);
50  
51  
usage(void)52  static void usage(void)
53  {
54  	fprintf(stderr, "%s\n", hostapd_cli_version);
55  	fprintf(stderr,
56  		"\n"
57  		"usage: hostapd_cli [-p<path>] [-i<ifname>] "
58  #ifdef CONFIG_IEEE80211BE
59  		"[-l<link_id>] "
60  #endif /* CONFIG_IEEE80211BE */
61  		"[-hvBr] "
62  		"[-a<path>] \\\n"
63  		"                   [-P<pid file>] [-G<ping interval>] [command..]\n"
64  		"\n"
65  		"Options:\n"
66  		"   -h           help (show this usage text)\n"
67  		"   -v           shown version information\n"
68  		"   -p<path>     path to find control sockets (default: "
69  		"/var/run/hostapd)\n"
70  		"   -s<dir_path> dir path to open client sockets (default: "
71  		CONFIG_CTRL_IFACE_DIR ")\n"
72  		"   -a<file>     run in daemon mode executing the action file "
73  		"based on events\n"
74  		"                from hostapd\n"
75  		"   -r           try to reconnect when client socket is "
76  		"disconnected.\n"
77  		"                This is useful only when used with -a.\n"
78  		"   -B           run a daemon in the background\n"
79  		"   -i<ifname>   Interface to listen on (default: first "
80  		"interface found in the\n"
81  		"                socket path)\n"
82  #ifdef CONFIG_IEEE80211BE
83  		"   -l<link_id>  Link ID of the interface in case of Multi-Link Operation\n"
84  #endif /* CONFIG_IEEE80211BE */
85  		"\n");
86  	print_help(stderr, NULL);
87  }
88  
89  
register_event_handler(struct wpa_ctrl * ctrl)90  static void register_event_handler(struct wpa_ctrl *ctrl)
91  {
92  	if (!ctrl_conn)
93  		return;
94  	if (interactive) {
95  		event_handler_registered =
96  			!eloop_register_read_sock(wpa_ctrl_get_fd(ctrl),
97  						  hostapd_cli_receive,
98  						  NULL, NULL);
99  	}
100  }
101  
102  
unregister_event_handler(struct wpa_ctrl * ctrl)103  static void unregister_event_handler(struct wpa_ctrl *ctrl)
104  {
105  	if (!ctrl_conn)
106  		return;
107  	if (interactive && event_handler_registered) {
108  		eloop_unregister_read_sock(wpa_ctrl_get_fd(ctrl));
109  		event_handler_registered = 0;
110  	}
111  }
112  
113  
hostapd_cli_open_connection(const char * ifname)114  static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
115  {
116  #ifndef CONFIG_CTRL_IFACE_UDP
117  	char *cfile;
118  	int flen;
119  #endif /* !CONFIG_CTRL_IFACE_UDP */
120  
121  	if (ifname == NULL)
122  		return NULL;
123  
124  #ifdef CONFIG_CTRL_IFACE_UDP
125  	ctrl_conn = wpa_ctrl_open(ifname);
126  	return ctrl_conn;
127  #else /* CONFIG_CTRL_IFACE_UDP */
128  	flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
129  	cfile = malloc(flen);
130  	if (cfile == NULL)
131  		return NULL;
132  	snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
133  
134  	if (client_socket_dir && client_socket_dir[0] &&
135  	    access(client_socket_dir, F_OK) < 0) {
136  		perror(client_socket_dir);
137  		free(cfile);
138  		return NULL;
139  	}
140  
141  	ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir);
142  	free(cfile);
143  	return ctrl_conn;
144  #endif /* CONFIG_CTRL_IFACE_UDP */
145  }
146  
147  
hostapd_cli_close_connection(void)148  static void hostapd_cli_close_connection(void)
149  {
150  	if (ctrl_conn == NULL)
151  		return;
152  
153  	unregister_event_handler(ctrl_conn);
154  	if (hostapd_cli_attached) {
155  		wpa_ctrl_detach(ctrl_conn);
156  		hostapd_cli_attached = 0;
157  	}
158  	wpa_ctrl_close(ctrl_conn);
159  	ctrl_conn = NULL;
160  }
161  
162  
hostapd_cli_reconnect(const char * ifname)163  static int hostapd_cli_reconnect(const char *ifname)
164  {
165  	char *next_ctrl_ifname;
166  
167  	hostapd_cli_close_connection();
168  
169  	if (!ifname)
170  		return -1;
171  
172  	next_ctrl_ifname = os_strdup(ifname);
173  	os_free(ctrl_ifname);
174  	ctrl_ifname = next_ctrl_ifname;
175  	if (!ctrl_ifname)
176  		return -1;
177  
178  	ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
179  	if (!ctrl_conn)
180  		return -1;
181  	if (!interactive && !action_file)
182  		return 0;
183  	if (wpa_ctrl_attach(ctrl_conn) == 0) {
184  		hostapd_cli_attached = 1;
185  		register_event_handler(ctrl_conn);
186  		update_stations(ctrl_conn);
187  	} else {
188  		printf("Warning: Failed to attach to hostapd.\n");
189  	}
190  	return 0;
191  }
192  
193  
hostapd_cli_msg_cb(char * msg,size_t len)194  static void hostapd_cli_msg_cb(char *msg, size_t len)
195  {
196  	cli_event(msg);
197  	printf("%s\n", msg);
198  }
199  
200  
_wpa_ctrl_command(struct wpa_ctrl * ctrl,const char * cmd,int print)201  static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd, int print)
202  {
203  	char buf[4096];
204  	size_t len;
205  	int ret;
206  
207  	if (ctrl_conn == NULL) {
208  		printf("Not connected to hostapd - command dropped.\n");
209  		return -1;
210  	}
211  	len = sizeof(buf) - 1;
212  	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
213  			       hostapd_cli_msg_cb);
214  	if (ret == -2) {
215  		printf("'%s' command timed out.\n", cmd);
216  		return -2;
217  	} else if (ret < 0) {
218  		printf("'%s' command failed.\n", cmd);
219  		return -1;
220  	}
221  	if (print) {
222  		buf[len] = '\0';
223  		printf("%s", buf);
224  	}
225  	return 0;
226  }
227  
228  
wpa_ctrl_command(struct wpa_ctrl * ctrl,const char * cmd)229  static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd)
230  {
231  	return _wpa_ctrl_command(ctrl, cmd, 1);
232  }
233  
234  
hostapd_cli_cmd(struct wpa_ctrl * ctrl,const char * cmd,int min_args,int argc,char * argv[])235  static int hostapd_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd,
236  			   int min_args, int argc, char *argv[])
237  {
238  	char buf[4096];
239  
240  	if (argc < min_args) {
241  		printf("Invalid %s command - at least %d argument%s required.\n",
242  		       cmd, min_args, min_args > 1 ? "s are" : " is");
243  		return -1;
244  	}
245  	if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0)
246  		return -1;
247  	return wpa_ctrl_command(ctrl, buf);
248  }
249  
250  
hostapd_cli_cmd_ping(struct wpa_ctrl * ctrl,int argc,char * argv[])251  static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
252  {
253  	return wpa_ctrl_command(ctrl, "PING");
254  }
255  
256  
hostapd_cli_cmd_relog(struct wpa_ctrl * ctrl,int argc,char * argv[])257  static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
258  {
259  	return wpa_ctrl_command(ctrl, "RELOG");
260  }
261  
262  
hostapd_cli_cmd_close_log(struct wpa_ctrl * ctrl,int argc,char * argv[])263  static int hostapd_cli_cmd_close_log(struct wpa_ctrl *ctrl, int argc,
264  				     char *argv[])
265  {
266  	return wpa_ctrl_command(ctrl, "CLOSE_LOG");
267  }
268  
269  
hostapd_cli_cmd_status(struct wpa_ctrl * ctrl,int argc,char * argv[])270  static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
271  {
272  	if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
273  		return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
274  	return wpa_ctrl_command(ctrl, "STATUS");
275  }
276  
277  
hostapd_cli_cmd_mib(struct wpa_ctrl * ctrl,int argc,char * argv[])278  static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
279  {
280  	if (argc > 0) {
281  		char buf[100];
282  		os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]);
283  		return wpa_ctrl_command(ctrl, buf);
284  	}
285  	return wpa_ctrl_command(ctrl, "MIB");
286  }
287  
288  
hostapd_cli_exec(const char * program,const char * arg1,const char * arg2)289  static int hostapd_cli_exec(const char *program, const char *arg1,
290  			    const char *arg2)
291  {
292  	char *arg;
293  	size_t len;
294  	int res;
295  
296  	len = os_strlen(arg1) + os_strlen(arg2) + 2;
297  	arg = os_malloc(len);
298  	if (arg == NULL)
299  		return -1;
300  	os_snprintf(arg, len, "%s %s", arg1, arg2);
301  	res = os_exec(program, arg, 1);
302  	os_free(arg);
303  
304  	return res;
305  }
306  
307  
hostapd_cli_action_process(char * msg,size_t len)308  static void hostapd_cli_action_process(char *msg, size_t len)
309  {
310  	const char *pos;
311  
312  	pos = msg;
313  	if (*pos == '<') {
314  		pos = os_strchr(pos, '>');
315  		if (pos)
316  			pos++;
317  		else
318  			pos = msg;
319  	}
320  
321  	hostapd_cli_exec(action_file, ctrl_ifname, pos);
322  }
323  
324  
hostapd_cli_action_cb(char * msg,size_t len)325  static void hostapd_cli_action_cb(char *msg, size_t len)
326  {
327  	hostapd_cli_action_process(msg, len);
328  }
329  
330  
hostapd_cli_cmd_sta(struct wpa_ctrl * ctrl,int argc,char * argv[])331  static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
332  {
333  	char buf[64];
334  	if (argc < 1) {
335  		printf("Invalid 'sta' command - at least one argument, STA "
336  		       "address, is required.\n");
337  		return -1;
338  	}
339  	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]);
343  	return wpa_ctrl_command(ctrl, buf);
344  }
345  
346  
hostapd_complete_stations(const char * str,int pos)347  static char ** hostapd_complete_stations(const char *str, int pos)
348  {
349  	int arg = get_cmd_arg_num(str, pos);
350  	char **res = NULL;
351  
352  	switch (arg) {
353  	case 1:
354  		res = cli_txt_list_array(&stations);
355  		break;
356  	}
357  
358  	return res;
359  }
360  
361  
hostapd_cli_cmd_new_sta(struct wpa_ctrl * ctrl,int argc,char * argv[])362  static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
363  				   char *argv[])
364  {
365  	char buf[64];
366  	if (argc != 1) {
367  		printf("Invalid 'new_sta' command - exactly one argument, STA "
368  		       "address, is required.\n");
369  		return -1;
370  	}
371  	snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
372  	return wpa_ctrl_command(ctrl, buf);
373  }
374  
375  
hostapd_cli_cmd_deauthenticate(struct wpa_ctrl * ctrl,int argc,char * argv[])376  static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
377  					  char *argv[])
378  {
379  	char buf[64];
380  	if (argc < 1) {
381  		printf("Invalid 'deauthenticate' command - exactly one "
382  		       "argument, STA address, is required.\n");
383  		return -1;
384  	}
385  	if (argc > 1)
386  		os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
387  			    argv[0], argv[1]);
388  	else
389  		os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
390  	return wpa_ctrl_command(ctrl, buf);
391  }
392  
393  
hostapd_cli_cmd_disassociate(struct wpa_ctrl * ctrl,int argc,char * argv[])394  static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
395  					char *argv[])
396  {
397  	char buf[64];
398  	if (argc < 1) {
399  		printf("Invalid 'disassociate' command - exactly one "
400  		       "argument, STA address, is required.\n");
401  		return -1;
402  	}
403  	if (argc > 1)
404  		os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
405  			    argv[0], argv[1]);
406  	else
407  		os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
408  	return wpa_ctrl_command(ctrl, buf);
409  }
410  
411  
412  #ifdef CONFIG_TAXONOMY
hostapd_cli_cmd_signature(struct wpa_ctrl * ctrl,int argc,char * argv[])413  static int hostapd_cli_cmd_signature(struct wpa_ctrl *ctrl, int argc,
414  				     char *argv[])
415  {
416  	char buf[64];
417  
418  	if (argc != 1) {
419  		printf("Invalid 'signature' command - exactly one argument, STA address, is required.\n");
420  		return -1;
421  	}
422  	os_snprintf(buf, sizeof(buf), "SIGNATURE %s", argv[0]);
423  	return wpa_ctrl_command(ctrl, buf);
424  }
425  #endif /* CONFIG_TAXONOMY */
426  
427  
hostapd_cli_cmd_sa_query(struct wpa_ctrl * ctrl,int argc,char * argv[])428  static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
429  				    char *argv[])
430  {
431  	char buf[64];
432  	if (argc != 1) {
433  		printf("Invalid 'sa_query' command - exactly one argument, "
434  		       "STA address, is required.\n");
435  		return -1;
436  	}
437  	snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
438  	return wpa_ctrl_command(ctrl, buf);
439  }
440  
441  
442  #ifdef CONFIG_WPS
hostapd_cli_cmd_wps_pin(struct wpa_ctrl * ctrl,int argc,char * argv[])443  static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
444  				   char *argv[])
445  {
446  	char buf[256];
447  	if (argc < 2) {
448  		printf("Invalid 'wps_pin' command - at least two arguments, "
449  		       "UUID and PIN, are required.\n");
450  		return -1;
451  	}
452  	if (argc > 3)
453  		snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
454  			 argv[0], argv[1], argv[2], argv[3]);
455  	else if (argc > 2)
456  		snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
457  			 argv[0], argv[1], argv[2]);
458  	else
459  		snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
460  	return wpa_ctrl_command(ctrl, buf);
461  }
462  
463  
hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl * ctrl,int argc,char * argv[])464  static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
465  					 char *argv[])
466  {
467  	char cmd[256];
468  	int res;
469  
470  	if (argc != 1 && argc != 2) {
471  		printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
472  		       "- PIN to be verified\n");
473  		return -1;
474  	}
475  
476  	if (argc == 2)
477  		res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
478  				  argv[0], argv[1]);
479  	else
480  		res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
481  				  argv[0]);
482  	if (os_snprintf_error(sizeof(cmd), res)) {
483  		printf("Too long WPS_CHECK_PIN command.\n");
484  		return -1;
485  	}
486  	return wpa_ctrl_command(ctrl, cmd);
487  }
488  
489  
hostapd_cli_cmd_wps_pbc(struct wpa_ctrl * ctrl,int argc,char * argv[])490  static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
491  				   char *argv[])
492  {
493  	return wpa_ctrl_command(ctrl, "WPS_PBC");
494  }
495  
496  
hostapd_cli_cmd_wps_cancel(struct wpa_ctrl * ctrl,int argc,char * argv[])497  static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
498  				      char *argv[])
499  {
500  	return wpa_ctrl_command(ctrl, "WPS_CANCEL");
501  }
502  
503  
504  #ifdef CONFIG_WPS_NFC
hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl * ctrl,int argc,char * argv[])505  static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
506  					    char *argv[])
507  {
508  	int ret;
509  	char *buf;
510  	size_t buflen;
511  
512  	if (argc != 1) {
513  		printf("Invalid 'wps_nfc_tag_read' command - one argument "
514  		       "is required.\n");
515  		return -1;
516  	}
517  
518  	buflen = 18 + os_strlen(argv[0]);
519  	buf = os_malloc(buflen);
520  	if (buf == NULL)
521  		return -1;
522  	os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
523  
524  	ret = wpa_ctrl_command(ctrl, buf);
525  	os_free(buf);
526  
527  	return ret;
528  }
529  
530  
hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl * ctrl,int argc,char * argv[])531  static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
532  						int argc, char *argv[])
533  {
534  	char cmd[64];
535  	int res;
536  
537  	if (argc != 1) {
538  		printf("Invalid 'wps_nfc_config_token' command - one argument "
539  		       "is required.\n");
540  		return -1;
541  	}
542  
543  	res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
544  			  argv[0]);
545  	if (os_snprintf_error(sizeof(cmd), res)) {
546  		printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
547  		return -1;
548  	}
549  	return wpa_ctrl_command(ctrl, cmd);
550  }
551  
552  
hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl * ctrl,int argc,char * argv[])553  static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
554  					 int argc, char *argv[])
555  {
556  	char cmd[64];
557  	int res;
558  
559  	if (argc != 1) {
560  		printf("Invalid 'wps_nfc_token' command - one argument is "
561  		       "required.\n");
562  		return -1;
563  	}
564  
565  	res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
566  	if (os_snprintf_error(sizeof(cmd), res)) {
567  		printf("Too long WPS_NFC_TOKEN command.\n");
568  		return -1;
569  	}
570  	return wpa_ctrl_command(ctrl, cmd);
571  }
572  
573  
hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl * ctrl,int argc,char * argv[])574  static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
575  						int argc, char *argv[])
576  {
577  	char cmd[64];
578  	int res;
579  
580  	if (argc != 2) {
581  		printf("Invalid 'nfc_get_handover_sel' command - two arguments "
582  		       "are required.\n");
583  		return -1;
584  	}
585  
586  	res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
587  			  argv[0], argv[1]);
588  	if (os_snprintf_error(sizeof(cmd), res)) {
589  		printf("Too long NFC_GET_HANDOVER_SEL command.\n");
590  		return -1;
591  	}
592  	return wpa_ctrl_command(ctrl, cmd);
593  }
594  
595  #endif /* CONFIG_WPS_NFC */
596  
597  
hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl * ctrl,int argc,char * argv[])598  static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
599  				      char *argv[])
600  {
601  	char buf[64];
602  	if (argc < 1) {
603  		printf("Invalid 'wps_ap_pin' command - at least one argument "
604  		       "is required.\n");
605  		return -1;
606  	}
607  	if (argc > 2)
608  		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
609  			 argv[0], argv[1], argv[2]);
610  	else if (argc > 1)
611  		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
612  			 argv[0], argv[1]);
613  	else
614  		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
615  	return wpa_ctrl_command(ctrl, buf);
616  }
617  
618  
hostapd_cli_cmd_wps_get_status(struct wpa_ctrl * ctrl,int argc,char * argv[])619  static int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc,
620  					  char *argv[])
621  {
622  	return wpa_ctrl_command(ctrl, "WPS_GET_STATUS");
623  }
624  
625  
hostapd_cli_cmd_wps_config(struct wpa_ctrl * ctrl,int argc,char * argv[])626  static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
627  				      char *argv[])
628  {
629  	char buf[256];
630  	char ssid_hex[2 * SSID_MAX_LEN + 1];
631  	char key_hex[2 * 64 + 1];
632  	int i;
633  
634  	if (argc < 1) {
635  		printf("Invalid 'wps_config' command - at least two arguments "
636  		       "are required.\n");
637  		return -1;
638  	}
639  
640  	ssid_hex[0] = '\0';
641  	for (i = 0; i < SSID_MAX_LEN; i++) {
642  		if (argv[0][i] == '\0')
643  			break;
644  		os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
645  	}
646  
647  	key_hex[0] = '\0';
648  	if (argc > 3) {
649  		for (i = 0; i < 64; i++) {
650  			if (argv[3][i] == '\0')
651  				break;
652  			os_snprintf(&key_hex[i * 2], 3, "%02x",
653  				    argv[3][i]);
654  		}
655  	}
656  
657  	if (argc > 3)
658  		snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
659  			 ssid_hex, argv[1], argv[2], key_hex);
660  	else if (argc > 2)
661  		snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
662  			 ssid_hex, argv[1], argv[2]);
663  	else
664  		snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
665  			 ssid_hex, argv[1]);
666  	return wpa_ctrl_command(ctrl, buf);
667  }
668  #endif /* CONFIG_WPS */
669  
670  
hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl * ctrl,int argc,char * argv[])671  static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
672  					     char *argv[])
673  {
674  	char buf[300];
675  	int res;
676  
677  	if (argc < 2) {
678  		printf("Invalid 'disassoc_imminent' command - two arguments "
679  		       "(STA addr and Disassociation Timer) are needed\n");
680  		return -1;
681  	}
682  
683  	res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
684  			  argv[0], argv[1]);
685  	if (os_snprintf_error(sizeof(buf), res))
686  		return -1;
687  	return wpa_ctrl_command(ctrl, buf);
688  }
689  
690  
hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl * ctrl,int argc,char * argv[])691  static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
692  					char *argv[])
693  {
694  	char buf[300];
695  	int res;
696  
697  	if (argc < 3) {
698  		printf("Invalid 'ess_disassoc' command - three arguments (STA "
699  		       "addr, disassoc timer, and URL) are needed\n");
700  		return -1;
701  	}
702  
703  	res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
704  			  argv[0], argv[1], argv[2]);
705  	if (os_snprintf_error(sizeof(buf), res))
706  		return -1;
707  	return wpa_ctrl_command(ctrl, buf);
708  }
709  
710  
hostapd_cli_cmd_bss_tm_req(struct wpa_ctrl * ctrl,int argc,char * argv[])711  static int hostapd_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc,
712  				      char *argv[])
713  {
714  	char buf[2000], *tmp;
715  	int res, i, total;
716  
717  	if (argc < 1) {
718  		printf("Invalid 'bss_tm_req' command - at least one argument (STA addr) is needed\n");
719  		return -1;
720  	}
721  
722  	res = os_snprintf(buf, sizeof(buf), "BSS_TM_REQ %s", argv[0]);
723  	if (os_snprintf_error(sizeof(buf), res))
724  		return -1;
725  
726  	total = res;
727  	for (i = 1; i < argc; i++) {
728  		tmp = &buf[total];
729  		res = os_snprintf(tmp, sizeof(buf) - total, " %s", argv[i]);
730  		if (os_snprintf_error(sizeof(buf) - total, res))
731  			return -1;
732  		total += res;
733  	}
734  	return wpa_ctrl_command(ctrl, buf);
735  }
736  
737  
hostapd_cli_cmd_get_config(struct wpa_ctrl * ctrl,int argc,char * argv[])738  static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
739  				      char *argv[])
740  {
741  	return wpa_ctrl_command(ctrl, "GET_CONFIG");
742  }
743  
744  
wpa_ctrl_command_sta(struct wpa_ctrl * ctrl,const char * cmd,char * addr,size_t addr_len,int print)745  static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, const char *cmd,
746  				char *addr, size_t addr_len, int print)
747  {
748  	char buf[4096], *pos;
749  	size_t len;
750  	int ret;
751  
752  	if (ctrl_conn == NULL) {
753  		printf("Not connected to hostapd - command dropped.\n");
754  		return -1;
755  	}
756  	len = sizeof(buf) - 1;
757  	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
758  			       hostapd_cli_msg_cb);
759  	if (ret == -2) {
760  		printf("'%s' command timed out.\n", cmd);
761  		return -2;
762  	} else if (ret < 0) {
763  		printf("'%s' command failed.\n", cmd);
764  		return -1;
765  	}
766  
767  	buf[len] = '\0';
768  	if (memcmp(buf, "FAIL", 4) == 0)
769  		return -1;
770  	if (print)
771  		printf("%s", buf);
772  
773  	pos = buf;
774  	while (*pos != '\0' && *pos != '\n')
775  		pos++;
776  	*pos = '\0';
777  	os_strlcpy(addr, buf, addr_len);
778  	return 0;
779  }
780  
781  
hostapd_cli_cmd_all_sta(struct wpa_ctrl * ctrl,int argc,char * argv[])782  static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
783  				   char *argv[])
784  {
785  	char addr[32], cmd[64];
786  
787  	if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 1))
788  		return 0;
789  	do {
790  		snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
791  	} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 1) == 0);
792  
793  	return -1;
794  }
795  
796  
hostapd_cli_cmd_list_sta(struct wpa_ctrl * ctrl,int argc,char * argv[])797  static int hostapd_cli_cmd_list_sta(struct wpa_ctrl *ctrl, int argc,
798  				    char *argv[])
799  {
800  	char addr[32], cmd[64];
801  
802  	if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0))
803  		return 0;
804  	do {
805  		if (os_strcmp(addr, "") != 0)
806  			printf("%s\n", addr);
807  		os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
808  	} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0);
809  
810  	return 0;
811  }
812  
813  
hostapd_cli_cmd_help(struct wpa_ctrl * ctrl,int argc,char * argv[])814  static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
815  {
816  	print_help(stdout, argc > 0 ? argv[0] : NULL);
817  	return 0;
818  }
819  
820  
hostapd_cli_complete_help(const char * str,int pos)821  static char ** hostapd_cli_complete_help(const char *str, int pos)
822  {
823  	int arg = get_cmd_arg_num(str, pos);
824  	char **res = NULL;
825  
826  	switch (arg) {
827  	case 1:
828  		res = list_cmd_list();
829  		break;
830  	}
831  
832  	return res;
833  }
834  
835  
hostapd_cli_cmd_license(struct wpa_ctrl * ctrl,int argc,char * argv[])836  static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
837  				   char *argv[])
838  {
839  	printf("%s\n\n%s\n", hostapd_cli_version, cli_full_license);
840  	return 0;
841  }
842  
843  
hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl * ctrl,int argc,char * argv[])844  static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl,
845  					   int argc, char *argv[])
846  {
847  	char buf[200];
848  	int res;
849  
850  	if (argc != 1) {
851  		printf("Invalid 'set_qos_map_set' command - "
852  		       "one argument (comma delimited QoS map set) "
853  		       "is needed\n");
854  		return -1;
855  	}
856  
857  	res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
858  	if (os_snprintf_error(sizeof(buf), res))
859  		return -1;
860  	return wpa_ctrl_command(ctrl, buf);
861  }
862  
863  
hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl * ctrl,int argc,char * argv[])864  static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
865  					     int argc, char *argv[])
866  {
867  	char buf[50];
868  	int res;
869  
870  	if (argc != 1) {
871  		printf("Invalid 'send_qos_map_conf' command - "
872  		       "one argument (STA addr) is needed\n");
873  		return -1;
874  	}
875  
876  	res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
877  	if (os_snprintf_error(sizeof(buf), res))
878  		return -1;
879  	return wpa_ctrl_command(ctrl, buf);
880  }
881  
882  
hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl * ctrl,int argc,char * argv[])883  static int hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc,
884  					  char *argv[])
885  {
886  	char buf[300];
887  	int res;
888  
889  	if (argc < 2) {
890  		printf("Invalid 'hs20_wnm_notif' command - two arguments (STA "
891  		       "addr and URL) are needed\n");
892  		return -1;
893  	}
894  
895  	res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s",
896  			  argv[0], argv[1]);
897  	if (os_snprintf_error(sizeof(buf), res))
898  		return -1;
899  	return wpa_ctrl_command(ctrl, buf);
900  }
901  
902  
hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl * ctrl,int argc,char * argv[])903  static int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc,
904  					   char *argv[])
905  {
906  	char buf[300];
907  	int res;
908  
909  	if (argc < 3) {
910  		printf("Invalid 'hs20_deauth_req' command - at least three arguments (STA addr, Code, Re-auth Delay) are needed\n");
911  		return -1;
912  	}
913  
914  	if (argc > 3)
915  		res = os_snprintf(buf, sizeof(buf),
916  				  "HS20_DEAUTH_REQ %s %s %s %s",
917  				  argv[0], argv[1], argv[2], argv[3]);
918  	else
919  		res = os_snprintf(buf, sizeof(buf),
920  				  "HS20_DEAUTH_REQ %s %s %s",
921  				  argv[0], argv[1], argv[2]);
922  	if (os_snprintf_error(sizeof(buf), res))
923  		return -1;
924  	return wpa_ctrl_command(ctrl, buf);
925  }
926  
927  
hostapd_cli_cmd_quit(struct wpa_ctrl * ctrl,int argc,char * argv[])928  static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
929  {
930  	hostapd_cli_quit = 1;
931  	if (interactive)
932  		eloop_terminate();
933  	return 0;
934  }
935  
936  
hostapd_cli_cmd_level(struct wpa_ctrl * ctrl,int argc,char * argv[])937  static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
938  {
939  	char cmd[256];
940  	if (argc != 1) {
941  		printf("Invalid LEVEL command: needs one argument (debug "
942  		       "level)\n");
943  		return 0;
944  	}
945  	snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
946  	return wpa_ctrl_command(ctrl, cmd);
947  }
948  
949  
update_stations(struct wpa_ctrl * ctrl)950  static void update_stations(struct wpa_ctrl *ctrl)
951  {
952  	char addr[32], cmd[64];
953  
954  	if (!ctrl || !interactive)
955  		return;
956  
957  	cli_txt_list_flush(&stations);
958  
959  	if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0))
960  		return;
961  	do {
962  		if (os_strcmp(addr, "") != 0)
963  			cli_txt_list_add(&stations, addr);
964  		os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
965  	} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0);
966  }
967  
968  
hostapd_cli_get_interfaces(struct wpa_ctrl * ctrl,struct dl_list * interfaces)969  static void hostapd_cli_get_interfaces(struct wpa_ctrl *ctrl,
970  				       struct dl_list *interfaces)
971  {
972  	struct dirent *dent;
973  	DIR *dir;
974  
975  	if (!ctrl || !interfaces)
976  		return;
977  	dir = opendir(ctrl_iface_dir);
978  	if (dir == NULL)
979  		return;
980  
981  	while ((dent = readdir(dir))) {
982  		if (strcmp(dent->d_name, ".") == 0 ||
983  		    strcmp(dent->d_name, "..") == 0)
984  			continue;
985  		cli_txt_list_add(interfaces, dent->d_name);
986  	}
987  	closedir(dir);
988  }
989  
990  
hostapd_cli_list_interfaces(struct wpa_ctrl * ctrl)991  static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
992  {
993  	struct dirent *dent;
994  	DIR *dir;
995  
996  	dir = opendir(ctrl_iface_dir);
997  	if (dir == NULL) {
998  		printf("Control interface directory '%s' could not be "
999  		       "opened.\n", ctrl_iface_dir);
1000  		return;
1001  	}
1002  
1003  	printf("Available interfaces:\n");
1004  	while ((dent = readdir(dir))) {
1005  		if (strcmp(dent->d_name, ".") == 0 ||
1006  		    strcmp(dent->d_name, "..") == 0)
1007  			continue;
1008  		printf("%s\n", dent->d_name);
1009  	}
1010  	closedir(dir);
1011  }
1012  
1013  
hostapd_cli_cmd_interface(struct wpa_ctrl * ctrl,int argc,char * argv[])1014  static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
1015  				     char *argv[])
1016  {
1017  	if (argc < 1) {
1018  		hostapd_cli_list_interfaces(ctrl);
1019  		return 0;
1020  	}
1021  	if (hostapd_cli_reconnect(argv[0]) != 0) {
1022  		printf("Could not connect to interface '%s' - re-trying\n",
1023  			ctrl_ifname);
1024  	}
1025  	return 0;
1026  }
1027  
1028  
hostapd_complete_interface(const char * str,int pos)1029  static char ** hostapd_complete_interface(const char *str, int pos)
1030  {
1031  	int arg = get_cmd_arg_num(str, pos);
1032  	char **res = NULL;
1033  	DEFINE_DL_LIST(interfaces);
1034  
1035  	switch (arg) {
1036  	case 1:
1037  		hostapd_cli_get_interfaces(ctrl_conn, &interfaces);
1038  		res = cli_txt_list_array(&interfaces);
1039  		cli_txt_list_flush(&interfaces);
1040  		break;
1041  	}
1042  
1043  	return res;
1044  }
1045  
1046  
hostapd_cli_cmd_set(struct wpa_ctrl * ctrl,int argc,char * argv[])1047  static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
1048  {
1049  	char cmd[2048];
1050  	int res;
1051  
1052  	if (argc != 2) {
1053  		printf("Invalid SET command: needs two arguments (variable "
1054  		       "name and value)\n");
1055  		return -1;
1056  	}
1057  
1058  	res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
1059  	if (os_snprintf_error(sizeof(cmd), res)) {
1060  		printf("Too long SET command.\n");
1061  		return -1;
1062  	}
1063  	return wpa_ctrl_command(ctrl, cmd);
1064  }
1065  
1066  
hostapd_complete_set(const char * str,int pos)1067  static char ** hostapd_complete_set(const char *str, int pos)
1068  {
1069  	int arg = get_cmd_arg_num(str, pos);
1070  	const char *fields[] = {
1071  #ifdef CONFIG_WPS_TESTING
1072  		"wps_version_number", "wps_testing_stub_cred",
1073  		"wps_corrupt_pkhash",
1074  #endif /* CONFIG_WPS_TESTING */
1075  #ifdef CONFIG_INTERWORKING
1076  		"gas_frag_limit",
1077  #endif /* CONFIG_INTERWORKING */
1078  #ifdef CONFIG_TESTING_OPTIONS
1079  		"ext_mgmt_frame_handling", "ext_eapol_frame_io",
1080  #endif /* CONFIG_TESTING_OPTIONS */
1081  #ifdef CONFIG_MBO
1082  		"mbo_assoc_disallow",
1083  #endif /* CONFIG_MBO */
1084  		"deny_mac_file", "accept_mac_file",
1085  	};
1086  	int i, num_fields = ARRAY_SIZE(fields);
1087  
1088  	if (arg == 1) {
1089  		char **res;
1090  
1091  		res = os_calloc(num_fields + 1, sizeof(char *));
1092  		if (!res)
1093  			return NULL;
1094  		for (i = 0; i < num_fields; i++) {
1095  			res[i] = os_strdup(fields[i]);
1096  			if (!res[i])
1097  				return res;
1098  		}
1099  		return res;
1100  	}
1101  	return NULL;
1102  }
1103  
1104  
hostapd_cli_cmd_get(struct wpa_ctrl * ctrl,int argc,char * argv[])1105  static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
1106  {
1107  	char cmd[256];
1108  	int res;
1109  
1110  	if (argc != 1) {
1111  		printf("Invalid GET command: needs one argument (variable "
1112  		       "name)\n");
1113  		return -1;
1114  	}
1115  
1116  	res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
1117  	if (os_snprintf_error(sizeof(cmd), res)) {
1118  		printf("Too long GET command.\n");
1119  		return -1;
1120  	}
1121  	return wpa_ctrl_command(ctrl, cmd);
1122  }
1123  
1124  
hostapd_complete_get(const char * str,int pos)1125  static char ** hostapd_complete_get(const char *str, int pos)
1126  {
1127  	int arg = get_cmd_arg_num(str, pos);
1128  	const char *fields[] = {
1129  		"version", "tls_library",
1130  	};
1131  	int i, num_fields = ARRAY_SIZE(fields);
1132  
1133  	if (arg == 1) {
1134  		char **res;
1135  
1136  		res = os_calloc(num_fields + 1, sizeof(char *));
1137  		if (!res)
1138  			return NULL;
1139  		for (i = 0; i < num_fields; i++) {
1140  			res[i] = os_strdup(fields[i]);
1141  			if (!res[i])
1142  				return res;
1143  		}
1144  		return res;
1145  	}
1146  	return NULL;
1147  }
1148  
1149  
1150  #ifdef CONFIG_FST
hostapd_cli_cmd_fst(struct wpa_ctrl * ctrl,int argc,char * argv[])1151  static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[])
1152  {
1153  	char cmd[256];
1154  	int res;
1155  	int i;
1156  	int total;
1157  
1158  	if (argc <= 0) {
1159  		printf("FST command: parameters are required.\n");
1160  		return -1;
1161  	}
1162  
1163  	total = os_snprintf(cmd, sizeof(cmd), "FST-MANAGER");
1164  
1165  	for (i = 0; i < argc; i++) {
1166  		res = os_snprintf(cmd + total, sizeof(cmd) - total, " %s",
1167  				  argv[i]);
1168  		if (os_snprintf_error(sizeof(cmd) - total, res)) {
1169  			printf("Too long fst command.\n");
1170  			return -1;
1171  		}
1172  		total += res;
1173  	}
1174  	return wpa_ctrl_command(ctrl, cmd);
1175  }
1176  #endif /* CONFIG_FST */
1177  
1178  
1179  #ifdef CONFIG_IEEE80211AX
hostapd_cli_cmd_color_change(struct wpa_ctrl * ctrl,int argc,char * argv[])1180  static int hostapd_cli_cmd_color_change(struct wpa_ctrl *ctrl,
1181  					int argc, char *argv[])
1182  {
1183  	return hostapd_cli_cmd(ctrl, "COLOR_CHANGE", 1, argc, argv);
1184  }
1185  #endif /* CONFIG_IEEE80211AX */
1186  
1187  
hostapd_cli_cmd_chan_switch(struct wpa_ctrl * ctrl,int argc,char * argv[])1188  static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
1189  				       int argc, char *argv[])
1190  {
1191  	char cmd[256];
1192  	int res;
1193  	int i;
1194  	char *tmp;
1195  	int total;
1196  
1197  	if (argc < 2) {
1198  		printf("Invalid chan_switch command: needs at least two "
1199  		       "arguments (count and freq)\n"
1200  		       "usage: <cs_count> <freq> [sec_channel_offset=] "
1201  		       "[center_freq1=] [center_freq2=] [bandwidth=] "
1202  		       "[blocktx] [ht|vht|he|eht]\n");
1203  		return -1;
1204  	}
1205  
1206  	res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
1207  			  argv[0], argv[1]);
1208  	if (os_snprintf_error(sizeof(cmd), res)) {
1209  		printf("Too long CHAN_SWITCH command.\n");
1210  		return -1;
1211  	}
1212  
1213  	total = res;
1214  	for (i = 2; i < argc; i++) {
1215  		tmp = cmd + total;
1216  		res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
1217  		if (os_snprintf_error(sizeof(cmd) - total, res)) {
1218  			printf("Too long CHAN_SWITCH command.\n");
1219  			return -1;
1220  		}
1221  		total += res;
1222  	}
1223  	return wpa_ctrl_command(ctrl, cmd);
1224  }
1225  
1226  
hostapd_cli_cmd_notify_cw_change(struct wpa_ctrl * ctrl,int argc,char * argv[])1227  static int hostapd_cli_cmd_notify_cw_change(struct wpa_ctrl *ctrl,
1228  					    int argc, char *argv[])
1229  {
1230  	return hostapd_cli_cmd(ctrl, "NOTIFY_CW_CHANGE", 1, argc, argv);
1231  }
1232  
1233  
hostapd_cli_cmd_enable(struct wpa_ctrl * ctrl,int argc,char * argv[])1234  static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc,
1235  				  char *argv[])
1236  {
1237  	return wpa_ctrl_command(ctrl, "ENABLE");
1238  }
1239  
1240  
hostapd_cli_cmd_reload(struct wpa_ctrl * ctrl,int argc,char * argv[])1241  static int hostapd_cli_cmd_reload(struct wpa_ctrl *ctrl, int argc,
1242  				  char *argv[])
1243  {
1244  	return wpa_ctrl_command(ctrl, "RELOAD");
1245  }
1246  
1247  
hostapd_cli_cmd_reload_bss(struct wpa_ctrl * ctrl,int argc,char * argv[])1248  static int hostapd_cli_cmd_reload_bss(struct wpa_ctrl *ctrl, int argc,
1249  				      char *argv[])
1250  {
1251  	return wpa_ctrl_command(ctrl, "RELOAD_BSS");
1252  }
1253  
1254  
hostapd_cli_cmd_reload_config(struct wpa_ctrl * ctrl,int argc,char * argv[])1255  static int hostapd_cli_cmd_reload_config(struct wpa_ctrl *ctrl, int argc,
1256  					 char *argv[])
1257  {
1258  	return wpa_ctrl_command(ctrl, "RELOAD_CONFIG");
1259  }
1260  
1261  
hostapd_cli_cmd_disable(struct wpa_ctrl * ctrl,int argc,char * argv[])1262  static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc,
1263  				   char *argv[])
1264  {
1265  	return wpa_ctrl_command(ctrl, "DISABLE");
1266  }
1267  
1268  
hostapd_cli_cmd_enable_mld(struct wpa_ctrl * ctrl,int argc,char * argv[])1269  static int hostapd_cli_cmd_enable_mld(struct wpa_ctrl *ctrl, int argc,
1270  				      char *argv[])
1271  {
1272  	return wpa_ctrl_command(ctrl, "ENABLE_MLD");
1273  }
1274  
1275  
hostapd_cli_cmd_disable_mld(struct wpa_ctrl * ctrl,int argc,char * argv[])1276  static int hostapd_cli_cmd_disable_mld(struct wpa_ctrl *ctrl, int argc,
1277  				       char *argv[])
1278  {
1279  	return wpa_ctrl_command(ctrl, "DISABLE_MLD");
1280  }
1281  
1282  
hostapd_cli_cmd_update_beacon(struct wpa_ctrl * ctrl,int argc,char * argv[])1283  static int hostapd_cli_cmd_update_beacon(struct wpa_ctrl *ctrl, int argc,
1284  					 char *argv[])
1285  {
1286  	return wpa_ctrl_command(ctrl, "UPDATE_BEACON");
1287  }
1288  
1289  
hostapd_cli_cmd_stop_ap(struct wpa_ctrl * ctrl,int argc,char * argv[])1290  static int hostapd_cli_cmd_stop_ap(struct wpa_ctrl *ctrl, int argc,
1291  				   char *argv[])
1292  {
1293  	return wpa_ctrl_command(ctrl, "STOP_AP");
1294  }
1295  
1296  
hostapd_cli_cmd_vendor(struct wpa_ctrl * ctrl,int argc,char * argv[])1297  static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
1298  {
1299  	char cmd[256];
1300  	int res;
1301  
1302  	if (argc < 2 || argc > 4) {
1303  		printf("Invalid vendor command\n"
1304  		       "usage: <vendor id> <command id> [<hex formatted command argument>] [nested=<0|1>]\n");
1305  		return -1;
1306  	}
1307  
1308  	res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s%s%s", argv[0],
1309  			  argv[1], argc >= 3 ? argv[2] : "",
1310  			  argc == 4 ? " " : "", argc == 4 ? argv[3] : "");
1311  	if (os_snprintf_error(sizeof(cmd), res)) {
1312  		printf("Too long VENDOR command.\n");
1313  		return -1;
1314  	}
1315  	return wpa_ctrl_command(ctrl, cmd);
1316  }
1317  
1318  
hostapd_cli_cmd_erp_flush(struct wpa_ctrl * ctrl,int argc,char * argv[])1319  static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc,
1320  				     char *argv[])
1321  {
1322  	return wpa_ctrl_command(ctrl, "ERP_FLUSH");
1323  }
1324  
1325  
hostapd_cli_cmd_log_level(struct wpa_ctrl * ctrl,int argc,char * argv[])1326  static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc,
1327  				     char *argv[])
1328  {
1329  	char cmd[256];
1330  	int res;
1331  
1332  	res = os_snprintf(cmd, sizeof(cmd), "LOG_LEVEL%s%s%s%s",
1333  			  argc >= 1 ? " " : "",
1334  			  argc >= 1 ? argv[0] : "",
1335  			  argc == 2 ? " " : "",
1336  			  argc == 2 ? argv[1] : "");
1337  	if (os_snprintf_error(sizeof(cmd), res)) {
1338  		printf("Too long option\n");
1339  		return -1;
1340  	}
1341  	return wpa_ctrl_command(ctrl, cmd);
1342  }
1343  
1344  
hostapd_cli_cmd_raw(struct wpa_ctrl * ctrl,int argc,char * argv[])1345  static int hostapd_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
1346  {
1347  	if (argc == 0)
1348  		return -1;
1349  	return hostapd_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]);
1350  }
1351  
1352  
hostapd_cli_cmd_pmksa(struct wpa_ctrl * ctrl,int argc,char * argv[])1353  static int hostapd_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
1354  {
1355  	return wpa_ctrl_command(ctrl, "PMKSA");
1356  }
1357  
1358  
hostapd_cli_cmd_pmksa_flush(struct wpa_ctrl * ctrl,int argc,char * argv[])1359  static int hostapd_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc,
1360  				       char *argv[])
1361  {
1362  	return wpa_ctrl_command(ctrl, "PMKSA_FLUSH");
1363  }
1364  
1365  
hostapd_cli_cmd_set_neighbor(struct wpa_ctrl * ctrl,int argc,char * argv[])1366  static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc,
1367  					char *argv[])
1368  {
1369  	char cmd[2048];
1370  	int res;
1371  
1372  	if (argc < 3 || argc > 6) {
1373  		printf("Invalid set_neighbor command: needs 3-6 arguments\n");
1374  		return -1;
1375  	}
1376  
1377  	res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s %s",
1378  			  argv[0], argv[1], argv[2], argc >= 4 ? argv[3] : "",
1379  			  argc >= 5 ? argv[4] : "", argc == 6 ? argv[5] : "");
1380  	if (os_snprintf_error(sizeof(cmd), res)) {
1381  		printf("Too long SET_NEIGHBOR command.\n");
1382  		return -1;
1383  	}
1384  	return wpa_ctrl_command(ctrl, cmd);
1385  }
1386  
1387  
hostapd_cli_cmd_show_neighbor(struct wpa_ctrl * ctrl,int argc,char * argv[])1388  static int hostapd_cli_cmd_show_neighbor(struct wpa_ctrl *ctrl, int argc,
1389  					 char *argv[])
1390  {
1391  	return wpa_ctrl_command(ctrl, "SHOW_NEIGHBOR");
1392  }
1393  
1394  
hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl * ctrl,int argc,char * argv[])1395  static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc,
1396  					   char *argv[])
1397  {
1398  	return hostapd_cli_cmd(ctrl, "REMOVE_NEIGHBOR", 1, argc, argv);
1399  }
1400  
1401  
hostapd_cli_cmd_req_lci(struct wpa_ctrl * ctrl,int argc,char * argv[])1402  static int hostapd_cli_cmd_req_lci(struct wpa_ctrl *ctrl, int argc,
1403  				   char *argv[])
1404  {
1405  	char cmd[256];
1406  	int res;
1407  
1408  	if (argc != 1) {
1409  		printf("Invalid req_lci command - requires destination address\n");
1410  		return -1;
1411  	}
1412  
1413  	res = os_snprintf(cmd, sizeof(cmd), "REQ_LCI %s", argv[0]);
1414  	if (os_snprintf_error(sizeof(cmd), res)) {
1415  		printf("Too long REQ_LCI command.\n");
1416  		return -1;
1417  	}
1418  	return wpa_ctrl_command(ctrl, cmd);
1419  }
1420  
1421  
hostapd_cli_cmd_req_range(struct wpa_ctrl * ctrl,int argc,char * argv[])1422  static int hostapd_cli_cmd_req_range(struct wpa_ctrl *ctrl, int argc,
1423  				     char *argv[])
1424  {
1425  	if (argc < 4) {
1426  		printf("Invalid req_range command: needs at least 4 arguments - dest address, randomization interval, min AP count, and 1 to 16 AP addresses\n");
1427  		return -1;
1428  	}
1429  
1430  	return hostapd_cli_cmd(ctrl, "REQ_RANGE", 4, argc, argv);
1431  }
1432  
1433  
hostapd_cli_cmd_driver_flags(struct wpa_ctrl * ctrl,int argc,char * argv[])1434  static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
1435  					char *argv[])
1436  {
1437  	return wpa_ctrl_command(ctrl, "DRIVER_FLAGS");
1438  }
1439  
1440  
hostapd_cli_cmd_driver_flags2(struct wpa_ctrl * ctrl,int argc,char * argv[])1441  static int hostapd_cli_cmd_driver_flags2(struct wpa_ctrl *ctrl, int argc,
1442  					 char *argv[])
1443  {
1444  	return wpa_ctrl_command(ctrl, "DRIVER_FLAGS2");
1445  }
1446  
1447  
1448  #ifdef CONFIG_DPP
1449  
hostapd_cli_cmd_dpp_qr_code(struct wpa_ctrl * ctrl,int argc,char * argv[])1450  static int hostapd_cli_cmd_dpp_qr_code(struct wpa_ctrl *ctrl, int argc,
1451  				       char *argv[])
1452  {
1453  	return hostapd_cli_cmd(ctrl, "DPP_QR_CODE", 1, argc, argv);
1454  }
1455  
1456  
hostapd_cli_cmd_dpp_bootstrap_gen(struct wpa_ctrl * ctrl,int argc,char * argv[])1457  static int hostapd_cli_cmd_dpp_bootstrap_gen(struct wpa_ctrl *ctrl, int argc,
1458  					     char *argv[])
1459  {
1460  	return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_GEN", 1, argc, argv);
1461  }
1462  
1463  
hostapd_cli_cmd_dpp_bootstrap_remove(struct wpa_ctrl * ctrl,int argc,char * argv[])1464  static int hostapd_cli_cmd_dpp_bootstrap_remove(struct wpa_ctrl *ctrl, int argc,
1465  						char *argv[])
1466  {
1467  	return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_REMOVE", 1, argc, argv);
1468  }
1469  
1470  
hostapd_cli_cmd_dpp_bootstrap_get_uri(struct wpa_ctrl * ctrl,int argc,char * argv[])1471  static int hostapd_cli_cmd_dpp_bootstrap_get_uri(struct wpa_ctrl *ctrl,
1472  						 int argc, char *argv[])
1473  {
1474  	return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_GET_URI", 1, argc, argv);
1475  }
1476  
1477  
hostapd_cli_cmd_dpp_bootstrap_info(struct wpa_ctrl * ctrl,int argc,char * argv[])1478  static int hostapd_cli_cmd_dpp_bootstrap_info(struct wpa_ctrl *ctrl, int argc,
1479  					      char *argv[])
1480  {
1481  	return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_INFO", 1, argc, argv);
1482  }
1483  
1484  
hostapd_cli_cmd_dpp_bootstrap_set(struct wpa_ctrl * ctrl,int argc,char * argv[])1485  static int hostapd_cli_cmd_dpp_bootstrap_set(struct wpa_ctrl *ctrl, int argc,
1486  					     char *argv[])
1487  {
1488  	return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_SET", 1, argc, argv);
1489  }
1490  
1491  
hostapd_cli_cmd_dpp_auth_init(struct wpa_ctrl * ctrl,int argc,char * argv[])1492  static int hostapd_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc,
1493  					 char *argv[])
1494  {
1495  	return hostapd_cli_cmd(ctrl, "DPP_AUTH_INIT", 1, argc, argv);
1496  }
1497  
1498  
hostapd_cli_cmd_dpp_listen(struct wpa_ctrl * ctrl,int argc,char * argv[])1499  static int hostapd_cli_cmd_dpp_listen(struct wpa_ctrl *ctrl, int argc,
1500  				      char *argv[])
1501  {
1502  	return hostapd_cli_cmd(ctrl, "DPP_LISTEN", 1, argc, argv);
1503  }
1504  
1505  
hostapd_cli_cmd_dpp_stop_listen(struct wpa_ctrl * ctrl,int argc,char * argv[])1506  static int hostapd_cli_cmd_dpp_stop_listen(struct wpa_ctrl *ctrl, int argc,
1507  				       char *argv[])
1508  {
1509  	return wpa_ctrl_command(ctrl, "DPP_STOP_LISTEN");
1510  }
1511  
1512  
hostapd_cli_cmd_dpp_configurator_add(struct wpa_ctrl * ctrl,int argc,char * argv[])1513  static int hostapd_cli_cmd_dpp_configurator_add(struct wpa_ctrl *ctrl, int argc,
1514  						char *argv[])
1515  {
1516  	return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_ADD", 0, argc, argv);
1517  }
1518  
1519  
hostapd_cli_cmd_dpp_configurator_remove(struct wpa_ctrl * ctrl,int argc,char * argv[])1520  static int hostapd_cli_cmd_dpp_configurator_remove(struct wpa_ctrl *ctrl,
1521  						   int argc, char *argv[])
1522  {
1523  	return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_REMOVE", 1, argc, argv);
1524  }
1525  
1526  
hostapd_cli_cmd_dpp_configurator_get_key(struct wpa_ctrl * ctrl,int argc,char * argv[])1527  static int hostapd_cli_cmd_dpp_configurator_get_key(struct wpa_ctrl *ctrl,
1528  						    int argc, char *argv[])
1529  {
1530  	return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_GET_KEY", 1, argc, argv);
1531  }
1532  
1533  
hostapd_cli_cmd_dpp_configurator_sign(struct wpa_ctrl * ctrl,int argc,char * argv[])1534  static int hostapd_cli_cmd_dpp_configurator_sign(struct wpa_ctrl *ctrl,
1535  						 int argc, char *argv[])
1536  {
1537         return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_SIGN", 1, argc, argv);
1538  }
1539  
1540  
hostapd_cli_cmd_dpp_pkex_add(struct wpa_ctrl * ctrl,int argc,char * argv[])1541  static int hostapd_cli_cmd_dpp_pkex_add(struct wpa_ctrl *ctrl, int argc,
1542  					char *argv[])
1543  {
1544  	return hostapd_cli_cmd(ctrl, "DPP_PKEX_ADD", 1, argc, argv);
1545  }
1546  
1547  
hostapd_cli_cmd_dpp_pkex_remove(struct wpa_ctrl * ctrl,int argc,char * argv[])1548  static int hostapd_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc,
1549  					   char *argv[])
1550  {
1551  	return hostapd_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv);
1552  }
1553  
1554  
1555  #ifdef CONFIG_DPP2
1556  
hostapd_cli_cmd_dpp_controller_start(struct wpa_ctrl * ctrl,int argc,char * argv[])1557  static int hostapd_cli_cmd_dpp_controller_start(struct wpa_ctrl *ctrl, int argc,
1558  						char *argv[])
1559  {
1560  	return hostapd_cli_cmd(ctrl, "DPP_CONTROLLER_START", 0, argc, argv);
1561  }
1562  
1563  
hostapd_cli_cmd_dpp_controller_stop(struct wpa_ctrl * ctrl,int argc,char * argv[])1564  static int hostapd_cli_cmd_dpp_controller_stop(struct wpa_ctrl *ctrl, int argc,
1565  					       char *argv[])
1566  {
1567  	return wpa_ctrl_command(ctrl, "DPP_CONTROLLER_STOP");
1568  }
1569  
1570  
hostapd_cli_cmd_dpp_chirp(struct wpa_ctrl * ctrl,int argc,char * argv[])1571  static int hostapd_cli_cmd_dpp_chirp(struct wpa_ctrl *ctrl, int argc,
1572  				     char *argv[])
1573  {
1574  	return hostapd_cli_cmd(ctrl, "DPP_CHIRP", 1, argc, argv);
1575  }
1576  
1577  
hostapd_cli_cmd_dpp_stop_chirp(struct wpa_ctrl * ctrl,int argc,char * argv[])1578  static int hostapd_cli_cmd_dpp_stop_chirp(struct wpa_ctrl *ctrl, int argc,
1579  					  char *argv[])
1580  {
1581  	return wpa_ctrl_command(ctrl, "DPP_STOP_CHIRP");
1582  }
1583  
1584  #endif /* CONFIG_DPP2 */
1585  
1586  
1587  #ifdef CONFIG_DPP3
hostapd_cli_cmd_dpp_push_button(struct wpa_ctrl * ctrl,int argc,char * argv[])1588  static int hostapd_cli_cmd_dpp_push_button(struct wpa_ctrl *ctrl, int argc,
1589  					   char *argv[])
1590  {
1591  	return hostapd_cli_cmd(ctrl, "DPP_PUSH_BUTTON", 0, argc, argv);
1592  }
1593  #endif /* CONFIG_DPP3 */
1594  #endif /* CONFIG_DPP */
1595  
1596  
hostapd_cli_cmd_accept_macacl(struct wpa_ctrl * ctrl,int argc,char * argv[])1597  static int hostapd_cli_cmd_accept_macacl(struct wpa_ctrl *ctrl, int argc,
1598  					 char *argv[])
1599  {
1600  	return hostapd_cli_cmd(ctrl, "ACCEPT_ACL", 1, argc, argv);
1601  }
1602  
1603  
hostapd_cli_cmd_deny_macacl(struct wpa_ctrl * ctrl,int argc,char * argv[])1604  static int hostapd_cli_cmd_deny_macacl(struct wpa_ctrl *ctrl, int argc,
1605  				       char *argv[])
1606  {
1607  	return hostapd_cli_cmd(ctrl, "DENY_ACL", 1, argc, argv);
1608  }
1609  
1610  
hostapd_cli_cmd_poll_sta(struct wpa_ctrl * ctrl,int argc,char * argv[])1611  static int hostapd_cli_cmd_poll_sta(struct wpa_ctrl *ctrl, int argc,
1612  				    char *argv[])
1613  {
1614  	return hostapd_cli_cmd(ctrl, "POLL_STA", 1, argc, argv);
1615  }
1616  
1617  
hostapd_cli_cmd_req_beacon(struct wpa_ctrl * ctrl,int argc,char * argv[])1618  static int hostapd_cli_cmd_req_beacon(struct wpa_ctrl *ctrl, int argc,
1619  				      char *argv[])
1620  {
1621  	return hostapd_cli_cmd(ctrl, "REQ_BEACON", 2, argc, argv);
1622  }
1623  
1624  
hostapd_cli_cmd_req_link_measurement(struct wpa_ctrl * ctrl,int argc,char * argv[])1625  static int hostapd_cli_cmd_req_link_measurement(struct wpa_ctrl *ctrl, int argc,
1626  						char *argv[])
1627  {
1628  	return hostapd_cli_cmd(ctrl, "REQ_LINK_MEASUREMENT", 1, argc, argv);
1629  }
1630  
1631  
hostapd_cli_cmd_reload_wpa_psk(struct wpa_ctrl * ctrl,int argc,char * argv[])1632  static int hostapd_cli_cmd_reload_wpa_psk(struct wpa_ctrl *ctrl, int argc,
1633  					  char *argv[])
1634  {
1635  	return wpa_ctrl_command(ctrl, "RELOAD_WPA_PSK");
1636  }
1637  
1638  
1639  #ifdef CONFIG_IEEE80211R_AP
1640  
hostapd_cli_cmd_get_rxkhs(struct wpa_ctrl * ctrl,int argc,char * argv[])1641  static int hostapd_cli_cmd_get_rxkhs(struct wpa_ctrl *ctrl, int argc,
1642  				     char *argv[])
1643  {
1644  	return wpa_ctrl_command(ctrl, "GET_RXKHS");
1645  }
1646  
1647  
hostapd_cli_cmd_reload_rxkhs(struct wpa_ctrl * ctrl,int argc,char * argv[])1648  static int hostapd_cli_cmd_reload_rxkhs(struct wpa_ctrl *ctrl, int argc,
1649  					char *argv[])
1650  {
1651  	return wpa_ctrl_command(ctrl, "RELOAD_RXKHS");
1652  }
1653  
1654  #endif /* CONFIG_IEEE80211R_AP */
1655  
1656  
1657  #ifdef ANDROID
hostapd_cli_cmd_driver(struct wpa_ctrl * ctrl,int argc,char * argv[])1658  static int hostapd_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[])
1659  {
1660  	return hostapd_cli_cmd(ctrl, "DRIVER", 1, argc, argv);
1661  }
1662  #endif /* ANDROID */
1663  
1664  
1665  struct hostapd_cli_cmd {
1666  	const char *cmd;
1667  	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
1668  	char ** (*completion)(const char *str, int pos);
1669  	const char *usage;
1670  };
1671  
1672  static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
1673  	{ "ping", hostapd_cli_cmd_ping, NULL,
1674  	  "= pings hostapd" },
1675  	{ "mib", hostapd_cli_cmd_mib, NULL,
1676  	  "= get MIB variables (dot1x, dot11, radius)" },
1677  	{ "relog", hostapd_cli_cmd_relog, NULL,
1678  	  "= reload/truncate debug log output file" },
1679  	{ "close_log", hostapd_cli_cmd_close_log, NULL,
1680  	  "= disable debug log output file" },
1681  	{ "status", hostapd_cli_cmd_status, NULL,
1682  	  "= show interface status info" },
1683  	{ "sta", hostapd_cli_cmd_sta, hostapd_complete_stations,
1684  	  "<addr> = get MIB variables for one station" },
1685  	{ "all_sta", hostapd_cli_cmd_all_sta, NULL,
1686  	   "= get MIB variables for all stations" },
1687  	{ "list_sta", hostapd_cli_cmd_list_sta, NULL,
1688  	   "= list all stations" },
1689  	{ "new_sta", hostapd_cli_cmd_new_sta, NULL,
1690  	  "<addr> = add a new station" },
1691  	{ "deauthenticate", hostapd_cli_cmd_deauthenticate,
1692  	  hostapd_complete_stations,
1693  	  "<addr> = deauthenticate a station" },
1694  	{ "disassociate", hostapd_cli_cmd_disassociate,
1695  	  hostapd_complete_stations,
1696  	  "<addr> = disassociate a station" },
1697  #ifdef CONFIG_TAXONOMY
1698  	{ "signature", hostapd_cli_cmd_signature, hostapd_complete_stations,
1699  	  "<addr> = get taxonomy signature for a station" },
1700  #endif /* CONFIG_TAXONOMY */
1701  	{ "sa_query", hostapd_cli_cmd_sa_query, hostapd_complete_stations,
1702  	  "<addr> = send SA Query to a station" },
1703  #ifdef CONFIG_WPS
1704  	{ "wps_pin", hostapd_cli_cmd_wps_pin, NULL,
1705  	  "<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" },
1706  	{ "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL,
1707  	  "<PIN> = verify PIN checksum" },
1708  	{ "wps_pbc", hostapd_cli_cmd_wps_pbc, NULL,
1709  	  "= indicate button pushed to initiate PBC" },
1710  	{ "wps_cancel", hostapd_cli_cmd_wps_cancel, NULL,
1711  	  "= cancel the pending WPS operation" },
1712  #ifdef CONFIG_WPS_NFC
1713  	{ "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read, NULL,
1714  	  "<hexdump> = report read NFC tag with WPS data" },
1715  	{ "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token, NULL,
1716  	  "<WPS/NDEF> = build NFC configuration token" },
1717  	{ "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token, NULL,
1718  	  "<WPS/NDEF/enable/disable> = manager NFC password token" },
1719  	{ "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel, NULL,
1720  	  NULL },
1721  #endif /* CONFIG_WPS_NFC */
1722  	{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin, NULL,
1723  	  "<cmd> [params..] = enable/disable AP PIN" },
1724  	{ "wps_config", hostapd_cli_cmd_wps_config, NULL,
1725  	  "<SSID> <auth> <encr> <key> = configure AP" },
1726  	{ "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL,
1727  	  "= show current WPS status" },
1728  #endif /* CONFIG_WPS */
1729  	{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL,
1730  	  "= send Disassociation Imminent notification" },
1731  	{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL,
1732  	  "= send ESS Dissassociation Imminent notification" },
1733  	{ "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL,
1734  	  "= send BSS Transition Management Request" },
1735  	{ "get_config", hostapd_cli_cmd_get_config, NULL,
1736  	  "= show current configuration" },
1737  	{ "help", hostapd_cli_cmd_help, hostapd_cli_complete_help,
1738  	  "= show this usage help" },
1739  	{ "interface", hostapd_cli_cmd_interface, hostapd_complete_interface,
1740  	  "[ifname] = show interfaces/select interface" },
1741  #ifdef CONFIG_FST
1742  	{ "fst", hostapd_cli_cmd_fst, NULL,
1743  	  "<params...> = send FST-MANAGER control interface command" },
1744  #endif /* CONFIG_FST */
1745  	{ "raw", hostapd_cli_cmd_raw, NULL,
1746  	  "<params..> = send unprocessed command" },
1747  	{ "level", hostapd_cli_cmd_level, NULL,
1748  	  "<debug level> = change debug level" },
1749  	{ "license", hostapd_cli_cmd_license, NULL,
1750  	  "= show full hostapd_cli license" },
1751  	{ "quit", hostapd_cli_cmd_quit, NULL,
1752  	  "= exit hostapd_cli" },
1753  	{ "set", hostapd_cli_cmd_set, hostapd_complete_set,
1754  	  "<name> <value> = set runtime variables" },
1755  	{ "get", hostapd_cli_cmd_get, hostapd_complete_get,
1756  	  "<name> = get runtime info" },
1757  	{ "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL,
1758  	  "<arg,arg,...> = set QoS Map set element" },
1759  	{ "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf,
1760  	  hostapd_complete_stations,
1761  	  "<addr> = send QoS Map Configure frame" },
1762  	{ "chan_switch", hostapd_cli_cmd_chan_switch, NULL,
1763  	  "<cs_count> <freq> [sec_channel_offset=] [center_freq1=]\n"
1764  	  "  [center_freq2=] [bandwidth=] [blocktx] [ht|vht]\n"
1765  	  "  = initiate channel switch announcement" },
1766  #ifdef CONFIG_IEEE80211AX
1767  	{ "color_change", hostapd_cli_cmd_color_change, NULL,
1768  	  "<color> = initiate BSS color change to set the specified color\n"
1769  	  "Value 0 will disable the color.\n"},
1770  #endif /* CONFIG_IEEE80211AX */
1771  	{ "notify_cw_change", hostapd_cli_cmd_notify_cw_change, NULL,
1772  	  "<channel_width> = 0 - 20 MHz, 1 - 40 MHz, 2 - 80 MHz, 3 - 160 MHz" },
1773  	{ "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL,
1774  	  "<addr> <url>\n"
1775  	  "  = send WNM-Notification Subscription Remediation Request" },
1776  	{ "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL,
1777  	  "<addr> <code (0/1)> <Re-auth-Delay(sec)> [url]\n"
1778  	  "  = send WNM-Notification imminent deauthentication indication" },
1779  	{ "vendor", hostapd_cli_cmd_vendor, NULL,
1780  	  "<vendor id> <sub command id> [<hex formatted data>]\n"
1781  	  "  = send vendor driver command" },
1782  	{ "enable", hostapd_cli_cmd_enable, NULL,
1783  	  "= enable hostapd on current interface" },
1784  	{ "reload", hostapd_cli_cmd_reload, NULL,
1785  	  "= reload configuration for current interface" },
1786  	{ "reload_bss", hostapd_cli_cmd_reload_bss, NULL,
1787  	  "= reload configuration for current BSS" },
1788  	{ "reload_config", hostapd_cli_cmd_reload_config, NULL,
1789  	  "= reload configuration for current interface" },
1790  	{ "disable", hostapd_cli_cmd_disable, NULL,
1791  	  "= disable hostapd on current interface" },
1792  	{ "enable_mld", hostapd_cli_cmd_enable_mld, NULL,
1793  	  "= enable AP MLD to which the interface is affiliated" },
1794  	{ "disable_mld", hostapd_cli_cmd_disable_mld, NULL,
1795  	  "= disable AP MLD to which the interface is affiliated" },
1796  	{ "update_beacon", hostapd_cli_cmd_update_beacon, NULL,
1797  	  "= update Beacon frame contents\n"},
1798  	{ "stop_ap", hostapd_cli_cmd_stop_ap, NULL,
1799  	  "= stop AP\n"},
1800  	{ "erp_flush", hostapd_cli_cmd_erp_flush, NULL,
1801  	  "= drop all ERP keys"},
1802  	{ "log_level", hostapd_cli_cmd_log_level, NULL,
1803  	  "[level] = show/change log verbosity level" },
1804  	{ "pmksa", hostapd_cli_cmd_pmksa, NULL,
1805  	  " = show PMKSA cache entries" },
1806  	{ "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL,
1807  	  " = flush PMKSA cache" },
1808  	{ "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL,
1809  	  "<addr> <ssid=> <nr=> [lci=] [civic=] [stat]\n"
1810  	  "  = add AP to neighbor database" },
1811  	{ "show_neighbor", hostapd_cli_cmd_show_neighbor, NULL,
1812  	  "  = show neighbor database entries" },
1813  	{ "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL,
1814  	  "<addr> [ssid=<hex>] = remove AP from neighbor database" },
1815  	{ "req_lci", hostapd_cli_cmd_req_lci, hostapd_complete_stations,
1816  	  "<addr> = send LCI request to a station"},
1817  	{ "req_range", hostapd_cli_cmd_req_range, NULL,
1818  	  " = send FTM range request"},
1819  	{ "driver_flags", hostapd_cli_cmd_driver_flags, NULL,
1820  	  " = show supported driver flags"},
1821  	{ "driver_flags2", hostapd_cli_cmd_driver_flags2, NULL,
1822  	  " = show supported driver flags2"},
1823  #ifdef CONFIG_DPP
1824  	{ "dpp_qr_code", hostapd_cli_cmd_dpp_qr_code, NULL,
1825  	  "report a scanned DPP URI from a QR Code" },
1826  	{ "dpp_bootstrap_gen", hostapd_cli_cmd_dpp_bootstrap_gen, NULL,
1827  	  "type=<qrcode> [chan=..] [mac=..] [info=..] [curve=..] [key=..] = generate DPP bootstrap information" },
1828  	{ "dpp_bootstrap_remove", hostapd_cli_cmd_dpp_bootstrap_remove, NULL,
1829  	  "*|<id> = remove DPP bootstrap information" },
1830  	{ "dpp_bootstrap_get_uri", hostapd_cli_cmd_dpp_bootstrap_get_uri, NULL,
1831  	  "<id> = get DPP bootstrap URI" },
1832  	{ "dpp_bootstrap_info", hostapd_cli_cmd_dpp_bootstrap_info, NULL,
1833  	  "<id> = show DPP bootstrap information" },
1834  	{ "dpp_bootstrap_set", hostapd_cli_cmd_dpp_bootstrap_set, NULL,
1835  	  "<id> [conf=..] [ssid=<SSID>] [ssid_charset=#] [psk=<PSK>] [pass=<passphrase>] [configurator=<id>] [conn_status=#] [akm_use_selector=<0|1>] [group_id=..] [expiry=#] [csrattrs=..] = set DPP configurator parameters" },
1836  	{ "dpp_auth_init", hostapd_cli_cmd_dpp_auth_init, NULL,
1837  	  "peer=<id> [own=<id>] = initiate DPP bootstrapping" },
1838  	{ "dpp_listen", hostapd_cli_cmd_dpp_listen, NULL,
1839  	  "<freq in MHz> = start DPP listen" },
1840  	{ "dpp_stop_listen", hostapd_cli_cmd_dpp_stop_listen, NULL,
1841  	  "= stop DPP listen" },
1842  	{ "dpp_configurator_add", hostapd_cli_cmd_dpp_configurator_add, NULL,
1843  	  "[curve=..] [key=..] = add DPP configurator" },
1844  	{ "dpp_configurator_remove", hostapd_cli_cmd_dpp_configurator_remove,
1845  	  NULL,
1846  	  "*|<id> = remove DPP configurator" },
1847  	{ "dpp_configurator_get_key", hostapd_cli_cmd_dpp_configurator_get_key,
1848  	  NULL,
1849  	  "<id> = Get DPP configurator's private key" },
1850  	{ "dpp_configurator_sign", hostapd_cli_cmd_dpp_configurator_sign, NULL,
1851  	  "conf=<role> configurator=<id> = generate self DPP configuration" },
1852  	{ "dpp_pkex_add", hostapd_cli_cmd_dpp_pkex_add, NULL,
1853  	  "add PKEX code" },
1854  	{ "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL,
1855  	  "*|<id> = remove DPP pkex information" },
1856  #ifdef CONFIG_DPP2
1857  	{ "dpp_controller_start", hostapd_cli_cmd_dpp_controller_start, NULL,
1858  	  "[tcp_port=<port>] [role=..] = start DPP controller" },
1859  	{ "dpp_controller_stop", hostapd_cli_cmd_dpp_controller_stop, NULL,
1860  	  "= stop DPP controller" },
1861  	{ "dpp_chirp", hostapd_cli_cmd_dpp_chirp, NULL,
1862  	  "own=<BI ID> iter=<count> = start DPP chirp" },
1863  	{ "dpp_stop_chirp", hostapd_cli_cmd_dpp_stop_chirp, NULL,
1864  	  "= stop DPP chirp" },
1865  #endif /* CONFIG_DPP2 */
1866  #ifdef CONFIG_DPP3
1867  	{ "dpp_push_button", hostapd_cli_cmd_dpp_push_button, NULL,
1868  	  "= press DPP push button" },
1869  #endif /* CONFIG_DPP3 */
1870  #endif /* CONFIG_DPP */
1871  	{ "accept_acl", hostapd_cli_cmd_accept_macacl, NULL,
1872  	  "=Add/Delete/Show/Clear accept MAC ACL" },
1873  	{ "deny_acl", hostapd_cli_cmd_deny_macacl, NULL,
1874  	  "=Add/Delete/Show/Clear deny MAC ACL" },
1875  	{ "poll_sta", hostapd_cli_cmd_poll_sta, hostapd_complete_stations,
1876  	  "<addr> = poll a STA to check connectivity with a QoS null frame" },
1877  	{ "req_beacon", hostapd_cli_cmd_req_beacon, NULL,
1878  	  "<addr> [req_mode=] <measurement request hexdump>  = send a Beacon report request to a station" },
1879  	{ "req_link_measurement", hostapd_cli_cmd_req_link_measurement, NULL,
1880  	  "<addr> = send a link measurement report request to a station"},
1881  	{ "reload_wpa_psk", hostapd_cli_cmd_reload_wpa_psk, NULL,
1882  	  "= reload wpa_psk_file only" },
1883  #ifdef CONFIG_IEEE80211R_AP
1884  	{ "reload_rxkhs", hostapd_cli_cmd_reload_rxkhs, NULL,
1885  	  "= reload R0KHs and R1KHs" },
1886  	{ "get_rxkhs", hostapd_cli_cmd_get_rxkhs, NULL,
1887  	  "= get R0KHs and R1KHs" },
1888  #endif /* CONFIG_IEEE80211R_AP */
1889  #ifdef ANDROID
1890  	{ "driver", hostapd_cli_cmd_driver, NULL,
1891  	  "<driver sub command> [<hex formatted data>] = send driver command data" },
1892  #endif /* ANDROID */
1893  	{ NULL, NULL, NULL, NULL }
1894  };
1895  
1896  
1897  /*
1898   * Prints command usage, lines are padded with the specified string.
1899   */
print_cmd_help(FILE * stream,const struct hostapd_cli_cmd * cmd,const char * pad)1900  static void print_cmd_help(FILE *stream, const struct hostapd_cli_cmd *cmd,
1901  			   const char *pad)
1902  {
1903  	char c;
1904  	size_t n;
1905  
1906  	if (cmd->usage == NULL)
1907  		return;
1908  	fprintf(stream, "%s%s ", pad, cmd->cmd);
1909  	for (n = 0; (c = cmd->usage[n]); n++) {
1910  		fprintf(stream, "%c", c);
1911  		if (c == '\n')
1912  			fprintf(stream, "%s", pad);
1913  	}
1914  	fprintf(stream, "\n");
1915  }
1916  
1917  
print_help(FILE * stream,const char * cmd)1918  static void print_help(FILE *stream, const char *cmd)
1919  {
1920  	int n;
1921  
1922  	fprintf(stream, "commands:\n");
1923  	for (n = 0; hostapd_cli_commands[n].cmd; n++) {
1924  		if (cmd == NULL || str_starts(hostapd_cli_commands[n].cmd, cmd))
1925  			print_cmd_help(stream, &hostapd_cli_commands[n], "  ");
1926  	}
1927  }
1928  
1929  
wpa_request(struct wpa_ctrl * ctrl,int argc,char * argv[])1930  static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
1931  {
1932  	const struct hostapd_cli_cmd *cmd, *match = NULL;
1933  	int count;
1934  
1935  	count = 0;
1936  	cmd = hostapd_cli_commands;
1937  	while (cmd->cmd) {
1938  		if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
1939  			match = cmd;
1940  			if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
1941  				/* we have an exact match */
1942  				count = 1;
1943  				break;
1944  			}
1945  			count++;
1946  		}
1947  		cmd++;
1948  	}
1949  
1950  	if (count > 1) {
1951  		printf("Ambiguous command '%s'; possible commands:", argv[0]);
1952  		cmd = hostapd_cli_commands;
1953  		while (cmd->cmd) {
1954  			if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
1955  			    0) {
1956  				printf(" %s", cmd->cmd);
1957  			}
1958  			cmd++;
1959  		}
1960  		printf("\n");
1961  	} else if (count == 0) {
1962  		printf("Unknown command '%s'\n", argv[0]);
1963  	} else {
1964  		match->handler(ctrl, argc - 1, &argv[1]);
1965  	}
1966  }
1967  
1968  
cli_event(const char * str)1969  static void cli_event(const char *str)
1970  {
1971  	const char *start, *s;
1972  
1973  	start = os_strchr(str, '>');
1974  	if (start == NULL)
1975  		return;
1976  
1977  	start++;
1978  
1979  	if (str_starts(start, AP_STA_CONNECTED)) {
1980  		s = os_strchr(start, ' ');
1981  		if (s == NULL)
1982  			return;
1983  		cli_txt_list_add(&stations, s + 1);
1984  		return;
1985  	}
1986  
1987  	if (str_starts(start, AP_STA_DISCONNECTED)) {
1988  		s = os_strchr(start, ' ');
1989  		if (s == NULL)
1990  			return;
1991  		cli_txt_list_del_addr(&stations, s + 1);
1992  		return;
1993  	}
1994  }
1995  
1996  
hostapd_cli_recv_pending(struct wpa_ctrl * ctrl,int in_read,int action_monitor)1997  static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
1998  				     int action_monitor)
1999  {
2000  	int first = 1;
2001  	if (ctrl_conn == NULL)
2002  		return;
2003  	while (wpa_ctrl_pending(ctrl)) {
2004  		char buf[4096];
2005  		size_t len = sizeof(buf) - 1;
2006  		if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
2007  			buf[len] = '\0';
2008  			if (action_monitor)
2009  				hostapd_cli_action_process(buf, len);
2010  			else {
2011  				cli_event(buf);
2012  				if (in_read && first)
2013  					printf("\n");
2014  				first = 0;
2015  				printf("%s\n", buf);
2016  			}
2017  		} else {
2018  			printf("Could not read pending message.\n");
2019  			break;
2020  		}
2021  	}
2022  }
2023  
2024  
hostapd_cli_receive(int sock,void * eloop_ctx,void * sock_ctx)2025  static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx)
2026  {
2027  	hostapd_cli_recv_pending(ctrl_conn, 0, 0);
2028  }
2029  
2030  
hostapd_cli_ping(void * eloop_ctx,void * timeout_ctx)2031  static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
2032  {
2033  	if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
2034  		printf("Connection to hostapd lost - trying to reconnect\n");
2035  		hostapd_cli_close_connection();
2036  	}
2037  	if (!ctrl_conn && hostapd_cli_reconnect(ctrl_ifname) == 0)
2038  		printf("Connection to hostapd re-established\n");
2039  	if (ctrl_conn)
2040  		hostapd_cli_recv_pending(ctrl_conn, 1, 0);
2041  	eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
2042  }
2043  
2044  
hostapd_cli_eloop_terminate(int sig,void * signal_ctx)2045  static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
2046  {
2047  	eloop_terminate();
2048  }
2049  
2050  
hostapd_cli_edit_cmd_cb(void * ctx,char * cmd)2051  static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
2052  {
2053  	char *argv[max_args];
2054  	int argc;
2055  	argc = tokenize_cmd(cmd, argv);
2056  	if (argc)
2057  		wpa_request(ctrl_conn, argc, argv);
2058  }
2059  
2060  
hostapd_cli_edit_eof_cb(void * ctx)2061  static void hostapd_cli_edit_eof_cb(void *ctx)
2062  {
2063  	eloop_terminate();
2064  }
2065  
2066  
list_cmd_list(void)2067  static char ** list_cmd_list(void)
2068  {
2069  	char **res;
2070  	int i, count;
2071  
2072  	count = ARRAY_SIZE(hostapd_cli_commands);
2073  	res = os_calloc(count + 1, sizeof(char *));
2074  	if (res == NULL)
2075  		return NULL;
2076  
2077  	for (i = 0; hostapd_cli_commands[i].cmd; i++) {
2078  		res[i] = os_strdup(hostapd_cli_commands[i].cmd);
2079  		if (res[i] == NULL)
2080  			break;
2081  	}
2082  
2083  	return res;
2084  }
2085  
2086  
hostapd_cli_cmd_completion(const char * cmd,const char * str,int pos)2087  static char ** hostapd_cli_cmd_completion(const char *cmd, const char *str,
2088  				      int pos)
2089  {
2090  	int i;
2091  
2092  	for (i = 0; hostapd_cli_commands[i].cmd; i++) {
2093  		if (os_strcasecmp(hostapd_cli_commands[i].cmd, cmd) != 0)
2094  			continue;
2095  		if (hostapd_cli_commands[i].completion)
2096  			return hostapd_cli_commands[i].completion(str, pos);
2097  		if (!hostapd_cli_commands[i].usage)
2098  			return NULL;
2099  		edit_clear_line();
2100  		printf("\r%s\n", hostapd_cli_commands[i].usage);
2101  		edit_redraw();
2102  		break;
2103  	}
2104  
2105  	return NULL;
2106  }
2107  
2108  
hostapd_cli_edit_completion_cb(void * ctx,const char * str,int pos)2109  static char ** hostapd_cli_edit_completion_cb(void *ctx, const char *str,
2110  					      int pos)
2111  {
2112  	char **res;
2113  	const char *end;
2114  	char *cmd;
2115  
2116  	end = os_strchr(str, ' ');
2117  	if (end == NULL || str + pos < end)
2118  		return list_cmd_list();
2119  
2120  	cmd = os_malloc(pos + 1);
2121  	if (cmd == NULL)
2122  		return NULL;
2123  	os_memcpy(cmd, str, pos);
2124  	cmd[end - str] = '\0';
2125  	res = hostapd_cli_cmd_completion(cmd, str, pos);
2126  	os_free(cmd);
2127  	return res;
2128  }
2129  
2130  
hostapd_cli_interactive(void)2131  static void hostapd_cli_interactive(void)
2132  {
2133  	char *hfile = NULL;
2134  	char *home;
2135  
2136  	printf("\nInteractive mode\n\n");
2137  
2138  #ifdef CONFIG_HOSTAPD_CLI_HISTORY_DIR
2139  	home = CONFIG_HOSTAPD_CLI_HISTORY_DIR;
2140  #else /* CONFIG_HOSTAPD_CLI_HISTORY_DIR */
2141  	home = getenv("HOME");
2142  #endif /* CONFIG_HOSTAPD_CLI_HISTORY_DIR */
2143  	if (home) {
2144  		const char *fname = ".hostapd_cli_history";
2145  		int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
2146  		hfile = os_malloc(hfile_len);
2147  		if (hfile)
2148  			os_snprintf(hfile, hfile_len, "%s/%s", home, fname);
2149  	}
2150  
2151  	edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
2152  		  hostapd_cli_edit_completion_cb, NULL, hfile, NULL);
2153  	eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
2154  
2155  	eloop_run();
2156  
2157  	cli_txt_list_flush(&stations);
2158  	edit_deinit(hfile, NULL);
2159  	os_free(hfile);
2160  	eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
2161  }
2162  
2163  
hostapd_cli_cleanup(void)2164  static void hostapd_cli_cleanup(void)
2165  {
2166  	hostapd_cli_close_connection();
2167  	if (pid_file)
2168  		os_daemonize_terminate(pid_file);
2169  
2170  	os_program_deinit();
2171  }
2172  
2173  
hostapd_cli_action_ping(void * eloop_ctx,void * timeout_ctx)2174  static void hostapd_cli_action_ping(void *eloop_ctx, void *timeout_ctx)
2175  {
2176  	struct wpa_ctrl *ctrl = eloop_ctx;
2177  	char buf[256];
2178  	size_t len;
2179  
2180  	/* verify that connection is still working */
2181  	len = sizeof(buf) - 1;
2182  	if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
2183  			     hostapd_cli_action_cb) < 0 ||
2184  	    len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
2185  		printf("hostapd did not reply to PING command - exiting\n");
2186  		eloop_terminate();
2187  		return;
2188  	}
2189  	eloop_register_timeout(ping_interval, 0, hostapd_cli_action_ping,
2190  			       ctrl, NULL);
2191  }
2192  
2193  
hostapd_cli_action_receive(int sock,void * eloop_ctx,void * sock_ctx)2194  static void hostapd_cli_action_receive(int sock, void *eloop_ctx,
2195  				       void *sock_ctx)
2196  {
2197  	struct wpa_ctrl *ctrl = eloop_ctx;
2198  
2199  	hostapd_cli_recv_pending(ctrl, 0, 1);
2200  }
2201  
2202  
hostapd_cli_action(struct wpa_ctrl * ctrl)2203  static void hostapd_cli_action(struct wpa_ctrl *ctrl)
2204  {
2205  	int fd;
2206  
2207  	fd = wpa_ctrl_get_fd(ctrl);
2208  	eloop_register_timeout(ping_interval, 0, hostapd_cli_action_ping,
2209  			       ctrl, NULL);
2210  	eloop_register_read_sock(fd, hostapd_cli_action_receive, ctrl, NULL);
2211  	eloop_run();
2212  	eloop_cancel_timeout(hostapd_cli_action_ping, ctrl, NULL);
2213  	eloop_unregister_read_sock(fd);
2214  }
2215  
2216  
main(int argc,char * argv[])2217  int main(int argc, char *argv[])
2218  {
2219  	int warning_displayed = 0;
2220  	int c;
2221  	int daemonize = 0;
2222  	int reconnect = 0;
2223  #ifdef CONFIG_IEEE80211BE
2224  	int link_id = -1;
2225  #endif /* CONFIG_IEEE80211BE */
2226  
2227  	if (os_program_init())
2228  		return -1;
2229  
2230  	for (;;) {
2231  		c = getopt(argc, argv, "a:BhG:i:l:p:P:rs:v");
2232  		if (c < 0)
2233  			break;
2234  		switch (c) {
2235  		case 'a':
2236  			action_file = optarg;
2237  			break;
2238  		case 'B':
2239  			daemonize = 1;
2240  			break;
2241  		case 'G':
2242  			ping_interval = atoi(optarg);
2243  			break;
2244  		case 'h':
2245  			usage();
2246  			return 0;
2247  		case 'v':
2248  			printf("%s\n", hostapd_cli_version);
2249  			return 0;
2250  		case 'i':
2251  			os_free(ctrl_ifname);
2252  			ctrl_ifname = os_strdup(optarg);
2253  			break;
2254  		case 'p':
2255  			ctrl_iface_dir = optarg;
2256  			break;
2257  		case 'P':
2258  			pid_file = optarg;
2259  			break;
2260  		case 'r':
2261  			reconnect = 1;
2262  			break;
2263  		case 's':
2264  			client_socket_dir = optarg;
2265  			break;
2266  #ifdef CONFIG_IEEE80211BE
2267  		case 'l':
2268  			link_id = atoi(optarg);
2269  			break;
2270  #endif /* CONFIG_IEEE80211BE */
2271  		default:
2272  			usage();
2273  			return -1;
2274  		}
2275  	}
2276  
2277  	interactive = (argc == optind) && (action_file == NULL);
2278  
2279  	if (interactive) {
2280  		printf("%s\n\n%s\n\n", hostapd_cli_version, cli_license);
2281  	}
2282  
2283  	if (eloop_init())
2284  		return -1;
2285  
2286  	for (;;) {
2287  		if (ctrl_ifname == NULL) {
2288  			struct dirent *dent;
2289  			DIR *dir = opendir(ctrl_iface_dir);
2290  			if (dir) {
2291  				while ((dent = readdir(dir))) {
2292  					if (os_strcmp(dent->d_name, ".") == 0
2293  					    ||
2294  					    os_strcmp(dent->d_name, "..") == 0)
2295  						continue;
2296  					printf("Selected interface '%s'\n",
2297  					       dent->d_name);
2298  					ctrl_ifname = os_strdup(dent->d_name);
2299  					break;
2300  				}
2301  				closedir(dir);
2302  			}
2303  		}
2304  
2305  #ifdef CONFIG_IEEE80211BE
2306  		if (link_id >= 0 && ctrl_ifname) {
2307  			int ret;
2308  			char buf[300];
2309  
2310  			ret = os_snprintf(buf, sizeof(buf), "%s_%s%d",
2311  					  ctrl_ifname, WPA_CTRL_IFACE_LINK_NAME,
2312  					  link_id);
2313  			if (os_snprintf_error(sizeof(buf), ret))
2314  				return -1;
2315  
2316  			os_free(ctrl_ifname);
2317  			ctrl_ifname = os_strdup(buf);
2318  			link_id = -1;
2319  		}
2320  #endif /* CONFIG_IEEE80211BE */
2321  
2322  		hostapd_cli_reconnect(ctrl_ifname);
2323  		if (ctrl_conn) {
2324  			if (warning_displayed)
2325  				printf("Connection established.\n");
2326  			break;
2327  		}
2328  		if (!interactive && !reconnect) {
2329  			perror("Failed to connect to hostapd - "
2330  			       "wpa_ctrl_open");
2331  			return -1;
2332  		}
2333  
2334  		if (!warning_displayed) {
2335  			printf("Could not connect to hostapd - re-trying\n");
2336  			warning_displayed = 1;
2337  		}
2338  		os_sleep(1, 0);
2339  		continue;
2340  	}
2341  
2342  	eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
2343  
2344  	if (action_file && !hostapd_cli_attached)
2345  		return -1;
2346  	if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
2347  		return -1;
2348  	if (reconnect && action_file && ctrl_ifname) {
2349  		while (!hostapd_cli_quit) {
2350  			if (ctrl_conn)
2351  				hostapd_cli_action(ctrl_conn);
2352  			os_sleep(1, 0);
2353  			hostapd_cli_reconnect(ctrl_ifname);
2354  		}
2355  	} else if (interactive)
2356  		hostapd_cli_interactive();
2357  	else if (action_file)
2358  		hostapd_cli_action(ctrl_conn);
2359  	else
2360  		wpa_request(ctrl_conn, argc - optind, &argv[optind]);
2361  
2362  	unregister_event_handler(ctrl_conn);
2363  	os_free(ctrl_ifname);
2364  	eloop_destroy();
2365  	hostapd_cli_cleanup();
2366  	return 0;
2367  }
2368  
2369  #else /* CONFIG_NO_CTRL_IFACE */
2370  
main(int argc,char * argv[])2371  int main(int argc, char *argv[])
2372  {
2373  	return -1;
2374  }
2375  
2376  #endif /* CONFIG_NO_CTRL_IFACE */
2377