1 /*
2  * Copyright 2025 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <openthread/platform/infra_if.h>
8 #include <zephyr/net/ethernet.h>
9 #include <route.h>
10 #include <icmpv6.h>
11 #include <zephyr/net/net_mgmt.h>
12 #include <zephyr/net/net_core.h>
13 #include <zephyr/net/openthread.h>
14 #include <zephyr/net/icmp.h>
15 #include <platform-zephyr.h>
16 #include <openthread.h>
17 #include <openthread/backbone_router_ftd.h>
18 #include <openthread/border_router.h>
19 #include <openthread/border_routing.h>
20 #include "openthread_border_router.h"
21 #include <common/code_utils.hpp>
22 
23 static struct net_mgmt_event_callback ail_net_event_connection_cb;
24 static struct net_icmp_ctx ra_ctx;
25 static struct net_icmp_ctx rs_ctx;
26 static uint32_t ail_iface_index;
27 static struct net_if *ail_iface_ptr;
28 static bool is_border_router_started;
29 
openthread_start_border_router_services(struct net_if * ot_iface,struct net_if * ail_iface)30 int openthread_start_border_router_services(struct net_if *ot_iface, struct net_if *ail_iface)
31 {
32 	otError error = OT_ERROR_NONE;
33 	otInstance *instance = openthread_get_default_instance();
34 
35 	ail_iface_index = (uint32_t)net_if_get_by_iface(ail_iface);
36 	ail_iface_ptr = ail_iface;
37 
38 	net_if_flag_set(ot_iface, NET_IF_FORWARD_MULTICASTS);
39 
40 	openthread_mutex_lock();
41 	/* Initialize platform modules first */
42 	VerifyOrExit(infra_if_init(instance, ail_iface_ptr) == OT_ERROR_NONE,
43 		     error = OT_ERROR_FAILED);
44 
45 	/* Call OpenThread API */
46 	VerifyOrExit(otBorderRoutingInit(instance, ail_iface_index, true) == OT_ERROR_NONE,
47 		     error = OT_ERROR_FAILED);
48 	VerifyOrExit(otBorderRoutingSetEnabled(instance, true) == OT_ERROR_NONE,
49 		     error = OT_ERROR_FAILED);
50 	VerifyOrExit(otPlatInfraIfStateChanged(instance, ail_iface_index, true) == OT_ERROR_NONE,
51 		     error = OT_ERROR_FAILED);
52 	otBackboneRouterSetEnabled(instance, true);
53 	is_border_router_started = true;
54 
55 exit:
56 	openthread_mutex_unlock();
57 	return error == OT_ERROR_NONE ? 0 : -EIO;
58 }
59 
openthread_stop_border_router_services(struct net_if * ot_iface,struct net_if * ail_iface)60 static int openthread_stop_border_router_services(struct net_if *ot_iface, struct net_if *ail_iface)
61 {
62 	otError error = OT_ERROR_FAILED;
63 	otInstance *instance = openthread_get_default_instance();
64 
65 	openthread_mutex_lock();
66 
67 	if (is_border_router_started) {
68 		/* Call OpenThread API */
69 		VerifyOrExit(otPlatInfraIfStateChanged(instance, ail_iface_index, false) ==
70 				     OT_ERROR_NONE,
71 			     error = OT_ERROR_FAILED);
72 		VerifyOrExit(otBorderRoutingSetEnabled(instance, false) == OT_ERROR_NONE,
73 			     error = OT_ERROR_FAILED);
74 		otBackboneRouterSetEnabled(instance, false);
75 
76 		error = OT_ERROR_NONE;
77 		is_border_router_started = false;
78 	}
79 exit:
80 	openthread_mutex_unlock();
81 	return error == OT_ERROR_NONE ? 0 : -EIO;
82 }
83 
openthread_set_bbr_multicast_listener_cb(openthread_bbr_multicast_listener_cb cb,void * context)84 void openthread_set_bbr_multicast_listener_cb(openthread_bbr_multicast_listener_cb cb,
85 					      void *context)
86 {
87 	__ASSERT(cb != NULL, "Receive callback is not set");
88 	__ASSERT(openthread_instance != NULL, "OpenThread instance is not initialized");
89 
90 	openthread_mutex_lock();
91 	otBackboneRouterSetMulticastListenerCallback(openthread_get_default_instance(), cb,
92 						     context);
93 	openthread_mutex_unlock();
94 }
95 
handle_ra_input(struct net_icmp_ctx * ctx,struct net_pkt * pkt,struct net_icmp_ip_hdr * hdr,struct net_icmp_hdr * icmp_hdr,void * user_data)96 static int handle_ra_input(struct net_icmp_ctx *ctx, struct net_pkt *pkt,
97 			   struct net_icmp_ip_hdr *hdr, struct net_icmp_hdr *icmp_hdr,
98 			   void *user_data)
99 {
100 	otInstance *ot_instance = openthread_get_default_instance();
101 	otIp6Address src_addr = {0};
102 	uint16_t length = net_pkt_get_len(pkt);
103 	uint8_t payload[512] = {0};
104 
105 	if (net_buf_linearize(payload, sizeof(payload), pkt->buffer, 0, length) ==
106 	    length) {
107 		memcpy(&src_addr, hdr->ipv6->src, sizeof(otIp6Address));
108 		/* TODO this will have to be executed on OT's context, not from here */
109 		otPlatInfraIfRecvIcmp6Nd(
110 			ot_instance, net_if_get_by_iface(net_pkt_iface(pkt)), &src_addr,
111 			(const uint8_t *)&payload[sizeof(struct net_ipv6_hdr)], length);
112 	}
113 	return 0;
114 }
115 
ail_connection_handler(struct net_mgmt_event_callback * cb,uint64_t mgmt_event,struct net_if * iface)116 static void ail_connection_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_event,
117 				   struct net_if *iface)
118 {
119 
120 	if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
121 		return;
122 	}
123 
124 	struct openthread_context *ot_context = openthread_get_default_context();
125 
126 	switch (mgmt_event) {
127 	case NET_EVENT_IF_UP:
128 		(void)openthread_start_border_router_services(ot_context->iface, iface);
129 		break;
130 	case NET_EVENT_IF_DOWN:
131 		(void)openthread_stop_border_router_services(ot_context->iface, iface);
132 		break;
133 	default:
134 		break;
135 	}
136 }
137 
ot_bbr_multicast_listener_handler(void * context,otBackboneRouterMulticastListenerEvent event,const otIp6Address * address)138 static void ot_bbr_multicast_listener_handler(void *context,
139 					      otBackboneRouterMulticastListenerEvent event,
140 					      const otIp6Address *address)
141 {
142 	struct openthread_context *ot_context = context;
143 	struct in6_addr mcast_prefix = {0};
144 
145 	memcpy(mcast_prefix.s6_addr, address->mFields.m32, sizeof(otIp6Address));
146 
147 	if (event == OT_BACKBONE_ROUTER_MULTICAST_LISTENER_ADDED) {
148 		net_route_mcast_add((struct net_if *)ot_context->iface, &mcast_prefix, 16);
149 	} else {
150 		struct net_route_entry_mcast *route_to_del = net_route_mcast_lookup(&mcast_prefix);
151 
152 		if (route_to_del != NULL) {
153 			net_route_mcast_del(route_to_del);
154 		}
155 	}
156 }
157 
openthread_border_router_init(struct openthread_context * ot_ctx)158 void openthread_border_router_init(struct openthread_context *ot_ctx)
159 {
160 	net_mgmt_init_event_callback(&ail_net_event_connection_cb, ail_connection_handler,
161 				     NET_EVENT_IF_UP | NET_EVENT_IF_DOWN);
162 	net_mgmt_add_event_callback(&ail_net_event_connection_cb);
163 	net_icmp_init_ctx(&ra_ctx, NET_ICMPV6_RA, 0, handle_ra_input);
164 	net_icmp_init_ctx(&rs_ctx, NET_ICMPV6_RS, 0, handle_ra_input);
165 	openthread_set_bbr_multicast_listener_cb(ot_bbr_multicast_listener_handler, (void *)ot_ctx);
166 }
167 
get_ot_slaac_address(otInstance * instance)168 const otIp6Address *get_ot_slaac_address(otInstance *instance)
169 {
170 	const otNetifAddress *unicast_addrs = otIp6GetUnicastAddresses(instance);
171 	otIp6Prefix omr_prefix_local = {0};
172 	otIp6Prefix addr_prefix = {0};
173 
174 	if (otBorderRoutingGetOmrPrefix(instance, &omr_prefix_local) == OT_ERROR_NONE) {
175 		for (const otNetifAddress *addr = unicast_addrs; addr; addr = addr->mNext) {
176 			otIp6GetPrefix(&addr->mAddress, 64, &addr_prefix);
177 			if (otIp6ArePrefixesEqual(&omr_prefix_local, &addr_prefix)) {
178 				return &addr->mAddress;
179 			}
180 		}
181 	}
182 	return NULL;
183 }
184