1 /*
2  * WPA Supplicant - command line interface for wpa_supplicant daemon
3  *                  for Zephyr (based on wpa_cli.c)
4  * Copyright (c) 2004-2022, Jouni Malinen <j@w1.fi>
5  *
6  * This software may be distributed under the terms of the BSD license.
7  * See README for more details.
8  */
9 #include "includes.h"
10 
11 #include "common/cli.h"
12 #include "common/wpa_ctrl.h"
13 #include "utils/common.h"
14 #include "utils/eloop.h"
15 #include "utils/edit.h"
16 #include "utils/list.h"
17 #include "wpa_supplicant_i.h"
18 #include "ctrl_iface.h"
19 #include "common/version.h"
20 #include "common/ieee802_11_defs.h"
21 
22 #include "supp_main.h"
23 #include "supp_events.h"
24 #include "wpa_cli_zephyr.h"
25 #include "ctrl_iface_zephyr.h"
26 
27 #define CMD_BUF_LEN  1024
28 #define MAX_CMD_SIZE 512
29 #define MAX_RESPONSE_SIZE 512
30 #define DEFAULT_IFNAME "wlan0"
31 #define MAX_ARGS 32
32 
33 struct wpa_ctrl *ctrl_conn;
34 struct wpa_ctrl *mon_conn;
35 struct wpa_ctrl *global_ctrl_conn;
36 char *ifname_prefix = NULL;
37 extern struct wpa_global *global;
38 
wpa_cli_msg_cb(char * msg,size_t len)39 static void wpa_cli_msg_cb(char *msg, size_t len)
40 {
41 	wpa_printf(MSG_INFO, "%s", msg);
42 }
43 
_wpa_ctrl_command(struct wpa_ctrl * ctrl,const char * cmd,int print,char * resp)44 static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd, int print, char *resp)
45 {
46 	char buf[CMD_BUF_LEN] = { 0 };
47 	size_t len;
48 	int ret;
49 
50 	if (ctrl_conn == NULL && global_ctrl_conn == NULL) {
51 		wpa_printf(MSG_ERROR, "Not connected to wpa_supplicant - command dropped.");
52 		return -1;
53 	}
54 
55 	if (ifname_prefix) {
56 		os_snprintf(buf, sizeof(buf), "IFNAME=%s %s", ifname_prefix, cmd);
57 		buf[sizeof(buf) - 1] = '\0';
58 		cmd = buf;
59 	}
60 
61 	len = sizeof(buf) - 1;
62 	ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, wpa_cli_msg_cb);
63 	if (ret == -2) {
64 		wpa_printf(MSG_ERROR, "'%s' command timed out.", cmd);
65 		return -2;
66 	} else if (ret < 0) {
67 		wpa_printf(MSG_ERROR, "'%s' command failed.", cmd);
68 		return -1;
69 	}
70 
71 	if (resp && len > 0) {
72 		os_memcpy(resp, buf, len);
73 		if (len > 1 && resp[len - 1] == '\n') {
74 			/* Remove the LF */
75 			resp[len - 1] = '\0';
76 		} else {
77 			resp[len] = '\0';
78 		}
79 		if (strncmp(resp, "FAIL", 4) == 0)
80 			return -3;
81 	}
82 
83 	if (print) {
84 		buf[len] = '\0';
85 		if (buf[0] != '\0')
86 			wpa_printf(MSG_INFO, "%s", buf);
87 	}
88 
89 	return 0;
90 }
91 
wpa_ctrl_command_resp(struct wpa_ctrl * ctrl,const char * cmd,char * resp)92 static int wpa_ctrl_command_resp(struct wpa_ctrl *ctrl, const char *cmd, char *resp)
93 {
94 	return _wpa_ctrl_command(ctrl, cmd, 0, resp);
95 }
96 
zephyr_wpa_cli_cmd_resp(const char * cmd,char * resp)97 int zephyr_wpa_cli_cmd_resp(const char *cmd, char *resp)
98 {
99 	return _wpa_ctrl_command(ctrl_conn, cmd, 1, resp);
100 }
101 
wpa_cli_close_connection(struct wpa_supplicant * wpa_s)102 static void wpa_cli_close_connection(struct wpa_supplicant *wpa_s)
103 {
104 	int ret;
105 
106 	if (ctrl_conn == NULL)
107 		return;
108 
109 	ret = wpa_ctrl_detach(ctrl_conn);
110 	if (ret < 0) {
111 		wpa_printf(MSG_INFO, "Failed to detach from wpa_supplicant: %s",
112 			strerror(errno));
113 	}
114 	wpa_ctrl_close(ctrl_conn);
115 	ctrl_conn = NULL;
116 
117 	eloop_unregister_read_sock(wpa_s->ctrl_iface->mon_sock_pair[0]);
118 
119 	wpa_ctrl_close(mon_conn);
120 	mon_conn = NULL;
121 
122 	close(wpa_s->ctrl_iface->mon_sock_pair[1]);
123 	wpa_s->ctrl_iface->mon_sock_pair[1] = -1;
124 }
125 
wpa_cli_recv_pending(struct wpa_ctrl * ctrl,struct wpa_supplicant * wpa_s)126 static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, struct wpa_supplicant *wpa_s)
127 {
128 	while (wpa_ctrl_pending(ctrl) > 0) {
129 		char buf[sizeof(struct conn_msg)];
130 		size_t hlen = sizeof(int);
131 		size_t plen = MAX_CTRL_MSG_LEN;
132 
133 		if (wpa_ctrl_recv(ctrl, buf, &hlen) == 0 &&
134 		    hlen == sizeof(int)) {
135 			plen = *((int *)buf);
136 		} else {
137 			wpa_printf(MSG_ERROR, "Could not read pending message header len %d.\n", hlen);
138 			continue;
139 		}
140 
141 		if (wpa_ctrl_recv(ctrl, buf + sizeof(int), &plen) == 0) {
142 			struct conn_msg *msg = (struct conn_msg *)buf;
143 
144 			msg->msg[msg->msg_len] = '\0';
145 			wpa_printf(MSG_DEBUG, "Received len: %d, msg_len:%d - %s->END\n",
146 				   plen, msg->msg_len, msg->msg);
147 			if (msg->msg_len >= MAX_CTRL_MSG_LEN) {
148 				wpa_printf(MSG_DEBUG, "Too long message received.\n");
149 				continue;
150 			}
151 
152 			if (msg->msg_len > 0) {
153 				/* Only interested in CTRL-EVENTs */
154 				if (strncmp(msg->msg, "CTRL-EVENT", 10) == 0) {
155 					if (strncmp(msg->msg, "CTRL-EVENT-SIGNAL-CHANGE", 24) == 0) {
156 						supplicant_send_wifi_mgmt_event(wpa_s->ifname,
157 									NET_EVENT_WIFI_CMD_SIGNAL_CHANGE,
158 									msg->msg, msg->msg_len);
159 					} else {
160 						supplicant_send_wifi_mgmt_event(wpa_s->ifname,
161 									NET_EVENT_WIFI_CMD_SUPPLICANT,
162 									msg->msg, msg->msg_len);
163 					}
164 				} else if (strncmp(msg->msg, "RRM-NEIGHBOR-REP-RECEIVED", 25) == 0) {
165 						supplicant_send_wifi_mgmt_event(wpa_s->ifname,
166 									NET_EVENT_WIFI_CMD_NEIGHBOR_REP_RECEIVED,
167 									msg->msg, msg->msg_len);
168 				}
169 			}
170 		} else {
171 			wpa_printf(MSG_INFO, "Could not read pending message.\n");
172 		}
173 	}
174 }
175 
wpa_cli_mon_receive(int sock,void * eloop_ctx,void * sock_ctx)176 static void wpa_cli_mon_receive(int sock, void *eloop_ctx,
177 					      void *sock_ctx)
178 {
179 	struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)eloop_ctx;
180 
181 	wpa_cli_recv_pending(mon_conn, wpa_s);
182 }
183 
wpa_cli_open_connection(struct wpa_supplicant * wpa_s)184 static int wpa_cli_open_connection(struct wpa_supplicant *wpa_s)
185 {
186 	int ret;
187 
188 	ctrl_conn = wpa_ctrl_open(wpa_s->ctrl_iface->sock_pair[0]);
189 	if (ctrl_conn == NULL) {
190 		wpa_printf(MSG_ERROR, "Failed to open control connection to %d",
191 			wpa_s->ctrl_iface->sock_pair[0]);
192 		return -1;
193 	}
194 
195 	ret = socketpair(AF_UNIX, SOCK_STREAM, 0, wpa_s->ctrl_iface->mon_sock_pair);
196 	if (ret != 0) {
197 		wpa_printf(MSG_ERROR, "Failed to open monitor connection: %s",
198 			    strerror(errno));
199 		goto fail;
200 	}
201 	mon_conn = wpa_ctrl_open(wpa_s->ctrl_iface->mon_sock_pair[0]);
202 	if (mon_conn) {
203 		if (wpa_ctrl_attach(ctrl_conn) == 0) {
204 			eloop_register_read_sock(wpa_s->ctrl_iface->mon_sock_pair[0],
205 						wpa_cli_mon_receive, wpa_s, NULL);
206 		}
207 	}
208 
209 	return 0;
210 fail:
211 	wpa_ctrl_close(ctrl_conn);
212 	return -1;
213 }
214 
wpa_cli_open_global_ctrl(void)215 static int wpa_cli_open_global_ctrl(void)
216 {
217 	global_ctrl_conn = wpa_ctrl_open(zephyr_get_default_supplicant_context()->
218 					 ctrl_iface->sock_pair[0]);
219 	if (global_ctrl_conn == NULL) {
220 		wpa_printf(MSG_ERROR, "Failed to open global control connection to "
221 			   "%d - %s",
222 			   zephyr_get_default_supplicant_context()->ctrl_iface->sock_pair[0],
223 			   strerror(errno));
224 		return -1;
225 	}
226 
227 	return 0;
228 }
229 
wpa_cli_close_global_ctrl(void)230 static void wpa_cli_close_global_ctrl(void)
231 {
232 	if (global_ctrl_conn == NULL)
233 		return;
234 
235 	wpa_ctrl_close(global_ctrl_conn);
236 	global_ctrl_conn = NULL;
237 }
238 
239 
240 /* Lifted from zephyr shell_utils.c to handle escapes */
supp_strlen(const char * str)241 static inline uint16_t supp_strlen(const char *str)
242 {
243 	return str == NULL ? 0U : (uint16_t)strlen(str);
244 }
245 
make_argv(char ** ppcmd,uint8_t c)246 static char make_argv(char **ppcmd, uint8_t c)
247 {
248 	char *cmd = *ppcmd;
249 	char quote = 0;
250 
251 	while (1) {
252 		c = *cmd;
253 
254 		if (c == '\0') {
255 			break;
256 		}
257 
258 		if (quote == c) {
259 			memmove(cmd, cmd + 1, supp_strlen(cmd));
260 			quote = 0;
261 			continue;
262 		}
263 
264 		if (quote && c == '\\') {
265 			char t = *(cmd + 1);
266 
267 			if (t == quote) {
268 				memmove(cmd, cmd + 1,
269 						supp_strlen(cmd));
270 				cmd += 1;
271 				continue;
272 			}
273 
274 			if (t == '0') {
275 				uint8_t i;
276 				uint8_t v = 0U;
277 
278 				for (i = 2U; i < (2 + 3); i++) {
279 					t = *(cmd + i);
280 
281 					if (t >= '0' && t <= '7') {
282 						v = (v << 3) | (t - '0');
283 					} else {
284 						break;
285 					}
286 				}
287 
288 				if (i > 2) {
289 					memmove(cmd, cmd + (i - 1),
290 						supp_strlen(cmd) - (i - 2));
291 					*cmd++ = v;
292 					continue;
293 				}
294 			}
295 
296 			if (t == 'x') {
297 				uint8_t i;
298 				uint8_t v = 0U;
299 
300 				for (i = 2U; i < (2 + 2); i++) {
301 					t = *(cmd + i);
302 
303 					if (t >= '0' && t <= '9') {
304 						v = (v << 4) | (t - '0');
305 					} else if ((t >= 'a') &&
306 						   (t <= 'f')) {
307 						v = (v << 4) | (t - 'a' + 10);
308 					} else if ((t >= 'A') && (t <= 'F')) {
309 						v = (v << 4) | (t - 'A' + 10);
310 					} else {
311 						break;
312 					}
313 				}
314 
315 				if (i > 2) {
316 					memmove(cmd, cmd + (i - 1),
317 						supp_strlen(cmd) - (i - 2));
318 					*cmd++ = v;
319 					continue;
320 				}
321 			}
322 		}
323 
324 		if (!quote && isspace((int) c)) {
325 			break;
326 		}
327 
328 		cmd += 1;
329 	}
330 	*ppcmd = cmd;
331 
332 	return quote;
333 }
334 
335 
supp_make_argv(size_t * argc,const char ** argv,char * cmd,uint8_t max_argc)336 char supp_make_argv(size_t *argc, const char **argv, char *cmd,
337 		       uint8_t max_argc)
338 {
339 	char quote = 0;
340 	char c;
341 
342 	*argc = 0;
343 	do {
344 		c = *cmd;
345 		if (c == '\0') {
346 			break;
347 		}
348 
349 		if (isspace((int) c)) {
350 			*cmd++ = '\0';
351 			continue;
352 		}
353 
354 		argv[(*argc)++] = cmd;
355 		if (*argc == max_argc) {
356 			break;
357 		}
358 		quote = make_argv(&cmd, c);
359 	} while (true);
360 
361 	return quote;
362 }
363 
wpa_ctrl_command(struct wpa_ctrl * ctrl,const char * cmd)364 int wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd)
365 {
366 	return _wpa_ctrl_command(ctrl, cmd, 0, NULL);
367 }
368 
wpa_ctrl_command_interactive(struct wpa_ctrl * ctrl,const char * cmd)369 int wpa_ctrl_command_interactive(struct wpa_ctrl *ctrl, const char *cmd)
370 {
371 	return _wpa_ctrl_command(ctrl, cmd, 1, NULL);
372 }
373 
374 /* Public APIs */
375 
zephyr_global_wpa_ctrl_init(void)376 int zephyr_global_wpa_ctrl_init(void)
377 {
378 	int ret;
379 
380 	ret = wpa_cli_open_global_ctrl();
381 	if (ret < 0) {
382 		wpa_printf(MSG_INFO, "Failed to initialize global control interface: %d", ret);
383 		return ret;
384 	}
385 
386 	return ret;
387 }
388 
389 
zephyr_global_wpa_ctrl_deinit(void)390 void zephyr_global_wpa_ctrl_deinit(void)
391 {
392 	return wpa_cli_close_global_ctrl();
393 }
394 
zephyr_wpa_ctrl_init(void * wpa_s)395 int zephyr_wpa_ctrl_init(void *wpa_s)
396 {
397 	int ret;
398 	struct wpa_supplicant *supp = wpa_s;
399 
400 	ret = wpa_cli_open_connection(supp);
401 	if (ret < 0) {
402 		wpa_printf(MSG_INFO, "Failed to initialize control interface: %s: %d", supp->ifname, ret);
403 		return ret;
404 	}
405 
406 	return ret;
407 }
408 
zephyr_wpa_ctrl_deinit(void * wpa_s)409 void zephyr_wpa_ctrl_deinit(void *wpa_s)
410 {
411 	wpa_cli_close_connection((struct wpa_supplicant *)wpa_s);
412 }
413 
zephyr_wpa_ctrl_zephyr_cmd(int argc,const char * argv[])414 int zephyr_wpa_ctrl_zephyr_cmd(int argc, const char *argv[])
415 {
416 	return wpa_request(ctrl_conn, argc , (char **) argv);
417 }
418 
zephyr_wpa_cli_cmd_v(const char * fmt,...)419 int zephyr_wpa_cli_cmd_v(const char *fmt, ...)
420 {
421 	va_list cmd_args;
422 	int argc;
423 	const char *argv[MAX_ARGS];
424 	char cmd[MAX_CMD_SIZE];
425 
426 	va_start(cmd_args, fmt);
427 	vsnprintf(cmd, sizeof(cmd), fmt, cmd_args);
428 	va_end(cmd_args);
429 
430 	(void)supp_make_argv(&argc, &argv[0], cmd, MAX_ARGS);
431 
432 	wpa_printf(MSG_DEBUG, "Calling wpa_cli: %s, argc: %d", cmd, argc);
433 	for (int i = 0; i < argc; i++)
434 		wpa_printf(MSG_DEBUG, "argv[%d]: %s", i, argv[i]);
435 
436 	return zephyr_wpa_ctrl_zephyr_cmd(argc, argv);
437 }
438 
z_wpa_ctrl_add_network(struct add_network_resp * resp)439 int z_wpa_ctrl_add_network(struct add_network_resp *resp)
440 {
441 	int ret;
442 	char buf[MAX_RESPONSE_SIZE] = {0};
443 
444 	ret =  wpa_ctrl_command_resp(ctrl_conn, "ADD_NETWORK", buf);
445 	if (ret) {
446 		return ret;
447 	}
448 
449 	ret = sscanf((const char *)buf, "%d", &resp->network_id);
450 	if (ret < 0) {
451 		wpa_printf(MSG_INFO, "Failed to parse ADD_NETWORK response: %s",
452 			strerror(errno));
453 		return -1;
454 	}
455 
456 	return 0;
457 }
458 
z_wpa_ctrl_signal_poll(struct signal_poll_resp * resp)459 int z_wpa_ctrl_signal_poll(struct signal_poll_resp *resp)
460 {
461 	int ret;
462 	char buf[MAX_RESPONSE_SIZE] = {0};
463 
464 	ret = wpa_ctrl_command_resp(ctrl_conn, "SIGNAL_POLL", buf);
465 	if (ret) {
466 		return ret;
467 	}
468 
469 	ret = sscanf((const char *)buf, "RSSI=%d\nLINKSPEED=%d\n", &resp->rssi, &resp->current_txrate);
470 	if (ret < 0) {
471 		wpa_printf(MSG_INFO, "Failed to parse SIGNAL_POLL response: %s",
472 			strerror(errno));
473 		return -1;
474 	}
475 
476 	return 0;
477 }
478 
z_wpa_ctrl_status(struct status_resp * resp)479 int z_wpa_ctrl_status(struct status_resp *resp)
480 {
481 	int ret;
482 	char buf[MAX_RESPONSE_SIZE] = {0};
483 
484 	ret = wpa_ctrl_command_resp(ctrl_conn, "STATUS", buf);
485 	if (ret) {
486 		return ret;
487 	}
488 
489 	ret = sscanf((const char *)buf, "bssid=%%*\nfreq=%%*\nssid=%s", resp->ssid);
490 	if (ret < 0) {
491 		wpa_printf(MSG_INFO, "Failed to parse STATUS response: %s",
492 			strerror(errno));
493 		return -1;
494 	}
495 	resp->ssid_len = strlen(resp->ssid);
496 
497 	return 0;
498 }
499 
zephyr_wpa_global_ctrl_zephyr_cmd(int argc,const char * argv[])500 int zephyr_wpa_global_ctrl_zephyr_cmd(int argc, const char *argv[])
501 {
502 	return wpa_request(global_ctrl_conn, argc , (char **) argv);
503 }
504 
zephyr_wpa_cli_global_cmd_v(const char * fmt,...)505 int zephyr_wpa_cli_global_cmd_v(const char *fmt, ...)
506 {
507 	va_list cmd_args;
508 	int argc;
509 	const char *argv[MAX_ARGS] = {0};
510 	char cmd[MAX_CMD_SIZE];
511 
512 	va_start(cmd_args, fmt);
513 	vsnprintf(cmd, sizeof(cmd), fmt, cmd_args);
514 	va_end(cmd_args);
515 
516 	(void)supp_make_argv(&argc, &argv[0], cmd, MAX_ARGS);
517 
518 	wpa_printf(MSG_DEBUG, "Calling wpa_cli: %s, argc: %d", cmd, argc);
519 	for (int i = 0; i < argc; i++)
520 		wpa_printf(MSG_DEBUG, "argv[%d]: %s", i, argv[i]);
521 
522 	return zephyr_wpa_global_ctrl_zephyr_cmd(argc, argv);
523 }
524