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