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