1 /*
2  * Copyright (c) 2018 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(net_l2_openthread, CONFIG_OPENTHREAD_L2_LOG_LEVEL);
9 
10 #include <zephyr/net/net_core.h>
11 #include <zephyr/net/net_pkt.h>
12 #include <zephyr/net/net_mgmt.h>
13 #include <zephyr/net/openthread.h>
14 
15 #include <net_private.h>
16 
17 #include <zephyr/init.h>
18 #include <zephyr/sys/check.h>
19 #include <zephyr/sys/slist.h>
20 #include <zephyr/sys/util.h>
21 #include <zephyr/sys/__assert.h>
22 #include <version.h>
23 
24 #include <openthread/cli.h>
25 #include <openthread/ip6.h>
26 #include <openthread/link.h>
27 #include <openthread/link_raw.h>
28 #include <openthread/ncp.h>
29 #include <openthread/message.h>
30 #include <openthread/platform/diag.h>
31 #include <openthread/tasklet.h>
32 #include <openthread/thread.h>
33 #include <openthread/dataset.h>
34 #include <openthread/joiner.h>
35 #include <openthread-system.h>
36 #include <utils/uart.h>
37 
38 #include <platform-zephyr.h>
39 
40 #include "openthread_utils.h"
41 
42 #define OT_STACK_SIZE (CONFIG_OPENTHREAD_THREAD_STACK_SIZE)
43 
44 #if defined(CONFIG_OPENTHREAD_THREAD_PREEMPTIVE)
45 #define OT_PRIORITY K_PRIO_PREEMPT(CONFIG_OPENTHREAD_THREAD_PRIORITY)
46 #else
47 #define OT_PRIORITY K_PRIO_COOP(CONFIG_OPENTHREAD_THREAD_PRIORITY)
48 #endif
49 
50 #if defined(CONFIG_OPENTHREAD_NETWORK_NAME)
51 #define OT_NETWORK_NAME CONFIG_OPENTHREAD_NETWORK_NAME
52 #else
53 #define OT_NETWORK_NAME ""
54 #endif
55 
56 #if defined(CONFIG_OPENTHREAD_CHANNEL)
57 #define OT_CHANNEL CONFIG_OPENTHREAD_CHANNEL
58 #else
59 #define OT_CHANNEL 0
60 #endif
61 
62 #if defined(CONFIG_OPENTHREAD_PANID)
63 #define OT_PANID CONFIG_OPENTHREAD_PANID
64 #else
65 #define OT_PANID 0
66 #endif
67 
68 #if defined(CONFIG_OPENTHREAD_XPANID)
69 #define OT_XPANID CONFIG_OPENTHREAD_XPANID
70 #else
71 #define OT_XPANID ""
72 #endif
73 
74 #if defined(CONFIG_OPENTHREAD_NETWORKKEY)
75 #define OT_NETWORKKEY CONFIG_OPENTHREAD_NETWORKKEY
76 #else
77 #define OT_NETWORKKEY ""
78 #endif
79 
80 #if defined(CONFIG_OPENTHREAD_JOINER_PSKD)
81 #define OT_JOINER_PSKD CONFIG_OPENTHREAD_JOINER_PSKD
82 #else
83 #define OT_JOINER_PSKD ""
84 #endif
85 
86 #if defined(CONFIG_OPENTHREAD_PLATFORM_INFO)
87 #define OT_PLATFORM_INFO CONFIG_OPENTHREAD_PLATFORM_INFO
88 #else
89 #define OT_PLATFORM_INFO ""
90 #endif
91 
92 #if defined(CONFIG_OPENTHREAD_POLL_PERIOD)
93 #define OT_POLL_PERIOD CONFIG_OPENTHREAD_POLL_PERIOD
94 #else
95 #define OT_POLL_PERIOD 0
96 #endif
97 
98 #define PACKAGE_NAME "Zephyr"
99 #define PACKAGE_VERSION KERNEL_VERSION_STRING
100 
101 extern void platformShellInit(otInstance *aInstance);
102 
103 K_KERNEL_STACK_DEFINE(ot_stack_area, OT_STACK_SIZE);
104 
105 static struct net_linkaddr *ll_addr;
106 static otStateChangedCallback state_changed_cb;
107 
openthread_thread_id_get(void)108 k_tid_t openthread_thread_id_get(void)
109 {
110 	struct openthread_context *ot_context = openthread_get_default_context();
111 
112 	return ot_context ? (k_tid_t)&ot_context->work_q.thread : 0;
113 }
114 
115 #ifdef CONFIG_NET_MGMT_EVENT
116 static struct net_mgmt_event_callback ip6_addr_cb;
117 
ipv6_addr_event_handler(struct net_mgmt_event_callback * cb,uint32_t mgmt_event,struct net_if * iface)118 static void ipv6_addr_event_handler(struct net_mgmt_event_callback *cb,
119 				    uint32_t mgmt_event, struct net_if *iface)
120 {
121 	if (net_if_l2(iface) != &NET_L2_GET_NAME(OPENTHREAD)) {
122 		return;
123 	}
124 
125 #ifdef CONFIG_NET_MGMT_EVENT_INFO
126 	struct openthread_context *ot_context = net_if_l2_data(iface);
127 
128 	if (cb->info == NULL || cb->info_length != sizeof(struct in6_addr)) {
129 		return;
130 	}
131 
132 	if (mgmt_event == NET_EVENT_IPV6_ADDR_ADD) {
133 		add_ipv6_addr_to_ot(ot_context, (const struct in6_addr *)cb->info);
134 	} else if (mgmt_event == NET_EVENT_IPV6_MADDR_ADD) {
135 		add_ipv6_maddr_to_ot(ot_context, (const struct in6_addr *)cb->info);
136 	}
137 #else
138 	NET_WARN("No address info provided with event, "
139 		 "please enable CONFIG_NET_MGMT_EVENT_INFO");
140 #endif /* CONFIG_NET_MGMT_EVENT_INFO */
141 }
142 #endif /* CONFIG_NET_MGMT_EVENT */
143 
ncp_hdlc_send(const uint8_t * buf,uint16_t len)144 static int ncp_hdlc_send(const uint8_t *buf, uint16_t len)
145 {
146 	otError err;
147 
148 	err = otPlatUartSend(buf, len);
149 	if (err != OT_ERROR_NONE) {
150 		return 0;
151 	}
152 
153 	return len;
154 }
155 
otPlatRadioGetIeeeEui64(otInstance * instance,uint8_t * ieee_eui64)156 void otPlatRadioGetIeeeEui64(otInstance *instance, uint8_t *ieee_eui64)
157 {
158 	ARG_UNUSED(instance);
159 
160 	memcpy(ieee_eui64, ll_addr->addr, ll_addr->len);
161 }
162 
otTaskletsSignalPending(otInstance * instance)163 void otTaskletsSignalPending(otInstance *instance)
164 {
165 	struct openthread_context *ot_context = openthread_get_default_context();
166 
167 	if (ot_context) {
168 		k_work_submit_to_queue(&ot_context->work_q, &ot_context->api_work);
169 	}
170 }
171 
otSysEventSignalPending(void)172 void otSysEventSignalPending(void)
173 {
174 	otTaskletsSignalPending(NULL);
175 }
176 
ot_state_changed_handler(uint32_t flags,void * context)177 static void ot_state_changed_handler(uint32_t flags, void *context)
178 {
179 	struct openthread_state_changed_cb *entry, *next;
180 	struct openthread_context *ot_context = context;
181 
182 	NET_INFO("State changed! Flags: 0x%08" PRIx32 " Current role: %s",
183 		flags,
184 		otThreadDeviceRoleToString(otThreadGetDeviceRole(ot_context->instance))
185 		);
186 
187 	if (flags & OT_CHANGED_THREAD_ROLE) {
188 		switch (otThreadGetDeviceRole(ot_context->instance)) {
189 		case OT_DEVICE_ROLE_CHILD:
190 		case OT_DEVICE_ROLE_ROUTER:
191 		case OT_DEVICE_ROLE_LEADER:
192 			net_if_dormant_off(ot_context->iface);
193 			break;
194 
195 		case OT_DEVICE_ROLE_DISABLED:
196 		case OT_DEVICE_ROLE_DETACHED:
197 		default:
198 			net_if_dormant_on(ot_context->iface);
199 			break;
200 		}
201 	}
202 
203 	if (flags & OT_CHANGED_IP6_ADDRESS_REMOVED) {
204 		NET_DBG("Ipv6 address removed");
205 		rm_ipv6_addr_from_zephyr(ot_context);
206 	}
207 
208 	if (flags & OT_CHANGED_IP6_ADDRESS_ADDED) {
209 		NET_DBG("Ipv6 address added");
210 		add_ipv6_addr_to_zephyr(ot_context);
211 	}
212 
213 	if (flags & OT_CHANGED_IP6_MULTICAST_UNSUBSCRIBED) {
214 		NET_DBG("Ipv6 multicast address removed");
215 		rm_ipv6_maddr_from_zephyr(ot_context);
216 	}
217 
218 	if (flags & OT_CHANGED_IP6_MULTICAST_SUBSCRIBED) {
219 		NET_DBG("Ipv6 multicast address added");
220 		add_ipv6_maddr_to_zephyr(ot_context);
221 	}
222 
223 	if (state_changed_cb) {
224 		state_changed_cb(flags, context);
225 	}
226 
227 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&ot_context->state_change_cbs, entry, next, node) {
228 		if (entry->state_changed_cb != NULL) {
229 			entry->state_changed_cb(flags, ot_context, entry->user_data);
230 		}
231 	}
232 }
233 
ot_receive_handler(otMessage * aMessage,void * context)234 static void ot_receive_handler(otMessage *aMessage, void *context)
235 {
236 	struct openthread_context *ot_context = context;
237 
238 	uint16_t offset = 0U;
239 	uint16_t read_len;
240 	struct net_pkt *pkt;
241 	struct net_buf *pkt_buf;
242 
243 	pkt = net_pkt_rx_alloc_with_buffer(ot_context->iface,
244 					   otMessageGetLength(aMessage),
245 					   AF_UNSPEC, 0, K_NO_WAIT);
246 	if (!pkt) {
247 		NET_ERR("Failed to reserve net pkt");
248 		goto out;
249 	}
250 
251 	pkt_buf = pkt->buffer;
252 
253 	while (1) {
254 		read_len = otMessageRead(aMessage, offset, pkt_buf->data,
255 					 net_buf_tailroom(pkt_buf));
256 		if (!read_len) {
257 			break;
258 		}
259 
260 		net_buf_add(pkt_buf, read_len);
261 
262 		offset += read_len;
263 
264 		if (!net_buf_tailroom(pkt_buf)) {
265 			pkt_buf = pkt_buf->frags;
266 			if (!pkt_buf) {
267 				break;
268 			}
269 		}
270 	}
271 
272 	NET_DBG("Injecting Ip6 packet to Zephyr net stack");
273 
274 	if (IS_ENABLED(CONFIG_OPENTHREAD_L2_DEBUG_DUMP_IPV6)) {
275 		net_pkt_hexdump(pkt, "Received IPv6 packet");
276 	}
277 
278 	if (!pkt_list_is_full(ot_context)) {
279 		if (pkt_list_add(ot_context, pkt) != 0) {
280 			NET_ERR("pkt_list_add failed");
281 			goto out;
282 		}
283 
284 		if (net_recv_data(ot_context->iface, pkt) < 0) {
285 			NET_ERR("net_recv_data failed");
286 			pkt_list_remove_first(ot_context);
287 			goto out;
288 		}
289 
290 		pkt = NULL;
291 	} else {
292 		NET_INFO("Packet list is full");
293 	}
294 out:
295 	if (pkt) {
296 		net_pkt_unref(pkt);
297 	}
298 
299 	otMessageFree(aMessage);
300 }
301 
ot_joiner_start_handler(otError error,void * context)302 static void ot_joiner_start_handler(otError error, void *context)
303 {
304 	struct openthread_context *ot_context = context;
305 
306 	switch (error) {
307 	case OT_ERROR_NONE:
308 		NET_INFO("Join success");
309 		otThreadSetEnabled(ot_context->instance, true);
310 		break;
311 	default:
312 		NET_ERR("Join failed [%d]", error);
313 		break;
314 	}
315 }
316 
openthread_process(struct k_work * work)317 static void openthread_process(struct k_work *work)
318 {
319 	struct openthread_context *ot_context
320 		= CONTAINER_OF(work, struct openthread_context, api_work);
321 
322 	openthread_api_mutex_lock(ot_context);
323 
324 	while (otTaskletsArePending(ot_context->instance)) {
325 		otTaskletsProcess(ot_context->instance);
326 	}
327 
328 	otSysProcessDrivers(ot_context->instance);
329 
330 	openthread_api_mutex_unlock(ot_context);
331 }
332 
is_ipv6_frag(struct net_pkt * pkt)333 static bool is_ipv6_frag(struct net_pkt *pkt)
334 {
335 	NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv6_access, struct net_ipv6_hdr);
336 	struct net_ipv6_hdr *hdr;
337 
338 	hdr = (struct net_ipv6_hdr *)net_pkt_get_data(pkt, &ipv6_access);
339 	if (!hdr) {
340 		return false;
341 	}
342 
343 	return hdr->nexthdr == NET_IPV6_NEXTHDR_FRAG ? true : false;
344 }
345 
openthread_recv(struct net_if * iface,struct net_pkt * pkt)346 static enum net_verdict openthread_recv(struct net_if *iface, struct net_pkt *pkt)
347 {
348 	struct openthread_context *ot_context = net_if_l2_data(iface);
349 
350 	if (pkt_list_peek(ot_context) == pkt) {
351 		pkt_list_remove_last(ot_context);
352 		NET_DBG("Got injected Ip6 packet, sending to upper layers");
353 
354 		if (IS_ENABLED(CONFIG_OPENTHREAD_L2_DEBUG_DUMP_IPV6)) {
355 			net_pkt_hexdump(pkt, "Injected IPv6 packet");
356 		}
357 
358 		if (IS_ENABLED(CONFIG_OPENTHREAD_IP6_FRAGM) && is_ipv6_frag(pkt)) {
359 			return NET_DROP;
360 		}
361 
362 		return NET_CONTINUE;
363 	}
364 
365 	NET_DBG("Got 802.15.4 packet, sending to OT");
366 
367 	if (IS_ENABLED(CONFIG_OPENTHREAD_L2_DEBUG_DUMP_IPV6)) {
368 		net_pkt_hexdump(pkt, "Received 802.15.4 frame");
369 	}
370 
371 	if (notify_new_rx_frame(pkt) != 0) {
372 		NET_ERR("Failed to queue RX packet for OpenThread");
373 		return NET_DROP;
374 	}
375 
376 	return NET_OK;
377 }
378 
openthread_send(struct net_if * iface,struct net_pkt * pkt)379 int openthread_send(struct net_if *iface, struct net_pkt *pkt)
380 {
381 	int len = net_pkt_get_len(pkt);
382 
383 	if (IS_ENABLED(CONFIG_OPENTHREAD_L2_DEBUG_DUMP_IPV6)) {
384 		net_pkt_hexdump(pkt, "IPv6 packet to send");
385 	}
386 
387 	net_capture_pkt(iface, pkt);
388 
389 	if (notify_new_tx_frame(pkt) != 0) {
390 		net_pkt_unref(pkt);
391 	}
392 
393 	return len;
394 }
395 
openthread_start(struct openthread_context * ot_context)396 int openthread_start(struct openthread_context *ot_context)
397 {
398 	otInstance *ot_instance = ot_context->instance;
399 	otError error = OT_ERROR_NONE;
400 
401 	openthread_api_mutex_lock(ot_context);
402 
403 	NET_INFO("OpenThread version: %s", otGetVersionString());
404 
405 	if (IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR)) {
406 		NET_DBG("OpenThread co-processor.");
407 		goto exit;
408 	}
409 
410 	otIp6SetEnabled(ot_context->instance, true);
411 
412 	/* Sleepy End Device specific configuration. */
413 	if (IS_ENABLED(CONFIG_OPENTHREAD_MTD_SED)) {
414 		otLinkModeConfig ot_mode = otThreadGetLinkMode(ot_instance);
415 
416 		/* A SED should always attach the network as a SED to indicate
417 		 * increased buffer requirement to a parent.
418 		 */
419 		ot_mode.mRxOnWhenIdle = false;
420 
421 		otThreadSetLinkMode(ot_context->instance, ot_mode);
422 		otLinkSetPollPeriod(ot_context->instance, OT_POLL_PERIOD);
423 	}
424 
425 	if (otDatasetIsCommissioned(ot_instance)) {
426 		/* OpenThread already has dataset stored - skip the
427 		 * configuration.
428 		 */
429 		NET_DBG("OpenThread already commissioned.");
430 	} else if (IS_ENABLED(CONFIG_OPENTHREAD_JOINER_AUTOSTART)) {
431 		/* No dataset - initiate network join procedure. */
432 		NET_DBG("Starting OpenThread join procedure.");
433 
434 		error = otJoinerStart(ot_instance, OT_JOINER_PSKD, NULL,
435 				      PACKAGE_NAME, OT_PLATFORM_INFO,
436 				      PACKAGE_VERSION, NULL,
437 				      &ot_joiner_start_handler, ot_context);
438 
439 		if (error != OT_ERROR_NONE) {
440 			NET_ERR("Failed to start joiner [%d]", error);
441 		}
442 
443 		goto exit;
444 	} else {
445 		/* No dataset - load the default configuration. */
446 		NET_DBG("Loading OpenThread default configuration.");
447 
448 		otExtendedPanId xpanid;
449 		otNetworkKey    networkKey;
450 
451 		otThreadSetNetworkName(ot_instance, OT_NETWORK_NAME);
452 		otLinkSetChannel(ot_instance, OT_CHANNEL);
453 		otLinkSetPanId(ot_instance, OT_PANID);
454 		net_bytes_from_str(xpanid.m8, 8, (char *)OT_XPANID);
455 		otThreadSetExtendedPanId(ot_instance, &xpanid);
456 
457 		if (strlen(OT_NETWORKKEY)) {
458 			net_bytes_from_str(networkKey.m8, OT_NETWORK_KEY_SIZE,
459 					   (char *)OT_NETWORKKEY);
460 			otThreadSetNetworkKey(ot_instance, &networkKey);
461 		}
462 	}
463 
464 	NET_INFO("Network name: %s",
465 		 otThreadGetNetworkName(ot_instance));
466 
467 	/* Start the network. */
468 	error = otThreadSetEnabled(ot_instance, true);
469 	if (error != OT_ERROR_NONE) {
470 		NET_ERR("Failed to start the OpenThread network [%d]", error);
471 	}
472 
473 exit:
474 
475 	openthread_api_mutex_unlock(ot_context);
476 
477 	return error == OT_ERROR_NONE ? 0 : -EIO;
478 }
479 
openthread_stop(struct openthread_context * ot_context)480 int openthread_stop(struct openthread_context *ot_context)
481 {
482 	otError error;
483 
484 	if (IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR)) {
485 		return 0;
486 	}
487 
488 	openthread_api_mutex_lock(ot_context);
489 
490 	error = otThreadSetEnabled(ot_context->instance, false);
491 	if (error == OT_ERROR_INVALID_STATE) {
492 		NET_DBG("Openthread interface was not up [%d]", error);
493 	}
494 
495 	openthread_api_mutex_unlock(ot_context);
496 
497 	return 0;
498 }
499 
openthread_init(struct net_if * iface)500 static int openthread_init(struct net_if *iface)
501 {
502 	struct openthread_context *ot_context = net_if_l2_data(iface);
503 	struct k_work_queue_config q_cfg = {
504 		.name = "openthread",
505 		.no_yield = true,
506 	};
507 	otError err;
508 
509 	NET_DBG("openthread_init");
510 
511 	k_mutex_init(&ot_context->api_lock);
512 	k_work_init(&ot_context->api_work, openthread_process);
513 
514 	ll_addr = net_if_get_link_addr(iface);
515 
516 	openthread_api_mutex_lock(ot_context);
517 
518 	otSysInit(0, NULL);
519 
520 	ot_context->instance = otInstanceInitSingle();
521 	ot_context->iface = iface;
522 
523 	__ASSERT(ot_context->instance, "OT instance is NULL");
524 
525 	if (IS_ENABLED(CONFIG_OPENTHREAD_SHELL)) {
526 		platformShellInit(ot_context->instance);
527 	}
528 
529 	if (IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR)) {
530 		otPlatUartEnable();
531 		otNcpHdlcInit(ot_context->instance, ncp_hdlc_send);
532 	} else {
533 		otIp6SetReceiveFilterEnabled(ot_context->instance, true);
534 		otIp6SetReceiveCallback(ot_context->instance,
535 					ot_receive_handler, ot_context);
536 		sys_slist_init(&ot_context->state_change_cbs);
537 		err = otSetStateChangedCallback(ot_context->instance,
538 						&ot_state_changed_handler,
539 						ot_context);
540 		if (err != OT_ERROR_NONE) {
541 			NET_ERR("Could not set state changed callback: %d", err);
542 		}
543 
544 		net_mgmt_init_event_callback(
545 			&ip6_addr_cb, ipv6_addr_event_handler,
546 			NET_EVENT_IPV6_ADDR_ADD | NET_EVENT_IPV6_MADDR_ADD);
547 		net_mgmt_add_event_callback(&ip6_addr_cb);
548 
549 		net_if_dormant_on(iface);
550 	}
551 
552 	openthread_api_mutex_unlock(ot_context);
553 
554 	k_work_queue_start(&ot_context->work_q, ot_stack_area,
555 			   K_KERNEL_STACK_SIZEOF(ot_stack_area),
556 			   OT_PRIORITY, &q_cfg);
557 
558 	(void)k_work_submit_to_queue(&ot_context->work_q, &ot_context->api_work);
559 
560 	return 0;
561 }
562 
ieee802154_init(struct net_if * iface)563 void ieee802154_init(struct net_if *iface)
564 {
565 	if (IS_ENABLED(CONFIG_IEEE802154_NET_IF_NO_AUTO_START)) {
566 		LOG_DBG("Interface auto start disabled.");
567 		net_if_flag_set(iface, NET_IF_NO_AUTO_START);
568 	}
569 
570 	net_if_flag_set(iface, NET_IF_IPV6_NO_ND);
571 	net_if_flag_set(iface, NET_IF_IPV6_NO_MLD);
572 
573 	openthread_init(iface);
574 }
575 
openthread_flags(struct net_if * iface)576 static enum net_l2_flags openthread_flags(struct net_if *iface)
577 {
578 	/* TODO: Should report NET_L2_PROMISC_MODE if the radio driver
579 	 *       reports the IEEE802154_HW_PROMISC capability.
580 	 */
581 	return NET_L2_MULTICAST | NET_L2_MULTICAST_SKIP_JOIN_SOLICIT_NODE;
582 }
583 
openthread_enable(struct net_if * iface,bool state)584 static int openthread_enable(struct net_if *iface, bool state)
585 {
586 	struct openthread_context *ot_context = net_if_l2_data(iface);
587 
588 	NET_DBG("iface %p %s", iface, state ? "up" : "down");
589 
590 	if (state) {
591 		if (IS_ENABLED(CONFIG_OPENTHREAD_MANUAL_START)) {
592 			NET_DBG("OpenThread manual start.");
593 			return 0;
594 		}
595 
596 		return openthread_start(ot_context);
597 	}
598 
599 	return openthread_stop(ot_context);
600 }
601 
openthread_get_default_context(void)602 struct openthread_context *openthread_get_default_context(void)
603 {
604 	struct net_if *iface;
605 	struct openthread_context *ot_context = NULL;
606 
607 	iface = net_if_get_first_by_type(&NET_L2_GET_NAME(OPENTHREAD));
608 	if (!iface) {
609 		NET_ERR("There is no net interface for OpenThread");
610 		goto exit;
611 	}
612 
613 	ot_context = net_if_l2_data(iface);
614 	if (!ot_context) {
615 		NET_ERR("There is no Openthread context in net interface data");
616 		goto exit;
617 	}
618 
619 exit:
620 	return ot_context;
621 }
622 
openthread_get_default_instance(void)623 struct otInstance *openthread_get_default_instance(void)
624 {
625 	struct openthread_context *ot_context =
626 		openthread_get_default_context();
627 
628 	return ot_context ? ot_context->instance : NULL;
629 }
630 
openthread_state_changed_cb_register(struct openthread_context * ot_context,struct openthread_state_changed_cb * cb)631 int openthread_state_changed_cb_register(struct openthread_context *ot_context,
632 					 struct openthread_state_changed_cb *cb)
633 {
634 	CHECKIF(cb == NULL || cb->state_changed_cb == NULL) {
635 		return -EINVAL;
636 	}
637 
638 	openthread_api_mutex_lock(ot_context);
639 	sys_slist_append(&ot_context->state_change_cbs, &cb->node);
640 	openthread_api_mutex_unlock(ot_context);
641 
642 	return 0;
643 }
644 
openthread_state_changed_cb_unregister(struct openthread_context * ot_context,struct openthread_state_changed_cb * cb)645 int openthread_state_changed_cb_unregister(struct openthread_context *ot_context,
646 					   struct openthread_state_changed_cb *cb)
647 {
648 	bool removed;
649 
650 	CHECKIF(cb == NULL) {
651 		return -EINVAL;
652 	}
653 
654 	openthread_api_mutex_lock(ot_context);
655 	removed = sys_slist_find_and_remove(&ot_context->state_change_cbs, &cb->node);
656 	openthread_api_mutex_unlock(ot_context);
657 
658 	if (!removed) {
659 		return -EALREADY;
660 	}
661 
662 	return 0;
663 }
664 
openthread_set_state_changed_cb(otStateChangedCallback cb)665 void openthread_set_state_changed_cb(otStateChangedCallback cb)
666 {
667 	state_changed_cb = cb;
668 }
669 
openthread_api_mutex_lock(struct openthread_context * ot_context)670 void openthread_api_mutex_lock(struct openthread_context *ot_context)
671 {
672 	(void)k_mutex_lock(&ot_context->api_lock, K_FOREVER);
673 }
674 
openthread_api_mutex_try_lock(struct openthread_context * ot_context)675 int openthread_api_mutex_try_lock(struct openthread_context *ot_context)
676 {
677 	return k_mutex_lock(&ot_context->api_lock, K_NO_WAIT);
678 }
679 
openthread_api_mutex_unlock(struct openthread_context * ot_context)680 void openthread_api_mutex_unlock(struct openthread_context *ot_context)
681 {
682 	(void)k_mutex_unlock(&ot_context->api_lock);
683 }
684 
685 NET_L2_INIT(OPENTHREAD_L2, openthread_recv, openthread_send, openthread_enable,
686 	    openthread_flags);
687