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