1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(wifi_supplicant, CONFIG_WIFI_NM_WPA_SUPPLICANT_LOG_LEVEL);
9 
10 #include <zephyr/kernel.h>
11 #include <zephyr/init.h>
12 #include <poll.h>
13 
14 #if !defined(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE) && !defined(CONFIG_MBEDTLS_ENABLE_HEAP)
15 #include <mbedtls/platform.h>
16 #endif /* !CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE && !CONFIG_MBEDTLS_ENABLE_HEAP */
17 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_MBEDTLS_PSA
18 #include "supp_psa_api.h"
19 #endif
20 
21 #include <zephyr/net/wifi_mgmt.h>
22 #include <zephyr/net/wifi_nm.h>
23 #include <zephyr/net/socket.h>
24 
25 static K_THREAD_STACK_DEFINE(supplicant_thread_stack,
26 			     CONFIG_WIFI_NM_WPA_SUPPLICANT_THREAD_STACK_SIZE);
27 static struct k_thread tid;
28 
29 static K_THREAD_STACK_DEFINE(iface_wq_stack, CONFIG_WIFI_NM_WPA_SUPPLICANT_WQ_STACK_SIZE);
30 
31 #define IFACE_NOTIFY_TIMEOUT_MS 1000
32 #define IFACE_NOTIFY_RETRY_MS 10
33 
34 #include "supp_main.h"
35 #include "supp_api.h"
36 #include "supp_events.h"
37 
38 #include "includes.h"
39 #include "common.h"
40 #include "eloop.h"
41 #include "wpa_supplicant/config.h"
42 #include "wpa_supplicant_i.h"
43 #include "fst/fst.h"
44 #include "includes.h"
45 #include "wpa_cli_zephyr.h"
46 
47 static const struct wifi_mgmt_ops mgmt_ops = {
48 	.scan = supplicant_scan,
49 	.connect = supplicant_connect,
50 	.disconnect = supplicant_disconnect,
51 	.iface_status = supplicant_status,
52 #ifdef CONFIG_NET_STATISTICS_WIFI
53 	.get_stats = supplicant_get_stats,
54 #endif
55 	.set_power_save = supplicant_set_power_save,
56 	.set_twt = supplicant_set_twt,
57 	.get_power_save_config = supplicant_get_power_save_config,
58 	.reg_domain = supplicant_reg_domain,
59 	.mode = supplicant_mode,
60 	.filter = supplicant_filter,
61 	.channel = supplicant_channel,
62 #ifdef CONFIG_AP
63 	.ap_enable = supplicant_ap_enable,
64 	.ap_disable = supplicant_ap_disable,
65 	.ap_sta_disconnect = supplicant_ap_sta_disconnect,
66 #endif /* CONFIG_AP */
67 };
68 
69 DEFINE_WIFI_NM_INSTANCE(wifi_supplicant, &mgmt_ops);
70 
71 #define WRITE_TIMEOUT 100 /* ms */
72 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_INF_MON
73 #define INTERFACE_EVENT_MASK (NET_EVENT_IF_ADMIN_UP | NET_EVENT_IF_ADMIN_DOWN)
74 #endif
75 struct supplicant_context {
76 	struct wpa_global *supplicant;
77 	struct net_mgmt_event_callback cb;
78 	struct net_if *iface;
79 	char if_name[CONFIG_NET_INTERFACE_NAME_LEN + 1];
80 	int event_socketpair[2];
81 	struct k_work iface_work;
82 	struct k_work_q iface_wq;
83 	int (*iface_handler)(struct supplicant_context *ctx, struct net_if *iface);
84 };
85 
get_default_context(void)86 static struct supplicant_context *get_default_context(void)
87 {
88 	static struct supplicant_context ctx;
89 
90 	return &ctx;
91 }
92 
zephyr_get_default_supplicant_context(void)93 struct wpa_global *zephyr_get_default_supplicant_context(void)
94 {
95 	return get_default_context()->supplicant;
96 }
97 
get_workq(void)98 struct k_work_q *get_workq(void)
99 {
100 	return &get_default_context()->iface_wq;
101 }
102 
zephyr_wifi_send_event(const struct wpa_supplicant_event_msg * msg)103 int zephyr_wifi_send_event(const struct wpa_supplicant_event_msg *msg)
104 {
105 	struct supplicant_context *ctx;
106 	struct pollfd fds[1];
107 	int ret;
108 
109 	/* TODO: Fix this to get the correct container */
110 	ctx = get_default_context();
111 
112 	if (ctx->event_socketpair[1] < 0) {
113 		ret = -ENOENT;
114 		goto out;
115 	}
116 
117 	fds[0].fd = ctx->event_socketpair[0];
118 	fds[0].events = POLLOUT;
119 	fds[0].revents = 0;
120 
121 	ret = zsock_poll(fds, 1, WRITE_TIMEOUT);
122 	if (ret < 0) {
123 		ret = -errno;
124 		LOG_ERR("Cannot write event (%d)", ret);
125 		goto out;
126 	}
127 
128 	ret = zsock_send(ctx->event_socketpair[1], msg, sizeof(*msg), 0);
129 	if (ret < 0) {
130 		ret = -errno;
131 		LOG_WRN("Event send failed (%d)", ret);
132 		goto out;
133 	}
134 
135 	if (ret != sizeof(*msg)) {
136 		ret = -EMSGSIZE;
137 		LOG_WRN("Event partial send (%d)", ret);
138 		goto out;
139 	}
140 
141 	ret = 0;
142 
143 out:
144 	return ret;
145 }
146 
147 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_INF_MON
send_event(const struct wpa_supplicant_event_msg * msg)148 static int send_event(const struct wpa_supplicant_event_msg *msg)
149 {
150 	return zephyr_wifi_send_event(msg);
151 }
152 
is_wanted_interface(struct net_if * iface)153 static bool is_wanted_interface(struct net_if *iface)
154 {
155 	if (!net_if_is_wifi(iface)) {
156 		return false;
157 	}
158 
159 	/* TODO: check against a list of valid interfaces */
160 
161 	return true;
162 }
163 #endif
zephyr_get_handle_by_ifname(const char * ifname)164 struct wpa_supplicant *zephyr_get_handle_by_ifname(const char *ifname)
165 {
166 	struct wpa_supplicant *wpa_s = NULL;
167 	struct supplicant_context *ctx = get_default_context();
168 
169 	wpa_s = wpa_supplicant_get_iface(ctx->supplicant, ifname);
170 	if (!wpa_s) {
171 		wpa_printf(MSG_ERROR, "%s: Unable to get wpa_s handle for %s\n", __func__, ifname);
172 		return NULL;
173 	}
174 
175 	return wpa_s;
176 }
177 
get_iface_count(struct supplicant_context * ctx)178 static int get_iface_count(struct supplicant_context *ctx)
179 {
180 	/* FIXME, should not access ifaces as it is supplicant internal data */
181 	struct wpa_supplicant *wpa_s;
182 	unsigned int count = 0;
183 
184 	for (wpa_s = ctx->supplicant->ifaces; wpa_s; wpa_s = wpa_s->next) {
185 		count += 1;
186 	}
187 
188 	return count;
189 }
190 
add_interface(struct supplicant_context * ctx,struct net_if * iface)191 static int add_interface(struct supplicant_context *ctx, struct net_if *iface)
192 {
193 	struct wpa_supplicant *wpa_s;
194 	char ifname[IFNAMSIZ + 1] = { 0 };
195 	int ret, retry = 0, count = IFACE_NOTIFY_TIMEOUT_MS / IFACE_NOTIFY_RETRY_MS;
196 
197 	ret = net_if_get_name(iface, ifname, sizeof(ifname) - 1);
198 	if (ret < 0) {
199 		LOG_ERR("Cannot get interface %d (%p) name", net_if_get_by_iface(iface), iface);
200 		goto out;
201 	}
202 
203 	LOG_DBG("Adding interface %s [%d] (%p)", ifname, net_if_get_by_iface(iface), iface);
204 
205 	ret = zephyr_wpa_cli_global_cmd_v("interface_add %s %s %s %s",
206 					  ifname, "zephyr", "zephyr", "zephyr");
207 	if (ret) {
208 		LOG_ERR("Failed to add interface %s", ifname);
209 		goto out;
210 	}
211 
212 	while (retry++ < count && !wpa_supplicant_get_iface(ctx->supplicant, ifname)) {
213 		k_sleep(K_MSEC(IFACE_NOTIFY_RETRY_MS));
214 	}
215 
216 	wpa_s = wpa_supplicant_get_iface(ctx->supplicant, ifname);
217 	if (wpa_s == NULL) {
218 		LOG_ERR("Failed to add iface %s", ifname);
219 		goto out;
220 	}
221 
222 	wpa_s->conf->filter_ssids = 1;
223 	wpa_s->conf->ap_scan = 1;
224 
225 	/* Default interface, kick start supplicant */
226 	if (get_iface_count(ctx) > 0) {
227 		ctx->iface = iface;
228 		net_if_get_name(iface, ctx->if_name, CONFIG_NET_INTERFACE_NAME_LEN);
229 	}
230 
231 	ret = zephyr_wpa_ctrl_init(wpa_s);
232 	if (ret) {
233 		LOG_ERR("Failed to initialize supplicant control interface");
234 		goto out;
235 	}
236 
237 	ret = wifi_nm_register_mgd_iface(wifi_nm_get_instance("wifi_supplicant"), iface);
238 	if (ret) {
239 		LOG_ERR("Failed to register mgd iface with native stack %s (%d)",
240 			ifname, ret);
241 		goto out;
242 	}
243 
244 	supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_IFACE_ADDED, 0);
245 
246 	if (get_iface_count(ctx) == 1) {
247 		supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_READY, 0);
248 	}
249 
250 	ret = 0;
251 
252 out:
253 	return ret;
254 }
255 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_INF_MON
del_interface(struct supplicant_context * ctx,struct net_if * iface)256 static int del_interface(struct supplicant_context *ctx, struct net_if *iface)
257 {
258 	struct wpa_supplicant_event_msg msg;
259 	struct wpa_supplicant *wpa_s;
260 	union wpa_event_data *event = NULL;
261 	int ret, retry = 0, count = IFACE_NOTIFY_TIMEOUT_MS / IFACE_NOTIFY_RETRY_MS;
262 	char ifname[IFNAMSIZ + 1] = { 0 };
263 
264 	ret = net_if_get_name(iface, ifname, sizeof(ifname) - 1);
265 	if (ret < 0) {
266 		LOG_ERR("Cannot get interface %d (%p) name", net_if_get_by_iface(iface), iface);
267 		goto out;
268 	}
269 
270 	LOG_DBG("Removing interface %s %d (%p)", ifname, net_if_get_by_iface(iface), iface);
271 
272 	event = os_zalloc(sizeof(*event));
273 	if (!event) {
274 		ret = -ENOMEM;
275 		LOG_ERR("Failed to allocate event data");
276 		goto out;
277 	}
278 
279 	wpa_s = wpa_supplicant_get_iface(ctx->supplicant, ifname);
280 	if (!wpa_s) {
281 		ret = -ENOENT;
282 		LOG_ERR("Failed to get wpa_s handle for %s", ifname);
283 		goto out;
284 	}
285 
286 	supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVING, 0);
287 
288 	if (sizeof(event->interface_status.ifname) < strlen(ifname)) {
289 		wpa_printf(MSG_ERROR, "Interface name too long: %s (max: %d)",
290 			ifname, sizeof(event->interface_status.ifname));
291 		goto out;
292 	}
293 
294 	os_memcpy(event->interface_status.ifname, ifname, strlen(ifname));
295 	event->interface_status.ievent = EVENT_INTERFACE_REMOVED;
296 
297 	msg.global = true;
298 	msg.ctx = ctx->supplicant;
299 	msg.event = EVENT_INTERFACE_STATUS;
300 	msg.data = event;
301 
302 	ret = send_event(&msg);
303 	if (ret) {
304 		/* We failed notify WPA supplicant about interface removal.
305 		 * There is not much we can do, interface is still registered
306 		 * with WPA supplicant so we cannot unregister NM etc.
307 		 */
308 		wpa_printf(MSG_ERROR, "Failed to send event: %d", ret);
309 		goto out;
310 	}
311 
312 	while (retry++ < count && wpa_s->wpa_state != WPA_INTERFACE_DISABLED) {
313 		k_sleep(K_MSEC(IFACE_NOTIFY_RETRY_MS));
314 	}
315 
316 	if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) {
317 		LOG_ERR("Failed to notify remove interface %s", ifname);
318 		supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVED, -1);
319 		goto out;
320 	}
321 
322 	zephyr_wpa_ctrl_deinit(wpa_s);
323 
324 	ret = zephyr_wpa_cli_global_cmd_v("interface_remove %s", ifname);
325 	if (ret) {
326 		LOG_ERR("Failed to remove interface %s", ifname);
327 		supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVED,
328 					  -EINVAL);
329 		goto out;
330 	}
331 
332 	ret = wifi_nm_unregister_mgd_iface(wifi_nm_get_instance("wpa_supplicant"), iface);
333 	if (ret) {
334 		LOG_ERR("Failed to unregister mgd iface %s with native stack (%d)",
335 			ifname, ret);
336 		goto out;
337 	}
338 
339 	if (get_iface_count(ctx) == 0) {
340 		supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_NOT_READY, 0);
341 	}
342 
343 	supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVED, 0);
344 
345 out:
346 	if (event) {
347 		os_free(event);
348 	}
349 
350 	return ret;
351 }
352 #endif
iface_work_handler(struct k_work * work)353 static void iface_work_handler(struct k_work *work)
354 {
355 	struct supplicant_context *ctx = CONTAINER_OF(work, struct supplicant_context,
356 						      iface_work);
357 	int ret;
358 
359 	ret = (*ctx->iface_handler)(ctx, ctx->iface);
360 	if (ret < 0) {
361 		LOG_ERR("Interface %d (%p) handler failed (%d)",
362 			net_if_get_by_iface(ctx->iface), ctx->iface, ret);
363 	}
364 }
365 
366 /* As the mgmt thread stack is limited, use a separate work queue for any network
367  * interface add/delete.
368  */
submit_iface_work(struct supplicant_context * ctx,struct net_if * iface,int (* handler)(struct supplicant_context * ctx,struct net_if * iface))369 static void submit_iface_work(struct supplicant_context *ctx,
370 			      struct net_if *iface,
371 			      int (*handler)(struct supplicant_context *ctx,
372 					     struct net_if *iface))
373 {
374 	ctx->iface_handler = handler;
375 
376 	k_work_submit_to_queue(&ctx->iface_wq, &ctx->iface_work);
377 }
378 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_INF_MON
interface_handler(struct net_mgmt_event_callback * cb,uint32_t mgmt_event,struct net_if * iface)379 static void interface_handler(struct net_mgmt_event_callback *cb,
380 			      uint32_t mgmt_event, struct net_if *iface)
381 {
382 	struct supplicant_context *ctx = CONTAINER_OF(cb, struct supplicant_context,
383 						      cb);
384 
385 	if ((mgmt_event & INTERFACE_EVENT_MASK) != mgmt_event) {
386 		return;
387 	}
388 
389 	if (!is_wanted_interface(iface)) {
390 		LOG_DBG("Ignoring event (0x%02x) from interface %d (%p)",
391 			mgmt_event, net_if_get_by_iface(iface), iface);
392 		return;
393 	}
394 
395 	if (mgmt_event == NET_EVENT_IF_ADMIN_UP) {
396 		LOG_INF("Network interface %d (%p) up", net_if_get_by_iface(iface), iface);
397 		submit_iface_work(ctx, iface, add_interface);
398 		return;
399 	}
400 
401 	if (mgmt_event == NET_EVENT_IF_ADMIN_DOWN) {
402 		LOG_INF("Network interface %d (%p) down", net_if_get_by_iface(iface), iface);
403 		submit_iface_work(ctx, iface, del_interface);
404 		return;
405 	}
406 }
407 #endif
408 
iface_cb(struct net_if * iface,void * user_data)409 static void iface_cb(struct net_if *iface, void *user_data)
410 {
411 	struct supplicant_context *ctx = user_data;
412 	int ret;
413 
414 	if (!net_if_is_wifi(iface)) {
415 		return;
416 	}
417 
418 	if (!net_if_is_admin_up(iface)) {
419 		return;
420 	}
421 
422 	ret = add_interface(ctx, iface);
423 	if (ret < 0) {
424 		return;
425 	}
426 }
427 
setup_interface_monitoring(struct supplicant_context * ctx,struct net_if * iface)428 static int setup_interface_monitoring(struct supplicant_context *ctx, struct net_if *iface)
429 {
430 	ARG_UNUSED(iface);
431 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_INF_MON
432 	net_mgmt_init_event_callback(&ctx->cb, interface_handler,
433 				     INTERFACE_EVENT_MASK);
434 	net_mgmt_add_event_callback(&ctx->cb);
435 #endif
436 	net_if_foreach(iface_cb, ctx);
437 
438 	return 0;
439 }
440 
event_socket_handler(int sock,void * eloop_ctx,void * user_data)441 static void event_socket_handler(int sock, void *eloop_ctx, void *user_data)
442 {
443 	struct supplicant_context *ctx = user_data;
444 	struct wpa_supplicant_event_msg msg;
445 	int ret;
446 
447 	ARG_UNUSED(eloop_ctx);
448 	ARG_UNUSED(ctx);
449 
450 	ret = zsock_recv(sock, &msg, sizeof(msg), 0);
451 	if (ret < 0) {
452 		LOG_ERR("Failed to recv the message (%d)", -errno);
453 		return;
454 	}
455 
456 	if (ret != sizeof(msg)) {
457 		LOG_ERR("Received incomplete message: got: %d, expected:%d",
458 			ret, sizeof(msg));
459 		return;
460 	}
461 
462 	LOG_DBG("Passing message %d to wpa_supplicant", msg.event);
463 
464 	if (msg.global) {
465 		wpa_supplicant_event_global(msg.ctx, msg.event, msg.data);
466 	} else {
467 		wpa_supplicant_event(msg.ctx, msg.event, msg.data);
468 	}
469 
470 	if (msg.data) {
471 		union wpa_event_data *data = msg.data;
472 
473 		/* Free up deep copied data */
474 		if (msg.event == EVENT_AUTH) {
475 			os_free((char *)data->auth.ies);
476 		} else if (msg.event == EVENT_RX_MGMT) {
477 			os_free((char *)data->rx_mgmt.frame);
478 		} else if (msg.event == EVENT_TX_STATUS) {
479 			os_free((char *)data->tx_status.data);
480 		} else if (msg.event == EVENT_ASSOC) {
481 			os_free((char *)data->assoc_info.addr);
482 			os_free((char *)data->assoc_info.req_ies);
483 			os_free((char *)data->assoc_info.resp_ies);
484 			os_free((char *)data->assoc_info.resp_frame);
485 		} else if (msg.event == EVENT_ASSOC_REJECT) {
486 			os_free((char *)data->assoc_reject.bssid);
487 			os_free((char *)data->assoc_reject.resp_ies);
488 		} else if (msg.event == EVENT_DEAUTH) {
489 			os_free((char *)data->deauth_info.addr);
490 			os_free((char *)data->deauth_info.ie);
491 		} else if (msg.event == EVENT_DISASSOC) {
492 			os_free((char *)data->disassoc_info.addr);
493 			os_free((char *)data->disassoc_info.ie);
494 		} else if (msg.event == EVENT_UNPROT_DEAUTH) {
495 			os_free((char *)data->unprot_deauth.sa);
496 			os_free((char *)data->unprot_deauth.da);
497 		} else if (msg.event == EVENT_UNPROT_DISASSOC) {
498 			os_free((char *)data->unprot_disassoc.sa);
499 			os_free((char *)data->unprot_disassoc.da);
500 		}
501 
502 		os_free(msg.data);
503 	}
504 }
505 
register_supplicant_event_socket(struct supplicant_context * ctx)506 static int register_supplicant_event_socket(struct supplicant_context *ctx)
507 {
508 	int ret;
509 
510 	ret = socketpair(AF_UNIX, SOCK_STREAM, 0, ctx->event_socketpair);
511 	if (ret < 0) {
512 		ret = -errno;
513 		LOG_ERR("Failed to initialize socket (%d)", ret);
514 		return ret;
515 	}
516 
517 	eloop_register_read_sock(ctx->event_socketpair[0], event_socket_handler, NULL, ctx);
518 
519 	return 0;
520 }
521 
handler(void)522 static void handler(void)
523 {
524 	struct supplicant_context *ctx;
525 	struct wpa_params params;
526 
527 #if !defined(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE) && !defined(CONFIG_MBEDTLS_ENABLE_HEAP)
528 	/* Needed for crypto operation as default is no-op and fails */
529 	mbedtls_platform_set_calloc_free(calloc, free);
530 #endif /* !CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE && !CONFIG_MBEDTLS_ENABLE_HEAP */
531 
532 #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_MBEDTLS_PSA
533 	supp_psa_crypto_init();
534 #endif
535 
536 	ctx = get_default_context();
537 
538 	k_work_queue_init(&ctx->iface_wq);
539 	k_work_queue_start(&ctx->iface_wq, iface_wq_stack,
540 			   K_THREAD_STACK_SIZEOF(iface_wq_stack),
541 			   CONFIG_WIFI_NM_WPA_SUPPLICANT_WQ_PRIO,
542 			   NULL);
543 
544 	k_work_init(&ctx->iface_work, iface_work_handler);
545 
546 	memset(&params, 0, sizeof(params));
547 	params.wpa_debug_level = CONFIG_WIFI_NM_WPA_SUPPLICANT_DEBUG_LEVEL;
548 
549 	ctx->supplicant = wpa_supplicant_init(&params);
550 	if (ctx->supplicant == NULL) {
551 		LOG_ERR("Failed to initialize %s", "wpa_supplicant");
552 		goto err;
553 	}
554 
555 	LOG_INF("%s initialized", "wpa_supplicant");
556 
557 	if (fst_global_init()) {
558 		LOG_ERR("Failed to initialize %s", "FST");
559 		goto out;
560 	}
561 
562 #if defined(CONFIG_FST) && defined(CONFIG_CTRL_IFACE)
563 	if (!fst_global_add_ctrl(fst_ctrl_cli)) {
564 		LOG_WRN("Failed to add CLI FST ctrl");
565 	}
566 #endif
567 	zephyr_global_wpa_ctrl_init();
568 
569 	register_supplicant_event_socket(ctx);
570 
571 	submit_iface_work(ctx, NULL, setup_interface_monitoring);
572 
573 	(void)wpa_supplicant_run(ctx->supplicant);
574 
575 	supplicant_generate_state_event(ctx->if_name, NET_EVENT_SUPPLICANT_CMD_NOT_READY, 0);
576 
577 	eloop_unregister_read_sock(ctx->event_socketpair[0]);
578 
579 	zephyr_global_wpa_ctrl_deinit();
580 
581 	fst_global_deinit();
582 
583 out:
584 	wpa_supplicant_deinit(ctx->supplicant);
585 
586 	zsock_close(ctx->event_socketpair[0]);
587 	zsock_close(ctx->event_socketpair[1]);
588 
589 err:
590 	os_free(params.pid_file);
591 }
592 
init(void)593 static int init(void)
594 {
595 	/* We create a thread that handles all supplicant connections */
596 	k_thread_create(&tid, supplicant_thread_stack,
597 			K_THREAD_STACK_SIZEOF(supplicant_thread_stack),
598 			(k_thread_entry_t)handler, NULL, NULL, NULL,
599 			0, 0, K_NO_WAIT);
600 
601 	return 0;
602 }
603 
604 SYS_INIT(init, APPLICATION, 0);
605