1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA.
3  * Copyright 2024 NXP
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/logging/log.h>
9 LOG_MODULE_REGISTER(wifi_supplicant, CONFIG_WIFI_NM_WPA_SUPPLICANT_LOG_LEVEL);
10 
11 #include <zephyr/kernel.h>
12 #include <zephyr/init.h>
13 #include <poll.h>
14 #include <zephyr/zvfs/eventfd.h>
15 
16 #if !defined(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE) && !defined(CONFIG_MBEDTLS_ENABLE_HEAP)
17 #include <mbedtls/platform.h>
18 #endif /* !CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE && !CONFIG_MBEDTLS_ENABLE_HEAP */
19 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_MBEDTLS_PSA
20 #include "supp_psa_api.h"
21 #endif
22 
23 #include <zephyr/net/wifi_mgmt.h>
24 #include <zephyr/net/wifi_nm.h>
25 #include <zephyr/net/socket.h>
26 
27 static K_THREAD_STACK_DEFINE(supplicant_thread_stack,
28 			     CONFIG_WIFI_NM_WPA_SUPPLICANT_THREAD_STACK_SIZE);
29 static struct k_thread tid;
30 
31 static K_THREAD_STACK_DEFINE(iface_wq_stack, CONFIG_WIFI_NM_WPA_SUPPLICANT_WQ_STACK_SIZE);
32 
33 #define IFACE_NOTIFY_TIMEOUT_MS 1000
34 #define IFACE_NOTIFY_RETRY_MS 10
35 
36 #include "supp_main.h"
37 #include "supp_api.h"
38 #include "supp_events.h"
39 
40 #include "includes.h"
41 #include "common.h"
42 #include "eloop.h"
43 #include "wpa_supplicant/config.h"
44 #include "wpa_supplicant_i.h"
45 #include "fst/fst.h"
46 #include "wpa_cli_zephyr.h"
47 #include "ctrl_iface_zephyr.h"
48 #ifdef CONFIG_WIFI_NM_HOSTAPD_AP
49 #include "hostapd.h"
50 #include "hapd_main.h"
51 #endif
52 
53 static const struct wifi_mgmt_ops mgmt_ops = {
54 	.get_version = supplicant_get_version,
55 	.scan = supplicant_scan,
56 	.connect = supplicant_connect,
57 	.disconnect = supplicant_disconnect,
58 	.iface_status = supplicant_status,
59 #ifdef CONFIG_NET_STATISTICS_WIFI
60 	.get_stats = supplicant_get_stats,
61 	.reset_stats = supplicant_reset_stats,
62 #endif
63 	.cfg_11k = supplicant_11k_cfg,
64 	.send_11k_neighbor_request = supplicant_11k_neighbor_request,
65 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_ROAMING
66 	.candidate_scan = supplicant_candidate_scan,
67 	.start_11r_roaming = supplicant_11r_roaming,
68 #endif
69 	.set_power_save = supplicant_set_power_save,
70 	.set_twt = supplicant_set_twt,
71 	.get_power_save_config = supplicant_get_power_save_config,
72 	.reg_domain = supplicant_reg_domain,
73 	.mode = supplicant_mode,
74 	.filter = supplicant_filter,
75 	.channel = supplicant_channel,
76 	.set_rts_threshold = supplicant_set_rts_threshold,
77 	.get_rts_threshold = supplicant_get_rts_threshold,
78 	.bss_support_neighbor_rep = supplicant_bss_support_neighbor_rep,
79 	.bss_ext_capab = supplicant_bss_ext_capab,
80 	.legacy_roam = supplicant_legacy_roam,
81 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_WNM
82 	.btm_query = supplicant_btm_query,
83 #endif
84 	.get_conn_params = supplicant_get_wifi_conn_params,
85 	.wps_config = supplicant_wps_config,
86 	.set_bss_max_idle_period = supplicant_set_bss_max_idle_period,
87 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN
88 	.set_bgscan = supplicant_set_bgscan,
89 #endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN */
90 #ifdef CONFIG_AP
91 	.ap_enable = supplicant_ap_enable,
92 	.ap_disable = supplicant_ap_disable,
93 	.ap_sta_disconnect = supplicant_ap_sta_disconnect,
94 #endif /* CONFIG_AP */
95 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_DPP
96 	.dpp_dispatch = supplicant_dpp_dispatch,
97 #endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_DPP */
98 	.pmksa_flush = supplicant_pmksa_flush,
99 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE
100 	.enterprise_creds = supplicant_add_enterprise_creds,
101 #endif
102 	.config_params = supplicant_config_params,
103 };
104 
105 DEFINE_WIFI_NM_INSTANCE(wifi_supplicant, &mgmt_ops);
106 
107 #define WRITE_TIMEOUT 100 /* ms */
108 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_INF_MON
109 #define INTERFACE_EVENT_MASK (NET_EVENT_IF_ADMIN_UP | NET_EVENT_IF_ADMIN_DOWN)
110 #endif
111 struct supplicant_context {
112 	struct wpa_global *supplicant;
113 #ifdef CONFIG_WIFI_NM_HOSTAPD_AP
114 	struct hapd_interfaces hostapd;
115 #endif
116 	struct net_mgmt_event_callback cb;
117 	struct net_if *iface;
118 	char if_name[CONFIG_NET_INTERFACE_NAME_LEN + 1];
119 	struct k_fifo fifo;
120 	int sock;
121 	struct k_work iface_work;
122 	struct k_work_q iface_wq;
123 	int (*iface_handler)(struct supplicant_context *ctx, struct net_if *iface);
124 };
125 
get_default_context(void)126 static struct supplicant_context *get_default_context(void)
127 {
128 	static struct supplicant_context ctx;
129 
130 	return &ctx;
131 }
132 
zephyr_get_default_supplicant_context(void)133 struct wpa_global *zephyr_get_default_supplicant_context(void)
134 {
135 	return get_default_context()->supplicant;
136 }
137 
138 #ifdef CONFIG_WIFI_NM_HOSTAPD_AP
zephyr_get_default_hapd_context(void)139 struct hapd_interfaces *zephyr_get_default_hapd_context(void)
140 {
141 	return &get_default_context()->hostapd;
142 }
143 #endif
144 
get_workq(void)145 struct k_work_q *get_workq(void)
146 {
147 	return &get_default_context()->iface_wq;
148 }
149 
150 /* found in hostap/wpa_supplicant/ctrl_iface_zephyr.c */
151 extern int send_data(struct k_fifo *fifo, int sock, const char *buf, size_t len, int flags);
152 
zephyr_wifi_send_event(const struct wpa_supplicant_event_msg * msg)153 int zephyr_wifi_send_event(const struct wpa_supplicant_event_msg *msg)
154 {
155 	struct supplicant_context *ctx;
156 	int ret;
157 
158 	/* TODO: Fix this to get the correct container */
159 	ctx = get_default_context();
160 
161 	if (ctx->sock < 0) {
162 		ret = -ENOENT;
163 		goto out;
164 	}
165 
166 	ret = send_data(&ctx->fifo, ctx->sock,
167 			(const char *)msg, sizeof(*msg), 0);
168 	if (ret != 0) {
169 		ret = -EMSGSIZE;
170 		LOG_WRN("Event partial send (%d)", ret);
171 		goto out;
172 	}
173 
174 	ret = 0;
175 
176 out:
177 	return ret;
178 }
179 
180 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_INF_MON
send_event(const struct wpa_supplicant_event_msg * msg)181 static int send_event(const struct wpa_supplicant_event_msg *msg)
182 {
183 	return zephyr_wifi_send_event(msg);
184 }
185 
is_wanted_interface(struct net_if * iface)186 static bool is_wanted_interface(struct net_if *iface)
187 {
188 	if (!net_if_is_wifi(iface)) {
189 		return false;
190 	}
191 
192 	/* TODO: check against a list of valid interfaces */
193 
194 	return true;
195 }
196 #endif
zephyr_get_handle_by_ifname(const char * ifname)197 struct wpa_supplicant *zephyr_get_handle_by_ifname(const char *ifname)
198 {
199 	struct wpa_supplicant *wpa_s = NULL;
200 	struct supplicant_context *ctx = get_default_context();
201 
202 	wpa_s = wpa_supplicant_get_iface(ctx->supplicant, ifname);
203 	if (!wpa_s) {
204 		wpa_printf(MSG_ERROR, "%s: Unable to get wpa_s handle for %s\n", __func__, ifname);
205 		return NULL;
206 	}
207 
208 	return wpa_s;
209 }
210 
get_iface_count(struct supplicant_context * ctx)211 static int get_iface_count(struct supplicant_context *ctx)
212 {
213 	/* FIXME, should not access ifaces as it is supplicant internal data */
214 	struct wpa_supplicant *wpa_s;
215 	unsigned int count = 0;
216 
217 	for (wpa_s = ctx->supplicant->ifaces; wpa_s; wpa_s = wpa_s->next) {
218 		count += 1;
219 	}
220 
221 	return count;
222 }
223 
zephyr_wpa_supplicant_msg(void * ctx,const char * txt,size_t len)224 static void zephyr_wpa_supplicant_msg(void *ctx, const char *txt, size_t len)
225 {
226 	struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)ctx;
227 
228 	if (!ctx || !txt) {
229 		return;
230 	}
231 
232 	/* Only interested in CTRL-EVENTs */
233 	if (strncmp(txt, "CTRL-EVENT", 10) == 0) {
234 		if (strncmp(txt, "CTRL-EVENT-SIGNAL-CHANGE", 24) == 0) {
235 			supplicant_send_wifi_mgmt_event(wpa_s->ifname,
236 						NET_EVENT_WIFI_CMD_SIGNAL_CHANGE,
237 						(void *)txt, len);
238 		} else {
239 			supplicant_send_wifi_mgmt_event(wpa_s->ifname,
240 						NET_EVENT_WIFI_CMD_SUPPLICANT,
241 						(void *)txt, len);
242 		}
243 	} else if (strncmp(txt, "RRM-NEIGHBOR-REP-RECEIVED", 25) == 0) {
244 		supplicant_send_wifi_mgmt_event(wpa_s->ifname,
245 						NET_EVENT_WIFI_CMD_NEIGHBOR_REP_RECEIVED,
246 						(void *)txt, len);
247 	}
248 }
249 
zephyr_hostap_msg_ifname_cb(void * ctx)250 static const char *zephyr_hostap_msg_ifname_cb(void *ctx)
251 {
252 	if (ctx == NULL) {
253 		return NULL;
254 	}
255 
256 #ifdef CONFIG_WIFI_NM_HOSTAPD_AP
257 	if ((((struct wpa_supplicant *)ctx))->is_hostapd == 0) {
258 		struct wpa_supplicant *wpa_s = ctx;
259 
260 		return wpa_s->ifname;
261 	}
262 
263 	struct hostapd_data *hapd = ctx;
264 
265 	if (hapd && hapd->conf) {
266 		return hapd->conf->iface;
267 	}
268 
269 	return NULL;
270 #else
271 	struct wpa_supplicant *wpa_s = ctx;
272 
273 	return wpa_s->ifname;
274 #endif
275 }
276 
zephyr_hostap_ctrl_iface_msg_cb(void * ctx,int level,enum wpa_msg_type type,const char * txt,size_t len)277 static void zephyr_hostap_ctrl_iface_msg_cb(void *ctx, int level, enum wpa_msg_type type,
278 					    const char *txt, size_t len)
279 {
280 	ARG_UNUSED(level);
281 	ARG_UNUSED(type);
282 
283 	if (ctx == NULL) {
284 		return;
285 	}
286 
287 #ifdef CONFIG_WIFI_NM_HOSTAPD_AP
288 	if ((((struct wpa_supplicant *)ctx))->is_hostapd == 0) {
289 		zephyr_wpa_supplicant_msg(ctx, txt, len);
290 	} else {
291 		zephyr_hostapd_msg(ctx, txt, len);
292 	}
293 #else
294 	zephyr_wpa_supplicant_msg(ctx, txt, len);
295 #endif
296 }
297 
add_interface(struct supplicant_context * ctx,struct net_if * iface)298 static int add_interface(struct supplicant_context *ctx, struct net_if *iface)
299 {
300 	struct wpa_supplicant *wpa_s;
301 	char ifname[IFNAMSIZ + 1] = { 0 };
302 	int ret, retry = 0, count = IFACE_NOTIFY_TIMEOUT_MS / IFACE_NOTIFY_RETRY_MS;
303 
304 	ret = net_if_get_name(iface, ifname, sizeof(ifname) - 1);
305 	if (ret < 0) {
306 		LOG_ERR("Cannot get interface %d (%p) name", net_if_get_by_iface(iface), iface);
307 		goto out;
308 	}
309 
310 	LOG_DBG("Adding interface %s [%d] (%p)", ifname, net_if_get_by_iface(iface), iface);
311 
312 	ret = zephyr_wpa_cli_global_cmd_v("interface_add %s %s %s %s",
313 					  ifname, "zephyr", "zephyr", "zephyr");
314 	if (ret) {
315 		LOG_ERR("Failed to add interface %s", ifname);
316 		goto out;
317 	}
318 
319 	while (retry++ < count && !wpa_supplicant_get_iface(ctx->supplicant, ifname)) {
320 		k_sleep(K_MSEC(IFACE_NOTIFY_RETRY_MS));
321 	}
322 
323 	wpa_s = wpa_supplicant_get_iface(ctx->supplicant, ifname);
324 	if (wpa_s == NULL) {
325 		LOG_ERR("Failed to add iface %s", ifname);
326 		goto out;
327 	}
328 
329 	wpa_s->conf->filter_ssids = 1;
330 	wpa_s->conf->ap_scan = 1;
331 
332 	/* Default interface, kick start supplicant */
333 	if (get_iface_count(ctx) > 0) {
334 		ctx->iface = iface;
335 		net_if_get_name(iface, ctx->if_name, CONFIG_NET_INTERFACE_NAME_LEN);
336 	}
337 
338 	ret = zephyr_wpa_ctrl_init(wpa_s);
339 	if (ret) {
340 		LOG_ERR("Failed to initialize supplicant control interface");
341 		goto out;
342 	}
343 
344 	ret = wifi_nm_register_mgd_type_iface(wifi_nm_get_instance("wifi_supplicant"),
345 					      WIFI_TYPE_STA,
346 					      iface);
347 	if (ret) {
348 		LOG_ERR("Failed to register mgd iface with native stack %s (%d)",
349 			ifname, ret);
350 		goto out;
351 	}
352 
353 	supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_IFACE_ADDED, 0);
354 
355 	if (get_iface_count(ctx) == 1) {
356 		supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_READY, 0);
357 	}
358 
359 	wpa_msg_register_cb(zephyr_hostap_ctrl_iface_msg_cb);
360 	ret = 0;
361 
362 out:
363 	return ret;
364 }
365 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_INF_MON
del_interface(struct supplicant_context * ctx,struct net_if * iface)366 static int del_interface(struct supplicant_context *ctx, struct net_if *iface)
367 {
368 	struct wpa_supplicant_event_msg msg;
369 	struct wpa_supplicant *wpa_s;
370 	union wpa_event_data *event = NULL;
371 	int ret, retry = 0, count = IFACE_NOTIFY_TIMEOUT_MS / IFACE_NOTIFY_RETRY_MS;
372 	char ifname[IFNAMSIZ + 1] = { 0 };
373 
374 	ret = net_if_get_name(iface, ifname, sizeof(ifname) - 1);
375 	if (ret < 0) {
376 		LOG_ERR("Cannot get interface %d (%p) name", net_if_get_by_iface(iface), iface);
377 		goto out;
378 	}
379 
380 	LOG_DBG("Removing interface %s %d (%p)", ifname, net_if_get_by_iface(iface), iface);
381 
382 	event = os_zalloc(sizeof(*event));
383 	if (!event) {
384 		ret = -ENOMEM;
385 		LOG_ERR("Failed to allocate event data");
386 		goto out;
387 	}
388 
389 	wpa_s = wpa_supplicant_get_iface(ctx->supplicant, ifname);
390 	if (!wpa_s) {
391 		ret = -ENOENT;
392 		LOG_ERR("Failed to get wpa_s handle for %s", ifname);
393 		goto free;
394 	}
395 
396 	supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVING, 0);
397 
398 	if (sizeof(event->interface_status.ifname) < strlen(ifname)) {
399 		wpa_printf(MSG_ERROR, "Interface name too long: %s (max: %zu)",
400 			ifname, sizeof(event->interface_status.ifname));
401 		goto free;
402 	}
403 
404 	os_memcpy(event->interface_status.ifname, ifname, strlen(ifname));
405 	event->interface_status.ievent = EVENT_INTERFACE_REMOVED;
406 
407 	msg.global = true;
408 	msg.ctx = ctx->supplicant;
409 	msg.event = EVENT_INTERFACE_STATUS;
410 	msg.data = event;
411 
412 	ret = send_event(&msg);
413 	if (ret) {
414 		/* We failed notify WPA supplicant about interface removal.
415 		 * There is not much we can do, interface is still registered
416 		 * with WPA supplicant so we cannot unregister NM etc.
417 		 */
418 		wpa_printf(MSG_ERROR, "Failed to send event: %d", ret);
419 		goto free;
420 	}
421 
422 	while (retry++ < count && wpa_s->wpa_state != WPA_INTERFACE_DISABLED) {
423 		k_sleep(K_MSEC(IFACE_NOTIFY_RETRY_MS));
424 	}
425 
426 	if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) {
427 		LOG_ERR("Failed to notify remove interface %s", ifname);
428 		supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVED, -1);
429 		goto out;
430 	}
431 
432 	zephyr_wpa_ctrl_deinit(wpa_s);
433 
434 	ret = zephyr_wpa_cli_global_cmd_v("interface_remove %s", ifname);
435 	if (ret) {
436 		LOG_ERR("Failed to remove interface %s", ifname);
437 		supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVED,
438 					  -EINVAL);
439 		goto out;
440 	}
441 
442 	ret = wifi_nm_unregister_mgd_iface(wifi_nm_get_instance("wifi_supplicant"), iface);
443 	if (ret) {
444 		LOG_ERR("Failed to unregister mgd iface %s with native stack (%d)",
445 			ifname, ret);
446 		goto out;
447 	}
448 
449 	if (get_iface_count(ctx) == 0) {
450 		supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_NOT_READY, 0);
451 	}
452 
453 	supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVED, 0);
454 
455 	return 0;
456 
457 free:
458 	if (event) {
459 		os_free(event);
460 	}
461 out:
462 	return ret;
463 }
464 #endif
iface_work_handler(struct k_work * work)465 static void iface_work_handler(struct k_work *work)
466 {
467 	struct supplicant_context *ctx = CONTAINER_OF(work, struct supplicant_context,
468 						      iface_work);
469 	int ret;
470 
471 	ret = (*ctx->iface_handler)(ctx, ctx->iface);
472 	if (ret < 0) {
473 		LOG_ERR("Interface %d (%p) handler failed (%d)",
474 			net_if_get_by_iface(ctx->iface), ctx->iface, ret);
475 	}
476 }
477 
478 /* As the mgmt thread stack is limited, use a separate work queue for any network
479  * interface add/delete.
480  */
submit_iface_work(struct supplicant_context * ctx,struct net_if * iface,int (* handler)(struct supplicant_context * ctx,struct net_if * iface))481 static void submit_iface_work(struct supplicant_context *ctx,
482 			      struct net_if *iface,
483 			      int (*handler)(struct supplicant_context *ctx,
484 					     struct net_if *iface))
485 {
486 	ctx->iface_handler = handler;
487 
488 	k_work_submit_to_queue(&ctx->iface_wq, &ctx->iface_work);
489 }
490 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_INF_MON
interface_handler(struct net_mgmt_event_callback * cb,uint64_t mgmt_event,struct net_if * iface)491 static void interface_handler(struct net_mgmt_event_callback *cb,
492 			      uint64_t mgmt_event, struct net_if *iface)
493 {
494 	if ((mgmt_event & INTERFACE_EVENT_MASK) != mgmt_event) {
495 		return;
496 	}
497 
498 	if (!is_wanted_interface(iface)) {
499 		LOG_DBG("Ignoring event (0x%" PRIx64 ") from interface %d (%p)",
500 			mgmt_event, net_if_get_by_iface(iface), iface);
501 		return;
502 	}
503 
504 	if (mgmt_event == NET_EVENT_IF_ADMIN_UP) {
505 		LOG_INF("Network interface %d (%p) up", net_if_get_by_iface(iface), iface);
506 		add_interface(get_default_context(), iface);
507 		return;
508 	}
509 
510 	if (mgmt_event == NET_EVENT_IF_ADMIN_DOWN) {
511 		LOG_INF("Network interface %d (%p) down", net_if_get_by_iface(iface), iface);
512 		del_interface(get_default_context(), iface);
513 		return;
514 	}
515 }
516 #endif
517 
iface_cb(struct net_if * iface,void * user_data)518 static void iface_cb(struct net_if *iface, void *user_data)
519 {
520 	struct supplicant_context *ctx = user_data;
521 	int ret;
522 
523 	if (!net_if_is_wifi(iface)) {
524 		return;
525 	}
526 
527 #ifdef CONFIG_WIFI_NM_HOSTAPD_AP
528 	if (wifi_nm_iface_is_sap(iface)) {
529 		return;
530 	}
531 #endif
532 
533 	if (!net_if_is_admin_up(iface)) {
534 		return;
535 	}
536 
537 	ret = add_interface(ctx, iface);
538 	if (ret < 0) {
539 		return;
540 	}
541 }
542 
setup_interface_monitoring(struct supplicant_context * ctx,struct net_if * iface)543 static int setup_interface_monitoring(struct supplicant_context *ctx, struct net_if *iface)
544 {
545 	ARG_UNUSED(iface);
546 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_INF_MON
547 	net_mgmt_init_event_callback(&ctx->cb, interface_handler,
548 				     INTERFACE_EVENT_MASK);
549 	net_mgmt_add_event_callback(&ctx->cb);
550 #endif
551 	net_if_foreach(iface_cb, ctx);
552 
553 	return 0;
554 }
555 
event_socket_handler(int sock,void * eloop_ctx,void * user_data)556 static void event_socket_handler(int sock, void *eloop_ctx, void *user_data)
557 {
558 	struct supplicant_context *ctx = user_data;
559 	struct wpa_supplicant_event_msg event_msg;
560 	struct zephyr_msg *msg;
561 	zvfs_eventfd_t value;
562 
563 	ARG_UNUSED(eloop_ctx);
564 
565 	do {
566 		zvfs_eventfd_read(sock, &value);
567 
568 		msg = k_fifo_get(&ctx->fifo, K_NO_WAIT);
569 		if (msg == NULL) {
570 			LOG_ERR("fifo(event): %s", "empty");
571 			return;
572 		}
573 
574 		if (msg->data == NULL) {
575 			LOG_ERR("fifo(event): %s", "no data");
576 			goto out;
577 		}
578 
579 		if (msg->len != sizeof(event_msg)) {
580 			LOG_ERR("Received incomplete message: got: %d, expected:%d",
581 				msg->len, sizeof(event_msg));
582 			goto out;
583 		}
584 
585 		memcpy(&event_msg, msg->data, sizeof(event_msg));
586 
587 		LOG_DBG("Passing message %d to wpa_supplicant", event_msg.event);
588 
589 		if (event_msg.global) {
590 			wpa_supplicant_event_global(event_msg.ctx, event_msg.event,
591 						    event_msg.data);
592 #ifdef CONFIG_WIFI_NM_HOSTAPD_AP
593 		} else if (event_msg.hostapd) {
594 			hostapd_event(event_msg.ctx, event_msg.event, event_msg.data);
595 #endif
596 		} else {
597 			wpa_supplicant_event(event_msg.ctx, event_msg.event, event_msg.data);
598 		}
599 
600 		if (event_msg.data) {
601 			union wpa_event_data *data = event_msg.data;
602 
603 			/* Free up deep copied data */
604 			if (event_msg.event == EVENT_AUTH) {
605 				os_free((char *)data->auth.ies);
606 			} else if (event_msg.event == EVENT_RX_MGMT) {
607 				os_free((char *)data->rx_mgmt.frame);
608 			} else if (event_msg.event == EVENT_TX_STATUS) {
609 				os_free((char *)data->tx_status.data);
610 			} else if (event_msg.event == EVENT_ASSOC) {
611 				os_free((char *)data->assoc_info.addr);
612 				os_free((char *)data->assoc_info.req_ies);
613 				os_free((char *)data->assoc_info.resp_ies);
614 				os_free((char *)data->assoc_info.resp_frame);
615 			} else if (event_msg.event == EVENT_ASSOC_REJECT) {
616 				os_free((char *)data->assoc_reject.bssid);
617 				os_free((char *)data->assoc_reject.resp_ies);
618 			} else if (event_msg.event == EVENT_DEAUTH) {
619 				os_free((char *)data->deauth_info.addr);
620 				os_free((char *)data->deauth_info.ie);
621 			} else if (event_msg.event == EVENT_DISASSOC) {
622 				os_free((char *)data->disassoc_info.addr);
623 				os_free((char *)data->disassoc_info.ie);
624 			} else if (event_msg.event == EVENT_UNPROT_DEAUTH) {
625 				os_free((char *)data->unprot_deauth.sa);
626 				os_free((char *)data->unprot_deauth.da);
627 			} else if (event_msg.event == EVENT_UNPROT_DISASSOC) {
628 				os_free((char *)data->unprot_disassoc.sa);
629 				os_free((char *)data->unprot_disassoc.da);
630 			}
631 
632 			os_free(event_msg.data);
633 		}
634 
635 out:
636 		os_free(msg->data);
637 		os_free(msg);
638 
639 	} while (!k_fifo_is_empty(&ctx->fifo));
640 }
641 
register_supplicant_event_socket(struct supplicant_context * ctx)642 static int register_supplicant_event_socket(struct supplicant_context *ctx)
643 {
644 	int ret;
645 
646 	ret = zvfs_eventfd(0, ZVFS_EFD_NONBLOCK);
647 	if (ret < 0) {
648 		ret = -errno;
649 		LOG_ERR("Failed to initialize socket (%d)", ret);
650 		return ret;
651 	}
652 
653 	ctx->sock = ret;
654 
655 	k_fifo_init(&ctx->fifo);
656 
657 	eloop_register_read_sock(ctx->sock, event_socket_handler, NULL, ctx);
658 
659 	return 0;
660 }
661 
handler(void)662 static void handler(void)
663 {
664 	struct supplicant_context *ctx;
665 	struct wpa_params params;
666 	struct k_work_queue_config iface_wq_cfg = {
667 		.name = "hostap_iface_wq",
668 	};
669 
670 #if !defined(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE) && !defined(CONFIG_MBEDTLS_ENABLE_HEAP)
671 	/* Needed for crypto operation as default is no-op and fails */
672 	mbedtls_platform_set_calloc_free(calloc, free);
673 #endif /* !CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE && !CONFIG_MBEDTLS_ENABLE_HEAP */
674 
675 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_MBEDTLS_PSA
676 	supp_psa_crypto_init();
677 #endif
678 
679 	ctx = get_default_context();
680 
681 	k_work_queue_init(&ctx->iface_wq);
682 	k_work_queue_start(&ctx->iface_wq, iface_wq_stack,
683 			   K_THREAD_STACK_SIZEOF(iface_wq_stack),
684 			   CONFIG_WIFI_NM_WPA_SUPPLICANT_WQ_PRIO,
685 			   &iface_wq_cfg);
686 
687 	k_work_init(&ctx->iface_work, iface_work_handler);
688 
689 	memset(&params, 0, sizeof(params));
690 	params.wpa_debug_level = CONFIG_WIFI_NM_WPA_SUPPLICANT_DEBUG_LEVEL;
691 
692 	ctx->supplicant = wpa_supplicant_init(&params);
693 	if (ctx->supplicant == NULL) {
694 		LOG_ERR("Failed to initialize %s", "wpa_supplicant");
695 		goto err;
696 	}
697 
698 	LOG_INF("%s initialized", "wpa_supplicant");
699 
700 	if (fst_global_init()) {
701 		LOG_ERR("Failed to initialize %s", "FST");
702 		goto out;
703 	}
704 
705 #if defined(CONFIG_FST) && defined(CONFIG_CTRL_IFACE)
706 	if (!fst_global_add_ctrl(fst_ctrl_cli)) {
707 		LOG_WRN("Failed to add CLI FST ctrl");
708 	}
709 #endif
710 	zephyr_global_wpa_ctrl_init();
711 
712 	register_supplicant_event_socket(ctx);
713 
714 	submit_iface_work(ctx, NULL, setup_interface_monitoring);
715 
716 #ifdef CONFIG_WIFI_NM_HOSTAPD_AP
717 	zephyr_hostapd_init(&ctx->hostapd);
718 #endif
719 	wpa_msg_register_ifname_cb(zephyr_hostap_msg_ifname_cb);
720 
721 	(void)wpa_supplicant_run(ctx->supplicant);
722 
723 	supplicant_generate_state_event(ctx->if_name, NET_EVENT_SUPPLICANT_CMD_NOT_READY, 0);
724 
725 	eloop_unregister_read_sock(ctx->sock);
726 
727 	zephyr_global_wpa_ctrl_deinit();
728 
729 	fst_global_deinit();
730 
731 out:
732 	wpa_supplicant_deinit(ctx->supplicant);
733 
734 	close(ctx->sock);
735 
736 err:
737 	os_free(params.pid_file);
738 }
739 
init(void)740 static int init(void)
741 {
742 	k_tid_t id;
743 
744 	/* We create a thread that handles all supplicant connections */
745 	id = k_thread_create(&tid, supplicant_thread_stack,
746 			     K_THREAD_STACK_SIZEOF(supplicant_thread_stack),
747 			     (k_thread_entry_t)handler, NULL, NULL, NULL,
748 			     CONFIG_WIFI_NM_WPA_SUPPLICANT_PRIO, 0, K_NO_WAIT);
749 
750 	k_thread_name_set(id, "hostap_handler");
751 
752 	return 0;
753 }
754 
755 SYS_INIT(init, APPLICATION, 0);
756 
eapol_recv(struct net_if * iface,uint16_t ptype,struct net_pkt * pkt)757 static enum net_verdict eapol_recv(struct net_if *iface, uint16_t ptype,
758 				   struct net_pkt *pkt)
759 {
760 	ARG_UNUSED(iface);
761 	ARG_UNUSED(ptype);
762 
763 	net_pkt_set_family(pkt, AF_UNSPEC);
764 
765 	return NET_CONTINUE;
766 }
767 
768 ETH_NET_L3_REGISTER(EAPOL, NET_ETH_PTYPE_EAPOL, eapol_recv);
769