1 /*
2  * Copyright (c) 2025 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  *   This file implements the OpenThread module initialization and state change handling.
10  *
11  */
12 
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(net_openthread_platform, CONFIG_OPENTHREAD_PLATFORM_LOG_LEVEL);
15 
16 #include <zephyr/kernel.h>
17 #include <zephyr/init.h>
18 #include <zephyr/version.h>
19 #include <zephyr/sys/check.h>
20 
21 #include "platform/platform-zephyr.h"
22 
23 #include <openthread.h>
24 #include <openthread_utils.h>
25 
26 #include <openthread/child_supervision.h>
27 #include <openthread/cli.h>
28 #include <openthread/ip6.h>
29 #include <openthread/link.h>
30 #include <openthread/link_raw.h>
31 #include <openthread/ncp.h>
32 #include <openthread/message.h>
33 #include <openthread/platform/diag.h>
34 #include <openthread/tasklet.h>
35 #include <openthread/thread.h>
36 #include <openthread/thread_ftd.h>
37 #include <openthread/dataset.h>
38 #include <openthread/joiner.h>
39 #include <openthread-system.h>
40 #include <utils/uart.h>
41 
42 #if defined(CONFIG_OPENTHREAD_NAT64_TRANSLATOR)
43 #include <openthread/nat64.h>
44 #endif /* CONFIG_OPENTHREAD_NAT64_TRANSLATOR */
45 
46 #define OT_STACK_SIZE (CONFIG_OPENTHREAD_THREAD_STACK_SIZE)
47 
48 #if defined(CONFIG_OPENTHREAD_THREAD_PREEMPTIVE)
49 #define OT_PRIORITY K_PRIO_PREEMPT(CONFIG_OPENTHREAD_THREAD_PRIORITY)
50 #else
51 #define OT_PRIORITY K_PRIO_COOP(CONFIG_OPENTHREAD_THREAD_PRIORITY)
52 #endif
53 
54 #if defined(CONFIG_OPENTHREAD_NETWORK_NAME)
55 #define OT_NETWORK_NAME CONFIG_OPENTHREAD_NETWORK_NAME
56 #else
57 #define OT_NETWORK_NAME ""
58 #endif
59 
60 #if defined(CONFIG_OPENTHREAD_CHANNEL)
61 #define OT_CHANNEL CONFIG_OPENTHREAD_CHANNEL
62 #else
63 #define OT_CHANNEL 0
64 #endif
65 
66 #if defined(CONFIG_OPENTHREAD_PANID)
67 #define OT_PANID CONFIG_OPENTHREAD_PANID
68 #else
69 #define OT_PANID 0
70 #endif
71 
72 #if defined(CONFIG_OPENTHREAD_XPANID)
73 #define OT_XPANID CONFIG_OPENTHREAD_XPANID
74 #else
75 #define OT_XPANID ""
76 #endif
77 
78 #if defined(CONFIG_OPENTHREAD_NETWORKKEY)
79 #define OT_NETWORKKEY CONFIG_OPENTHREAD_NETWORKKEY
80 #else
81 #define OT_NETWORKKEY ""
82 #endif
83 
84 #if defined(CONFIG_OPENTHREAD_JOINER_PSKD)
85 #define OT_JOINER_PSKD CONFIG_OPENTHREAD_JOINER_PSKD
86 #else
87 #define OT_JOINER_PSKD ""
88 #endif
89 
90 #if defined(CONFIG_OPENTHREAD_PLATFORM_INFO)
91 #define OT_PLATFORM_INFO CONFIG_OPENTHREAD_PLATFORM_INFO
92 #else
93 #define OT_PLATFORM_INFO ""
94 #endif
95 
96 #if defined(CONFIG_OPENTHREAD_POLL_PERIOD)
97 #define OT_POLL_PERIOD CONFIG_OPENTHREAD_POLL_PERIOD
98 #else
99 #define OT_POLL_PERIOD 0
100 #endif
101 
102 #if defined(CONFIG_OPENTHREAD_ROUTER_SELECTION_JITTER)
103 #define OT_ROUTER_SELECTION_JITTER CONFIG_OPENTHREAD_ROUTER_SELECTION_JITTER
104 #else
105 #define OT_ROUTER_SELECTION_JITTER 0
106 #endif
107 
108 #define ZEPHYR_PACKAGE_NAME "Zephyr"
109 #define PACKAGE_VERSION     KERNEL_VERSION_STRING
110 
111 static void openthread_process(struct k_work *work);
112 
113 /* Global variables to store the OpenThread module context */
114 static otInstance *openthread_instance;
115 static sys_slist_t openthread_state_change_cbs = SYS_SLIST_STATIC_INIT(openthread_state_change_cbs);
116 static struct k_work_q openthread_work_q;
117 
118 static K_WORK_DEFINE(openthread_work, openthread_process);
119 static K_MUTEX_DEFINE(openthread_lock);
120 K_KERNEL_STACK_DEFINE(ot_stack_area, OT_STACK_SIZE);
121 
openthread_thread_id_get(void)122 k_tid_t openthread_thread_id_get(void)
123 {
124 	return (k_tid_t)&openthread_work_q.thread;
125 }
126 
ncp_hdlc_send(const uint8_t * buf,uint16_t len)127 static int ncp_hdlc_send(const uint8_t *buf, uint16_t len)
128 {
129 	otError err = OT_ERROR_NONE;
130 
131 	err = otPlatUartSend(buf, len);
132 	if (err != OT_ERROR_NONE) {
133 		return 0;
134 	}
135 
136 	return len;
137 }
138 
openthread_process(struct k_work * work)139 static void openthread_process(struct k_work *work)
140 {
141 	ARG_UNUSED(work);
142 
143 	openthread_mutex_lock();
144 
145 	while (otTaskletsArePending(openthread_instance)) {
146 		otTaskletsProcess(openthread_instance);
147 	}
148 
149 	otSysProcessDrivers(openthread_instance);
150 
151 	openthread_mutex_unlock();
152 }
153 
ot_joiner_start_handler(otError error,void * context)154 static void ot_joiner_start_handler(otError error, void *context)
155 {
156 	ARG_UNUSED(context);
157 
158 	if (error != OT_ERROR_NONE) {
159 		LOG_ERR("Join failed [%d]", error);
160 	} else {
161 		LOG_INF("Join success");
162 		error = otThreadSetEnabled(openthread_instance, true);
163 		if (error != OT_ERROR_NONE) {
164 			LOG_ERR("Failed to start the OpenThread network [%d]", error);
165 		}
166 	}
167 }
168 
ot_setup_default_configuration(void)169 static bool ot_setup_default_configuration(void)
170 {
171 	otExtendedPanId xpanid = {0};
172 	otNetworkKey networkKey = {0};
173 	otError error = OT_ERROR_NONE;
174 
175 	error = otThreadSetNetworkName(openthread_instance, OT_NETWORK_NAME);
176 	if (error != OT_ERROR_NONE) {
177 		LOG_ERR("Failed to set %s [%d]", "network name", error);
178 		return false;
179 	}
180 
181 	error = otLinkSetChannel(openthread_instance, OT_CHANNEL);
182 	if (error != OT_ERROR_NONE) {
183 		LOG_ERR("Failed to set %s [%d]", "channel", error);
184 		return false;
185 	}
186 
187 	error = otLinkSetPanId(openthread_instance, OT_PANID);
188 	if (error != OT_ERROR_NONE) {
189 		LOG_ERR("Failed to set %s [%d]", "PAN ID", error);
190 		return false;
191 	}
192 
193 	if (bytes_from_str(xpanid.m8, 8, (char *)OT_XPANID) != 0) {
194 		LOG_ERR("Failed to parse extended PAN ID");
195 		return false;
196 	}
197 	error = otThreadSetExtendedPanId(openthread_instance, &xpanid);
198 	if (error != OT_ERROR_NONE) {
199 		LOG_ERR("Failed to set %s [%d]", "ext PAN ID", error);
200 		return false;
201 	}
202 
203 	if (strlen(OT_NETWORKKEY)) {
204 		if (bytes_from_str(networkKey.m8, OT_NETWORK_KEY_SIZE, (char *)OT_NETWORKKEY) !=
205 		    0) {
206 			LOG_ERR("Failed to parse network key");
207 			return false;
208 		}
209 		error = otThreadSetNetworkKey(openthread_instance, &networkKey);
210 		if (error != OT_ERROR_NONE) {
211 			LOG_ERR("Failed to set %s [%d]", "network key", error);
212 			return false;
213 		}
214 	}
215 
216 	return true;
217 }
218 
ot_state_changed_handler(uint32_t flags,void * context)219 static void ot_state_changed_handler(uint32_t flags, void *context)
220 {
221 	ARG_UNUSED(context);
222 
223 	struct openthread_state_changed_callback *entry, *next;
224 
225 	bool is_up = otIp6IsEnabled(openthread_instance);
226 
227 	LOG_INF("State changed! Flags: 0x%08" PRIx32 " Current role: %s Ip6: %s", flags,
228 		otThreadDeviceRoleToString(otThreadGetDeviceRole(openthread_instance)),
229 		(is_up ? "up" : "down"));
230 
231 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&openthread_state_change_cbs, entry, next, node) {
232 		if (entry->otCallback != NULL) {
233 			entry->otCallback(flags, entry->user_data);
234 		}
235 	}
236 }
237 
otTaskletsSignalPending(otInstance * instance)238 void otTaskletsSignalPending(otInstance *instance)
239 {
240 	ARG_UNUSED(instance);
241 
242 	int error = k_work_submit_to_queue(&openthread_work_q, &openthread_work);
243 
244 	if (error < 0) {
245 		LOG_ERR("Failed to submit work to queue, error: %d", error);
246 	}
247 }
248 
otSysEventSignalPending(void)249 void otSysEventSignalPending(void)
250 {
251 	otTaskletsSignalPending(NULL);
252 }
253 
openthread_state_changed_callback_register(struct openthread_state_changed_callback * cb)254 int openthread_state_changed_callback_register(struct openthread_state_changed_callback *cb)
255 {
256 	CHECKIF(cb == NULL || cb->otCallback == NULL) {
257 		return -EINVAL;
258 	}
259 
260 	openthread_mutex_lock();
261 	sys_slist_append(&openthread_state_change_cbs, &cb->node);
262 	openthread_mutex_unlock();
263 
264 	return 0;
265 }
266 
openthread_state_changed_callback_unregister(struct openthread_state_changed_callback * cb)267 int openthread_state_changed_callback_unregister(struct openthread_state_changed_callback *cb)
268 {
269 	bool removed = false;
270 
271 	CHECKIF(cb == NULL) {
272 		return -EINVAL;
273 	}
274 
275 	openthread_mutex_lock();
276 	removed = sys_slist_find_and_remove(&openthread_state_change_cbs, &cb->node);
277 	openthread_mutex_unlock();
278 
279 	if (!removed) {
280 		return -EALREADY;
281 	}
282 
283 	return 0;
284 }
285 
openthread_get_default_instance(void)286 struct otInstance *openthread_get_default_instance(void)
287 {
288 	__ASSERT(openthread_instance, "OT instance is not initialized");
289 	return openthread_instance;
290 }
291 
openthread_init(void)292 int openthread_init(void)
293 {
294 	struct k_work_queue_config q_cfg = {
295 		.name = "openthread",
296 		.no_yield = true,
297 	};
298 	otError error = OT_ERROR_NONE;
299 
300 	/* Prevent multiple initializations */
301 	if (openthread_instance) {
302 		return 0;
303 	}
304 
305 	/* Initialize the OpenThread work queue */
306 	k_work_queue_init(&openthread_work_q);
307 
308 	/* Start work queue for the OpenThread module */
309 	k_work_queue_start(&openthread_work_q, ot_stack_area,
310 			   K_KERNEL_STACK_SIZEOF(ot_stack_area),
311 			   OT_PRIORITY, &q_cfg);
312 
313 	openthread_mutex_lock();
314 
315 	otSysInit(0, NULL);
316 	openthread_instance = otInstanceInitSingle();
317 
318 	__ASSERT(openthread_instance, "OT instance initialization failed");
319 
320 	if (IS_ENABLED(CONFIG_OPENTHREAD_SHELL)) {
321 		platformShellInit(openthread_instance);
322 	}
323 
324 	if (IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR)) {
325 		error = otPlatUartEnable();
326 		if (error != OT_ERROR_NONE) {
327 			LOG_ERR("Failed to enable UART: [%d]", error);
328 		}
329 
330 		otNcpHdlcInit(openthread_instance, ncp_hdlc_send);
331 	} else {
332 		otIp6SetReceiveFilterEnabled(openthread_instance, true);
333 
334 #if defined(CONFIG_OPENTHREAD_NAT64_TRANSLATOR)
335 
336 		otIp4Cidr nat64_cidr;
337 
338 		if (otIp4CidrFromString(CONFIG_OPENTHREAD_NAT64_CIDR, &nat64_cidr) ==
339 		    OT_ERROR_NONE) {
340 			if (otNat64SetIp4Cidr(openthread_instance, &nat64_cidr) != OT_ERROR_NONE) {
341 				LOG_ERR("Incorrect NAT64 CIDR");
342 				return -EIO;
343 			}
344 		} else {
345 			LOG_ERR("Failed to parse NAT64 CIDR");
346 			return -EIO;
347 		}
348 #endif /* CONFIG_OPENTHREAD_NAT64_TRANSLATOR */
349 
350 		error = otSetStateChangedCallback(openthread_instance, &ot_state_changed_handler,
351 						  NULL);
352 		if (error != OT_ERROR_NONE) {
353 			LOG_ERR("Could not set state changed callback: %d", error);
354 			return -EIO;
355 		}
356 	}
357 
358 	if (IS_ENABLED(CONFIG_OPENTHREAD_ROUTER_SELECTION_JITTER_OVERRIDE)) {
359 		otThreadSetRouterSelectionJitter(openthread_instance, OT_ROUTER_SELECTION_JITTER);
360 	}
361 
362 	openthread_mutex_unlock();
363 
364 	(void)k_work_submit_to_queue(&openthread_work_q, &openthread_work);
365 
366 	return error == OT_ERROR_NONE ? 0 : -EIO;
367 }
368 
openthread_run(void)369 int openthread_run(void)
370 {
371 	openthread_mutex_lock();
372 	otError error = OT_ERROR_NONE;
373 
374 	LOG_INF("OpenThread version: %s", otGetVersionString());
375 
376 	if (IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR)) {
377 		LOG_DBG("OpenThread co-processor.");
378 		goto exit;
379 	}
380 
381 	error = otIp6SetEnabled(openthread_instance, true);
382 	if (error != OT_ERROR_NONE) {
383 		LOG_ERR("Failed to set %s [%d]", "IPv6 support", error);
384 		goto exit;
385 	}
386 
387 	/* Sleepy End Device specific configuration. */
388 	if (IS_ENABLED(CONFIG_OPENTHREAD_MTD_SED)) {
389 		otLinkModeConfig ot_mode = otThreadGetLinkMode(openthread_instance);
390 
391 		/* A SED should always attach the network as a SED to indicate
392 		 * increased buffer requirement to a parent.
393 		 */
394 		ot_mode.mRxOnWhenIdle = false;
395 
396 		error = otThreadSetLinkMode(openthread_instance, ot_mode);
397 		if (error != OT_ERROR_NONE) {
398 			LOG_ERR("Failed to set %s [%d]", "link mode", error);
399 			goto exit;
400 		}
401 
402 		error = otLinkSetPollPeriod(openthread_instance, OT_POLL_PERIOD);
403 		if (error != OT_ERROR_NONE) {
404 			LOG_ERR("Failed to set %s [%d]", "poll period", error);
405 			goto exit;
406 		}
407 	}
408 
409 	/* Configure Child Supervision and MLE Child timeouts. */
410 	otChildSupervisionSetInterval(openthread_instance,
411 				      CONFIG_OPENTHREAD_CHILD_SUPERVISION_INTERVAL);
412 	otChildSupervisionSetCheckTimeout(openthread_instance,
413 					  CONFIG_OPENTHREAD_CHILD_SUPERVISION_CHECK_TIMEOUT);
414 	otThreadSetChildTimeout(openthread_instance, CONFIG_OPENTHREAD_MLE_CHILD_TIMEOUT);
415 
416 	if (otDatasetIsCommissioned(openthread_instance)) {
417 		/* OpenThread already has dataset stored - skip the
418 		 * configuration.
419 		 */
420 		LOG_DBG("OpenThread already commissioned.");
421 	} else if (IS_ENABLED(CONFIG_OPENTHREAD_JOINER_AUTOSTART)) {
422 		/* No dataset - initiate network join procedure. */
423 		LOG_DBG("Starting OpenThread join procedure.");
424 
425 		error = otJoinerStart(openthread_instance, OT_JOINER_PSKD, NULL,
426 				      ZEPHYR_PACKAGE_NAME, OT_PLATFORM_INFO, PACKAGE_VERSION, NULL,
427 				      &ot_joiner_start_handler, NULL);
428 
429 		if (error != OT_ERROR_NONE) {
430 			LOG_ERR("Failed to start joiner [%d]", error);
431 		}
432 
433 		goto exit;
434 	} else {
435 		/* No dataset - load the default configuration. */
436 		LOG_DBG("Loading OpenThread default configuration.");
437 
438 		if (!ot_setup_default_configuration()) {
439 			goto exit;
440 		}
441 	}
442 
443 	LOG_INF("Network name: %s", otThreadGetNetworkName(openthread_instance));
444 
445 	/* Start the network. */
446 	error = otThreadSetEnabled(openthread_instance, true);
447 	if (error != OT_ERROR_NONE) {
448 		LOG_ERR("Failed to start the OpenThread network [%d]", error);
449 	}
450 
451 exit:
452 
453 	openthread_mutex_unlock();
454 
455 	return error == OT_ERROR_NONE ? 0 : -EIO;
456 }
457 
openthread_stop(void)458 int openthread_stop(void)
459 {
460 	otError error = OT_ERROR_NONE;
461 
462 	if (IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR)) {
463 		return 0;
464 	}
465 
466 	openthread_mutex_lock();
467 
468 	error = otThreadSetEnabled(openthread_instance, false);
469 	if (error == OT_ERROR_INVALID_STATE) {
470 		LOG_DBG("Openthread interface was not up [%d]", error);
471 	}
472 
473 	openthread_mutex_unlock();
474 
475 	return 0;
476 }
477 
openthread_set_receive_cb(openthread_receive_cb cb,void * context)478 void openthread_set_receive_cb(openthread_receive_cb cb, void *context)
479 {
480 	__ASSERT(cb != NULL, "Receive callback is not set");
481 	__ASSERT(openthread_instance != NULL, "OpenThread instance is not initialized");
482 
483 	if (!IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR)) {
484 		openthread_mutex_lock();
485 		otIp6SetReceiveCallback(openthread_instance, cb, context);
486 
487 #if defined(CONFIG_OPENTHREAD_NAT64_TRANSLATOR)
488 		otNat64SetReceiveIp4Callback(openthread_instance, cb, context);
489 #endif /* CONFIG_OPENTHREAD_NAT64_TRANSLATOR */
490 
491 		openthread_mutex_unlock();
492 	}
493 }
494 
openthread_mutex_lock(void)495 void openthread_mutex_lock(void)
496 {
497 	(void)k_mutex_lock(&openthread_lock, K_FOREVER);
498 }
499 
openthread_mutex_try_lock(void)500 int openthread_mutex_try_lock(void)
501 {
502 	return k_mutex_lock(&openthread_lock, K_NO_WAIT);
503 }
504 
openthread_mutex_unlock(void)505 void openthread_mutex_unlock(void)
506 {
507 	(void)k_mutex_unlock(&openthread_lock);
508 }
509 
510 #ifdef CONFIG_OPENTHREAD_SYS_INIT
openthread_sys_init(void)511 static int openthread_sys_init(void)
512 {
513 	int error = openthread_init();
514 
515 	if (error == 0) {
516 #ifndef CONFIG_OPENTHREAD_MANUAL_START
517 		error = openthread_run();
518 #endif
519 	}
520 
521 	return error;
522 }
523 
524 SYS_INIT(openthread_sys_init, POST_KERNEL, CONFIG_OPENTHREAD_SYS_INIT_PRIORITY);
525 #endif /* CONFIG_OPENTHREAD_SYS_INIT */
526